source: trunk/lib/Prefs.inc.php @ 151

Last change on this file since 151 was 151, checked in by scdev, 18 years ago

Q - Changed one more SessionCache? -> Cache, small bug fixt to Prefs, added operation help to modulemaker scripts.

File size: 12.5 KB
Line 
1<?php
2/**
3 * Prefs.inc.php
4 * code by strangecode :: www.strangecode.com :: this document contains copyrighted information
5 *
6 * Prefs provides an API for saving arbitrary values in a user's session.
7 * Session prefs can be stored into a database with the optional save() and load() methods.
8 *
9 * @author  Quinn Comendant <quinn@strangecode.com>
10 * @version 2.1
11 *
12 * Example of use:
13---------------------------------------------------------------------
14// Load preferences for the user's session.
15require_once 'codebase/lib/Prefs.inc.php';
16$prefs = new Prefs('bURB');
17$prefs->setParam(array(
18    'enable_db' => $auth->isLoggedIn(),
19    'user_id' => $auth->get('user_id'),
20));
21$prefs->setDefaults(array(
22    'search_num_results' => 25,
23    'datalog_num_entries' => 25,
24));
25$prefs->load();
26
27// Update preferences. Make sure to validate this input first!
28$prefs->set('search_num_results', getFormData('search_num_results'));
29$prefs->set('datalog_num_entries', getFormData('datalog_num_entries'));
30$prefs->save();
31
32---------------------------------------------------------------------
33 */
34class Prefs {
35
36    // Namespace of this instance of Prefs.
37    var $_ns;
38
39    // Configuration of this object.
40    var $_params = array(
41       
42        // The current user_id for which to load/save preferences.
43        'user_id' => null,
44       
45        // How long before we force a reload of the prefs data? 3600 = once every hour.
46        'load_timeout' => 3600,
47       
48        // Enable database storage.
49        'enable_db' => true,
50       
51        // Name of database table to store prefs.
52        'db_table' => 'pref_tbl',
53
54        // Automatically create table and verify columns. Better set to false after site launch.
55        'create_table' => true,
56    );
57
58    /**
59     * Prefs constructor.
60     */
61    function Prefs($namespace='')
62    {
63        $app =& App::getInstance();
64
65        $this->_ns = '_prefs_' . $namespace;
66       
67        // Initialized the prefs array.
68        if (!isset($_SESSION[$this->_ns])) {
69            $this->clear();
70        }
71
72        // Get create tables config from global context.
73        if (!is_null($app->getParam('db_create_tables'))) {
74            $this->setParam(array('create_table' => $app->getParam('db_create_tables')));
75        }
76    }
77
78    /**
79     * Setup the database table for this class.
80     *
81     * @access  public
82     * @author  Quinn Comendant <quinn@strangecode.com>
83     * @since   04 Jun 2006 16:41:42
84     */
85    function initDB($recreate_db=false)
86    {
87        $app =& App::getInstance();
88        $db =& DB::getInstance();
89
90        static $_db_tested = false;
91
92        if ($recreate_db || !$_db_tested && $this->getParam('create_table')) {
93            if ($recreate_db) {
94                $db->query("DROP TABLE IF EXISTS " . $this->getParam('db_table'));
95                $app->logMsg(sprintf('Dropping and recreating table %s.', $this->getParam('db_table')), LOG_DEBUG, __FILE__, __LINE__);
96            }
97            $db->query("CREATE TABLE IF NOT EXISTS " . $db->escapeString($this->getParam('db_table')) . " (
98                user_id VARCHAR(32) NOT NULL DEFAULT '',
99                pref_namespace VARCHAR(32) NOT NULL DEFAULT '',
100                pref_key VARCHAR(64) NOT NULL DEFAULT '',
101                pref_value TEXT,
102                PRIMARY KEY (user_id, pref_namespace, pref_key)
103            )");
104
105            if (!$db->columnExists($this->getParam('db_table'), array(
106                'user_id',
107                'pref_namespace',
108                'pref_key',
109                'pref_value',
110            ), false, false)) {
111                $app->logMsg(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), LOG_ALERT, __FILE__, __LINE__);
112                trigger_error(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), E_USER_ERROR);
113            }
114        }
115        $_db_tested = true;
116    }
117
118    /**
119     * Set the params of this object.
120     *
121     * @param  array $params   Array of param keys and values to set.
122     */
123    function setParam($params=null)
124    {
125        if (isset($params) && is_array($params)) {
126            // Merge new parameters with old overriding only those passed.
127            $this->_params = array_merge($this->_params, $params);
128        }
129    }
130
131    /**
132     * Return the value of a parameter, if it exists.
133     *
134     * @access public
135     * @param string $param        Which parameter to return.
136     * @return mixed               Configured parameter value.
137     */
138    function getParam($param)
139    {
140        $app =& App::getInstance();
141   
142        if (isset($this->_params[$param])) {
143            return $this->_params[$param];
144        } else {
145            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
146            return null;
147        }
148    }
149
150    /**
151     * Sets the default values for preferences. If a preference is not explicitly
152     * set, the value set here will be used. Can be called multiple times to merge additional
153     * defaults together.
154     *
155     * @param  array $defaults  Array of key-value pairs
156     */
157    function setDefaults($defaults)
158    {
159        if (isset($defaults) && is_array($defaults)) {
160            $_SESSION[$this->_ns]['defaults'] = array_merge($_SESSION[$this->_ns]['defaults'], $defaults);
161        }
162    }
163
164    /**
165     * Store a key-value pair in the session. If the value is different than what is set by setDefaults
166     * the value will be scheduled to be saved in the database.
167     * This function determins what data is saved to the database. Ensure clean values!
168     *
169     * @param  string $key       The name of the preference to modify.
170     * @param  string $val       The new value for this preference.
171     */
172    function set($key, $val)
173    {
174        $app =& App::getInstance();
175        if ('' == $key) {
176            $app->logMsg(sprintf('Key is empty (provided with value: %s)', $val), LOG_NOTICE, __FILE__, __LINE__);
177            return false;
178        }
179        if (!isset($_SESSION[$this->_ns]['defaults'][$key]) || $_SESSION[$this->_ns]['defaults'][$key] != $val || isset($_SESSION[$this->_ns]['persistent'][$key])) {
180            $_SESSION[$this->_ns]['persistent'][$key] = $val;           
181        }
182    }
183
184    /**
185     * Returns the value of the requested preference. Persistent values take precedence, but if none is set
186     * a default value is returned, or if not that, null.
187     *
188     * @param string $key       The name of the preference to retrieve.
189     *
190     * @return string           The value of the preference.
191     */
192    function get($key)
193    {
194        $app =& App::getInstance();
195        if (isset($_SESSION[$this->_ns]['persistent'][$key])) {
196            return $_SESSION[$this->_ns]['persistent'][$key];
197        } else if (isset($_SESSION[$this->_ns]['defaults'][$key])) {
198            return $_SESSION[$this->_ns]['defaults'][$key];
199        } else {
200            $app->logMsg(sprintf('Key not defined in default or persistent prefs cache: %s', $key), LOG_NOTICE, __FILE__, __LINE__);
201            return null;
202        }
203    }
204
205    /**
206     * To see if a persistent preference has been set.
207     *
208     * @param string $key       The name of the preference to check.
209     * @return boolean          True if the preference isset and not empty false otherwise.
210     */
211    function exists($key)
212    {
213        return isset($_SESSION[$this->_ns]['persistent'][$key]);
214    }
215
216    /**
217     * Clear a set preference value. This will also remove the value from the database.
218     *
219     * @param string $key       The name of the preference to delete.
220     */
221    function delete($key)
222    {
223        unset($_SESSION[$this->_ns]['persistent'][$key]);
224    }
225
226    /**
227     * Resets the $_SESSION cache. This should be executed with the same consideration
228     * as $auth->clear(), such as when logging out.
229     */
230    function clear()
231    {
232        $_SESSION[$this->_ns] = array(
233            'loaded' => false,
234            'load_datetime' => '1970-01-01',
235            'defaults' => array(),
236            'persistent' => array(),
237        );
238    }
239   
240    /*
241    * Retrieves all prefs from the database and stores them in the $_SESSION.
242    *
243    * @access   public
244    * @param    bool    $force  Set to always load from database, regardless if _isLoaded() or not.
245    * @return   bool    True if loading succeeded.
246    * @author   Quinn Comendant <quinn@strangecode.com>
247    * @version  1.0
248    * @since    04 Jun 2006 16:56:53
249    */
250    function load($force=false)
251    {
252        $app =& App::getInstance();
253        $db =& DB::getInstance();
254       
255        // Skip this method if not using the db.
256        if (true !== $this->getParam('enable_db')) {
257            return true;
258        }
259
260        $this->initDB();
261
262        // Prefs already loaded for this session.
263        if (!$force && $this->_isLoaded()) {
264            return true;
265        }
266
267        // User_id must not be empty.
268        if ('' == $this->getParam('user_id')) {
269            $app->logMsg(sprintf('Cannot save prefs because user_id not set.', null), LOG_WARNING, __FILE__, __LINE__);
270            return false;
271        }
272       
273        // Clear existing cache.
274        $this->clear();
275       
276        // Retrieve all prefs for this user and namespace.
277        $qid = $db->query("
278            SELECT pref_key, pref_value
279            FROM " . $db->escapeString($this->getParam('db_table')) . "
280            WHERE user_id = '" . $db->escapeString($this->getParam('user_id')) . "'
281            AND pref_namespace = '" . $db->escapeString($this->_ns) . "'
282            LIMIT 10000
283        ");
284        while (list($key, $val) = mysql_fetch_row($qid)) {
285            $_SESSION[$this->_ns]['persistent'][$key] = $val;
286        }
287       
288        $app->logMsg(sprintf('Loaded %s prefs from database.', sizeof($_SESSION[$this->_ns]['persistent'])), LOG_DEBUG, __FILE__, __LINE__);
289       
290        // Data loaded only once per session.
291        $_SESSION[$this->_ns]['loaded'] = true;
292        $_SESSION[$this->_ns]['load_datetime'] = date('Y-m-d H:i:s');
293       
294        return true;
295    }
296   
297    /*
298    * Returns true if the prefs had been loaded from the database into the $_SESSION recently.
299    * This function is simply a check so the database isn't access every page load.
300    *
301    * @access   private
302    * @return   bool    True if prefs are loaded.
303    * @author   Quinn Comendant <quinn@strangecode.com>
304    * @version  1.0
305    * @since    04 Jun 2006 17:12:44
306    */
307    function _isLoaded()
308    {
309        if (isset($_SESSION[$this->_ns]['load_datetime'])
310        && strtotime($_SESSION[$this->_ns]['load_datetime']) > time() - $this->getParam('load_timeout')
311        && isset($_SESSION[$this->_ns]['loaded']) 
312        && true === $_SESSION[$this->_ns]['loaded']) {
313            return true;
314        } else {
315            return false;
316        }
317    }
318   
319    /*
320    * Saves all prefs stored in the $_SESSION into the database.
321    *
322    * @access   public
323    * @return   bool    True if prefs exist and were saved.
324    * @author   Quinn Comendant <quinn@strangecode.com>
325    * @version  1.0
326    * @since    04 Jun 2006 17:19:56
327    */
328    function save()
329    {
330        $app =& App::getInstance();
331        $db =& DB::getInstance();
332       
333        // Skip this method if not using the db.
334        if (true !== $this->getParam('enable_db')) {
335            return true;
336        }
337       
338        // User_id must not be empty.
339        if ('' == $this->getParam('user_id')) {
340            $app->logMsg(sprintf('Cannot save prefs because user_id not set.', null), LOG_WARNING, __FILE__, __LINE__);
341            return false;
342        }
343
344        $this->initDB();
345
346        if (isset($_SESSION[$this->_ns]['persistent']) && is_array($_SESSION[$this->_ns]['persistent'])) {
347            // Delete old prefs from database.
348            $db->query("
349                DELETE FROM " . $db->escapeString($this->getParam('db_table')) . "
350                WHERE user_id = '" . $db->escapeString($this->getParam('user_id')) . "'
351                AND pref_namespace = '" . $db->escapeString($this->_ns) . "'
352            ");
353           
354            // Insert new prefs.
355            $insert_values = array();
356            foreach ($_SESSION[$this->_ns]['persistent'] as $key => $val) {
357                $insert_values[] = sprintf("('%s', '%s', '%s', '%s')", $db->escapeString($this->getParam('user_id')), $db->escapeString($this->_ns), $db->escapeString($key), $db->escapeString($val));
358            }
359            $db->query("
360                INSERT LOW_PRIORITY INTO " . $db->escapeString($this->getParam('db_table')) . "
361                (user_id, pref_namespace, pref_key, pref_value)
362                VALUES " . join(', ', $insert_values) . "
363            ");
364           
365            $app->logMsg(sprintf('Saved %s prefs to database.', sizeof($insert_values)), LOG_DEBUG, __FILE__, __LINE__);
366            return true;
367        }
368       
369        return false;
370    }
371}
372
373
374?>
Note: See TracBrowser for help on using the repository browser.