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

Last change on this file since 487 was 484, checked in by anonymous, 10 years ago

Changed private methods and properties to protected. A few minor bug fixes.

File size: 23.1 KB
RevLine 
[1]1<?php
2/**
[362]3 * The Strangecode Codebase - a general application development framework for PHP
4 * For details visit the project site: <http://trac.strangecode.com/codebase/>
[396]5 * Copyright 2001-2012 Strangecode, LLC
[462]6 *
[362]7 * This file is part of The Strangecode Codebase.
8 *
9 * The Strangecode Codebase is free software: you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your option)
12 * any later version.
[462]13 *
[362]14 * The Strangecode Codebase is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
[462]18 *
[362]19 * You should have received a copy of the GNU General Public License along with
20 * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/**
[136]24 * Prefs.inc.php
[1]25 *
[478]26 * Prefs provides an API for saving arbitrary values in a user's session, in cookies, and in the database.
27 * Prefs can be stored into a database with the optional save() and load() methods.
[136]28 *
[1]29 * @author  Quinn Comendant <quinn@strangecode.com>
[478]30 * @version 3.0
[481]31 * @todo This class could really benefit from being refactored using the factory pattern, with backend storage mechanisms.
[462]32 *
[477]33 * Example of use (database storagetype):
[150]34---------------------------------------------------------------------
[151]35// Load preferences for the user's session.
[150]36require_once 'codebase/lib/Prefs.inc.php';
[153]37$prefs = new Prefs('my-namespace');
[150]38$prefs->setParam(array(
[477]39    'storagetype' => ($auth->isLoggedIn() ? 'database' : 'session'),
[150]40    'user_id' => $auth->get('user_id'),
41));
42$prefs->setDefaults(array(
43    'search_num_results' => 25,
44    'datalog_num_entries' => 25,
45));
46$prefs->load();
[151]47
48// Update preferences. Make sure to validate this input first!
49$prefs->set('search_num_results', getFormData('search_num_results'));
50$prefs->set('datalog_num_entries', getFormData('datalog_num_entries'));
51$prefs->save();
[150]52---------------------------------------------------------------------
[1]53 */
54class Prefs {
55
[136]56    // Namespace of this instance of Prefs.
[484]57    protected $_ns;
[1]58
[152]59    // Configuration parameters for this object.
[484]60    protected $_params = array(
[462]61
[481]62        // Store preferences in one of the available storage mechanisms: session, cookie, database
63        // This default should remain set to 'session' for legacy support.
64        'storagetype' => 'session',
65
66        // This parameter is only used for legacy support, superceeded by the 'storagetype' setting.
[152]67        // Enable database storage. If this is false, all prefs will live only as long as the session.
[477]68        'persistent' => null,
[462]69
[477]70        // ----------------------------------------------------------
71        // Cookie-type settings.
72
73        // Lifespan of the cookie. If set to an integer, interpreted as a timestamp (0 for 'when user closes browser'), otherwise as a strtotime-compatible value ('tomorrow', etc).
74        'cookie_expire' => '+10 years',
75
76        // The path on the server in which the cookie will be available on.
77        'cookie_path' => null,
78
79        // The domain that the cookie is available to.
80        'cookie_domain' => null,
81
82        // ----------------------------------------------------------
83        // Database-type settings.
84
85        // The current user_id for which to load/save database-backed preferences.
[149]86        'user_id' => null,
[462]87
[152]88        // How long before we force a reload of the persistent prefs data? 3600 = once every hour.
[149]89        'load_timeout' => 3600,
[462]90
[481]91        // Name of database table to store prefs.
[147]92        'db_table' => 'pref_tbl',
[146]93
94        // Automatically create table and verify columns. Better set to false after site launch.
[396]95        // This value is overwritten by the $app->getParam('db_create_tables') setting if it is available.
[146]96        'create_table' => true,
97    );
98
[1]99    /**
100     * Prefs constructor.
101     */
[478]102    public function __construct($namespace='', array $params=null)
[1]103    {
[477]104        $app =& App::getInstance();
[146]105
[154]106        $this->_ns = $namespace;
[462]107
[146]108        // Get create tables config from global context.
109        if (!is_null($app->getParam('db_create_tables'))) {
110            $this->setParam(array('create_table' => $app->getParam('db_create_tables')));
111        }
[478]112
113        // Optional initial params.
114        $this->setParam($params);
115
[481]116        // Initialized the prefs array.
117        if ('cookie' != $app->getParam('storagetype') && !isset($_SESSION['_prefs'][$this->_ns]['saved'])) {
118            $this->clear();
119        }
120
[478]121        // Run Prefs->save() upon script completion if we're using the database storagetype.
122        // This only works if 'storagetype' is provided as a parameter to the constructor rather than via setParam() later.
123        if ('database' == $this->getParam('storagetype')) {
124            register_shutdown_function(array($this, 'save'));
125        }
[1]126    }
127
128    /**
[146]129     * Setup the database table for this class.
130     *
131     * @access  public
132     * @author  Quinn Comendant <quinn@strangecode.com>
133     * @since   04 Jun 2006 16:41:42
134     */
[468]135    public function initDB($recreate_db=false)
[146]136    {
[477]137        $app =& App::getInstance();
138        $db =& DB::getInstance();
[146]139
140        static $_db_tested = false;
141
142        if ($recreate_db || !$_db_tested && $this->getParam('create_table')) {
143            if ($recreate_db) {
144                $db->query("DROP TABLE IF EXISTS " . $this->getParam('db_table'));
[201]145                $app->logMsg(sprintf('Dropping and recreating table %s.', $this->getParam('db_table')), LOG_INFO, __FILE__, __LINE__);
[146]146            }
147            $db->query("CREATE TABLE IF NOT EXISTS " . $db->escapeString($this->getParam('db_table')) . " (
148                user_id VARCHAR(32) NOT NULL DEFAULT '',
149                pref_namespace VARCHAR(32) NOT NULL DEFAULT '',
150                pref_key VARCHAR(64) NOT NULL DEFAULT '',
151                pref_value TEXT,
152                PRIMARY KEY (user_id, pref_namespace, pref_key)
153            )");
154
155            if (!$db->columnExists($this->getParam('db_table'), array(
156                'user_id',
157                'pref_namespace',
158                'pref_key',
159                'pref_value',
160            ), false, false)) {
161                $app->logMsg(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), LOG_ALERT, __FILE__, __LINE__);
162                trigger_error(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), E_USER_ERROR);
163            }
164        }
165        $_db_tested = true;
166    }
167
168    /**
169     * Set the params of this object.
170     *
171     * @param  array $params   Array of param keys and values to set.
172     */
[478]173    public function setParam(array $params=null)
[146]174    {
[477]175        // CLI scripts can't use prefs stored in HTTP-based protocols.
176        if (defined('_CLI')
177        && isset($params['storagetype'])
178        && in_array($params['storagetype'], array('cookie', 'session'))) {
179            $app->logMsg(sprintf('Storage type %s not available for CLI', $params['storagetype']), LOG_NOTICE, __FILE__, __LINE__);
180        }
181
182        // Convert the legacy param 'persistent' to 'storagetype=database'.
[481]183        // Old sites would set 'persistent' to true (use database) or false (use sessions).
184        // If it is true, we set storagetype=database here.
185        // If false, we rely on the default, sessions (which is assigned in the params).
[477]186        if (isset($params['persistent']) && $params['persistent'] && !isset($params['storagetype'])) {
187            $params['storagetype'] = 'database';
188        }
189
[146]190        if (isset($params) && is_array($params)) {
191            // Merge new parameters with old overriding only those passed.
192            $this->_params = array_merge($this->_params, $params);
193        }
194    }
195
196    /**
197     * Return the value of a parameter, if it exists.
198     *
199     * @access public
200     * @param string $param        Which parameter to return.
201     * @return mixed               Configured parameter value.
202     */
[468]203    public function getParam($param)
[146]204    {
[477]205        $app =& App::getInstance();
[462]206
[478]207        if (array_key_exists($param, $this->_params)) {
[146]208            return $this->_params[$param];
209        } else {
210            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
211            return null;
212        }
213    }
214
215    /**
[462]216     * Sets the default values for preferences. If a preference is not explicitly
[151]217     * set, the value set here will be used. Can be called multiple times to merge additional
[481]218     * defaults together. This is mostly only useful for the database storagetype, when you have
[478]219     * values you want to use as default, and those are not stored to the database (so the defaults
220     * can be changed later and apply to all users who haven't make s specific setting).
[481]221     * For the cookie storagetype, using setDefaults just sets cookies but only if a cookie with
[478]222     * the same name is not already set.
[1]223     *
[462]224     * @param  array $defaults  Array of key-value pairs
[1]225     */
[468]226    public function setDefaults($defaults)
[1]227    {
[478]228        $app =& App::getInstance();
229
[146]230        if (isset($defaults) && is_array($defaults)) {
[478]231            switch ($this->getParam('storagetype')) {
232            case 'session':
233            case 'database':
234                $_SESSION['_prefs'][$this->_ns]['defaults'] = array_merge($_SESSION['_prefs'][$this->_ns]['defaults'], $defaults);
235                break;
236
237            case 'cookie':
238                foreach ($defaults as $key => $val) {
239                    if (!$this->exists($key)) {
240                        $this->set($key, $val);
241                    }
242                }
243                unset($key, $val);
244                break;
245            }
246        } else {
247            $app->logMsg(sprintf('Wrong data-type passed to Prefs->setDefaults().', null), LOG_NOTICE, __FILE__, __LINE__);
[1]248        }
249    }
250
251    /**
[478]252     * Store a key-value pair.
253     * When using the database storagetype, if the value is different than what is set by setDefaults the value will be scheduled to be saved in the database.
[1]254     *
[152]255     * @param  string $key          The name of the preference to modify.
256     * @param  string $val          The new value for this preference.
[1]257     */
[468]258    public function set($key, $val)
[1]259    {
[151]260        $app =& App::getInstance();
[152]261
[477]262        if (!is_string($key)) {
263            $app->logMsg(sprintf('Key is not a string-compatible type (%s)', getDump($key)), LOG_NOTICE, __FILE__, __LINE__);
[151]264            return false;
[149]265        }
[477]266        if ('' == trim($key)) {
267            $app->logMsg(sprintf('Key is empty (along with value: %s)', $val), LOG_NOTICE, __FILE__, __LINE__);
268            return false;
269        }
270        if (!is_scalar($val) && !is_array($val) && !is_object($val)) {
[479]271            $app->logMsg(sprintf('Value is not a compatible data type (%s=%s)', $key, getDump($val)), LOG_WARNING, __FILE__, __LINE__);
[477]272            return false;
273        }
[462]274
[477]275        switch ($this->getParam('storagetype')) {
[478]276        // Both session and database prefs are saved in the session (for database, only temporarily until they are saved).
[477]277        case 'session':
[478]278        case 'database':
279            // Set a saved preference if...
280            // - there isn't a default.
281            // - or the new value is different than the default
282            // - or there is a previously existing saved key.
[480]283            if (!(isset($_SESSION['_prefs'][$this->_ns]['defaults']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['defaults']))
[477]284            || $_SESSION['_prefs'][$this->_ns]['defaults'][$key] != $val
[480]285            || (isset($_SESSION['_prefs'][$this->_ns]['saved']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['saved']))) {
[477]286                $_SESSION['_prefs'][$this->_ns]['saved'][$key] = $val;
[478]287                $app->logMsg(sprintf('Setting session preference %s => %s', $key, getDump($val, true)), LOG_DEBUG, __FILE__, __LINE__);
[477]288            } else {
289                $app->logMsg(sprintf('Not setting session preference %s => %s', $key, getDump($val, true)), LOG_DEBUG, __FILE__, __LINE__);
290            }
291            break;
292
293        case 'cookie':
294            $name = $this->_getCookieName($key);
295            $val = json_encode($val);
296            $app->setCookie($name, $val, $this->getParam('cookie_expire'), $this->getParam('cookie_path'), $this->getParam('cookie_domain'));
[478]297            $_COOKIE[$name] = $val;
[477]298            $app->logMsg(sprintf('Setting cookie preference %s => %s', $key, $val), LOG_DEBUG, __FILE__, __LINE__);
299            break;
[151]300        }
[477]301
[1]302    }
[42]303
[1]304    /**
[462]305     * Returns the value of the requested preference. Saved values take precedence, but if none is set
[151]306     * a default value is returned, or if not that, null.
[1]307     *
[136]308     * @param string $key       The name of the preference to retrieve.
[1]309     *
310     * @return string           The value of the preference.
311     */
[468]312    public function get($key)
[1]313    {
[151]314        $app =& App::getInstance();
[477]315
316        switch ($this->getParam('storagetype')) {
317        case 'session':
318        case 'database':
319            if (isset($_SESSION['_prefs'][$this->_ns]['saved']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['saved'])) {
320                $app->logMsg(sprintf('Found %s in saved', $key), LOG_DEBUG, __FILE__, __LINE__);
321                return $_SESSION['_prefs'][$this->_ns]['saved'][$key];
322            } else if (isset($_SESSION['_prefs'][$this->_ns]['defaults']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['defaults'])) {
323                $app->logMsg(sprintf('Found %s in defaults', $key), LOG_DEBUG, __FILE__, __LINE__);
324                return $_SESSION['_prefs'][$this->_ns]['defaults'][$key];
325            } else {
326                $app->logMsg(sprintf('Key not found in prefs cache: %s', $key), LOG_DEBUG, __FILE__, __LINE__);
327                return null;
328            }
329            break;
330
331        case 'cookie':
332            $name = $this->_getCookieName($key);
333            if ($this->exists($key)) {
334                $val = json_decode($_COOKIE[$name]);
335                $app->logMsg(sprintf('Found %s in cookie: %s', $key, getDump($val)), LOG_DEBUG, __FILE__, __LINE__);
336                return $val;
337            } else {
338                $app->logMsg(sprintf('Key not found in cookie: %s', $key), LOG_DEBUG, __FILE__, __LINE__);
339                return null;
340            }
341            break;
[151]342        }
[1]343    }
[42]344
[1]345    /**
[152]346     * To see if a preference has been set.
[1]347     *
[136]348     * @param string $key       The name of the preference to check.
[151]349     * @return boolean          True if the preference isset and not empty false otherwise.
[1]350     */
[468]351    public function exists($key)
[1]352    {
[477]353        switch ($this->getParam('storagetype')) {
354        case 'session':
355        case 'database':
[480]356            return (isset($_SESSION['_prefs'][$this->_ns]['saved']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['saved']));
[477]357
358        case 'cookie':
359            $name = $this->_getCookieName($key);
[480]360            return (isset($_COOKIE) && array_key_exists($name, $_COOKIE));
[477]361        }
362
[1]363    }
[42]364
[1]365    /**
[478]366     * Delete an existing preference value. This will also remove the value from the database, once save() is called.
[1]367     *
[146]368     * @param string $key       The name of the preference to delete.
[1]369     */
[468]370    public function delete($key)
[1]371    {
[477]372        $app =& App::getInstance();
373
374        switch ($this->getParam('storagetype')) {
375        case 'session':
376        case 'database':
377            unset($_SESSION['_prefs'][$this->_ns]['saved'][$key]);
378            break;
379
380        case 'cookie':
381            if ($this->exists($key)) {
382                // Just set the existing value to an empty string, which expires in the past.
383                $name = $this->_getCookieName($key);
384                $app->setCookie($name, '', time() - 86400);
385                // Also unset the received cookie value, so it is unavailable.
386                unset($_COOKIE[$name]);
387            }
388            break;
389        }
390
[1]391    }
392
393    /**
[478]394     * Resets all existing values under this namespace. This should be executed with the same consideration as $auth->clear(), such as when logging out.
[1]395     */
[478]396    public function clear($scope='all')
[1]397    {
[478]398        switch ($scope) {
[241]399        case 'all' :
[477]400            switch ($this->getParam('storagetype')) {
401            case 'session':
402            case 'database':
403                $_SESSION['_prefs'][$this->_ns] = array(
404                    'loaded' => false,
405                    'load_datetime' => '1970-01-01',
406                    'defaults' => array(),
407                    'saved' => array(),
408                );
409                break;
410            case 'cookie':
411                foreach ($_COOKIE as $key => $value) {
412                    // All cookie keys with our internal prefix. Use only the last part as the key.
[478]413                    if (preg_match('/^' . preg_quote(sprintf('_prefs-%s-', $this->_ns)) . '(.+)$/i', $key, $match)) {
[477]414                        $this->delete($match[1]);
415                    }
416                }
417                break;
418            }
[241]419            break;
[478]420
[241]421        case 'defaults' :
422            $_SESSION['_prefs'][$this->_ns]['defaults'] = array();
423            break;
[478]424
[462]425        case 'saved' :
426            $_SESSION['_prefs'][$this->_ns]['saved'] = array();
[241]427            break;
428        }
[1]429    }
[462]430
[146]431    /*
[151]432    * Retrieves all prefs from the database and stores them in the $_SESSION.
[146]433    *
434    * @access   public
[150]435    * @param    bool    $force  Set to always load from database, regardless if _isLoaded() or not.
[146]436    * @return   bool    True if loading succeeded.
437    * @author   Quinn Comendant <quinn@strangecode.com>
438    * @version  1.0
439    * @since    04 Jun 2006 16:56:53
440    */
[468]441    public function load($force=false)
[146]442    {
443        $app =& App::getInstance();
[477]444        $db =& DB::getInstance();
[462]445
[477]446        // Skip this method if not using the db.
447        if ('database' != $this->getParam('storagetype')) {
[478]448            $app->logMsg('Prefs->load() does nothing unless using a database storagetype.', LOG_NOTICE, __FILE__, __LINE__);
[477]449            return true;
450        }
[146]451
[150]452        $this->initDB();
453
[146]454        // Prefs already loaded for this session.
[477]455        if (!$force && $this->_isLoaded()) {
456            return true;
457        }
[146]458
459        // User_id must not be empty.
460        if ('' == $this->getParam('user_id')) {
[151]461            $app->logMsg(sprintf('Cannot save prefs because user_id not set.', null), LOG_WARNING, __FILE__, __LINE__);
[146]462            return false;
463        }
[462]464
[150]465        // Clear existing cache.
[462]466        $this->clear('saved');
467
[151]468        // Retrieve all prefs for this user and namespace.
[477]469        $qid = $db->query("
470            SELECT pref_key, pref_value
471            FROM " . $db->escapeString($this->getParam('db_table')) . "
472            WHERE user_id = '" . $db->escapeString($this->getParam('user_id')) . "'
473            AND pref_namespace = '" . $db->escapeString($this->_ns) . "'
474            LIMIT 10000
475        ");
476        while (list($key, $val) = mysql_fetch_row($qid)) {
[462]477            $_SESSION['_prefs'][$this->_ns]['saved'][$key] = unserialize($val);
[477]478        }
[462]479
[477]480        $app->logMsg(sprintf('Loaded %s prefs from database.', mysql_num_rows($qid)), LOG_DEBUG, __FILE__, __LINE__);
[462]481
[477]482        // Data loaded only once per session.
483        $_SESSION['_prefs'][$this->_ns]['loaded'] = true;
[154]484        $_SESSION['_prefs'][$this->_ns]['load_datetime'] = date('Y-m-d H:i:s');
[462]485
[477]486        return true;
[146]487    }
[462]488
[146]489    /*
[149]490    * Returns true if the prefs had been loaded from the database into the $_SESSION recently.
491    * This function is simply a check so the database isn't access every page load.
[462]492    *
[146]493    * @access   private
494    * @return   bool    True if prefs are loaded.
495    * @author   Quinn Comendant <quinn@strangecode.com>
496    * @version  1.0
497    * @since    04 Jun 2006 17:12:44
498    */
[484]499    protected function _isLoaded()
[146]500    {
[477]501        if ('database' != $this->getParam('storagetype')) {
[478]502            $app->logMsg('Prefs->_isLoaded() does nothing unless using a database storagetype.', LOG_NOTICE, __FILE__, __LINE__);
[477]503            return true;
504        }
505
[154]506        if (isset($_SESSION['_prefs'][$this->_ns]['load_datetime'])
507        && strtotime($_SESSION['_prefs'][$this->_ns]['load_datetime']) > time() - $this->getParam('load_timeout')
[462]508        && isset($_SESSION['_prefs'][$this->_ns]['loaded'])
[154]509        && true === $_SESSION['_prefs'][$this->_ns]['loaded']) {
[149]510            return true;
511        } else {
512            return false;
513        }
[146]514    }
[462]515
[146]516    /*
517    * Saves all prefs stored in the $_SESSION into the database.
518    *
519    * @access   public
520    * @return   bool    True if prefs exist and were saved.
521    * @author   Quinn Comendant <quinn@strangecode.com>
522    * @version  1.0
523    * @since    04 Jun 2006 17:19:56
524    */
[468]525    public function save()
[146]526    {
527        $app =& App::getInstance();
[477]528        $db =& DB::getInstance();
[462]529
[477]530        // Skip this method if not using the db.
531        if ('database' != $this->getParam('storagetype')) {
[478]532            $app->logMsg('Prefs->save() does nothing unless using a database storagetype.', LOG_NOTICE, __FILE__, __LINE__);
[477]533            return true;
534        }
[462]535
[146]536        // User_id must not be empty.
537        if ('' == $this->getParam('user_id')) {
[151]538            $app->logMsg(sprintf('Cannot save prefs because user_id not set.', null), LOG_WARNING, __FILE__, __LINE__);
[146]539            return false;
540        }
541
542        $this->initDB();
543
[462]544        if (isset($_SESSION['_prefs'][$this->_ns]['saved']) && is_array($_SESSION['_prefs'][$this->_ns]['saved']) && !empty($_SESSION['_prefs'][$this->_ns]['saved'])) {
[146]545            // Delete old prefs from database.
546            $db->query("
547                DELETE FROM " . $db->escapeString($this->getParam('db_table')) . "
[477]548                WHERE user_id = '" . $db->escapeString($this->getParam('user_id')) . "'
549                AND pref_namespace = '" . $db->escapeString($this->_ns) . "'
[146]550            ");
[462]551
[146]552            // Insert new prefs.
553            $insert_values = array();
[462]554            foreach ($_SESSION['_prefs'][$this->_ns]['saved'] as $key => $val) {
555                $insert_values[] = sprintf("('%s', '%s', '%s', '%s')",
556                    $db->escapeString($this->getParam('user_id')),
557                    $db->escapeString($this->_ns),
558                    $db->escapeString($key),
[158]559                    $db->escapeString(serialize($val))
560                );
[146]561            }
[159]562            // TODO: after MySQL 5.0.23 is released this query could benefit from INSERT DELAYED.
[146]563            $db->query("
[462]564                INSERT INTO " . $db->escapeString($this->getParam('db_table')) . "
[146]565                (user_id, pref_namespace, pref_key, pref_value)
566                VALUES " . join(', ', $insert_values) . "
567            ");
[462]568
[151]569            $app->logMsg(sprintf('Saved %s prefs to database.', sizeof($insert_values)), LOG_DEBUG, __FILE__, __LINE__);
[146]570            return true;
571        }
[462]572
[146]573        return false;
574    }
[477]575
576    /*
577    *
578    *
579    * @access   public
580    * @param
581    * @return
582    * @author   Quinn Comendant <quinn@strangecode.com>
583    * @version  1.0
584    * @since    02 May 2014 18:17:04
585    */
[484]586    protected function _getCookieName($key)
[477]587    {
588        $app =& App::getInstance();
589
[478]590        if (mb_strpos($key, sprintf('_prefs-%s', $this->_ns)) === 0) {
591            $app->logMsg(sprintf('Invalid key name (%s). Leave off "_prefs-%s-" and it should work.', $key, $this->_ns), LOG_NOTICE, __FILE__, __LINE__);
[477]592        }
[478]593        // Use standardized class data names: _ + classname + namespace + variablekey
594        return sprintf('_prefs-%s-%s', $this->_ns, $key);
[477]595    }
[1]596}
597
Note: See TracBrowser for help on using the repository browser.