Index: trunk/lib/Prefs.inc.php
===================================================================
--- trunk/lib/Prefs.inc.php	(revision 815)
+++ trunk/lib/Prefs.inc.php	(revision 1)
@@ -1,667 +1,246 @@
 <?php
 /**
- * The Strangecode Codebase - a general application development framework for PHP
- * For details visit the project site: <http://trac.strangecode.com/codebase/>
- * Copyright 2001-2012 Strangecode, LLC
+ * Prefs:: provides an API for saving arbitrary values in a user's session.
+ * Database save routines to come.
  *
- * This file is part of The Strangecode Codebase.
- *
- * The Strangecode Codebase is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * The Strangecode Codebase is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
+ * @inspiration  Horde 2.0's Prefs class. This one is much simpler, but
+ *               the API for the methods that exist are sort of like Horde's
+ *               in case we want to be more like it in the future.
+ * @author  Quinn Comendant <quinn@strangecode.com>
+ * @version 1.1
  */
-
-/**
- * Prefs.inc.php
- *
- * Prefs provides an API for saving arbitrary values in a user's session, in cookies, and in the database.
- * Prefs can be stored into a database with the optional save() and load() methods.
- *
- * @author  Quinn Comendant <quinn@strangecode.com>
- * @version 3.0
- * @todo This class could really benefit from being refactored using the factory pattern, with backend storage mechanisms.
- *
- * Example of use (database storagetype):
----------------------------------------------------------------------
-// Load preferences for the user's session.
-require_once 'codebase/lib/Prefs.inc.php';
-$prefs = new Prefs('my-namespace');
-$prefs->setParam(array(
-    'storagetype' => ($auth->isLoggedIn() ? 'database' : 'session'),
-    'user_id' => $auth->get('user_id'),
-));
-$prefs->setDefaults(array(
-    'search_num_results' => 25,
-    'datalog_num_entries' => 25,
-));
-$prefs->load();
-
-// Update preferences. Make sure to validate this input first!
-$prefs->set('search_num_results', getFormData('search_num_results'));
-$prefs->set('datalog_num_entries', getFormData('datalog_num_entries'));
-$prefs->save();
----------------------------------------------------------------------
- */
-class Prefs
-{
-
-    // Namespace of this instance of Prefs.
-    protected $_ns;
-
-    // Configuration parameters for this object.
-    protected $_params = array(
-
-        // Store preferences in one of the available storage mechanisms: session, cookie, database
-        // This default should remain set to 'session' for legacy support.
-        'storagetype' => 'session',
-
-        // This parameter is only used for legacy support, superseded by the 'storagetype' setting.
-        // Enable database storage. If this is false, all prefs will live only as long as the session.
-        'persistent' => null,
-
-        // ----------------------------------------------------------
-        // Cookie-type settings.
-
-        // 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).
-        'cookie_expire' => '+10 years',
-
-        // The path on the server in which the cookie will be available on.
-        'cookie_path' => '/',
-
-        // The domain that the cookie is available to.
-        'cookie_domain' => null,
-
-        // ----------------------------------------------------------
-        // Database-type settings.
-
-        // The current user_id for which to load/save database-backed preferences.
-        'user_id' => null,
-
-        // How long before we force a reload of the persistent prefs data?
-        'load_timeout' => 60,
-
-        // Name of database table to store prefs.
-        'db_table' => 'pref_tbl',
-
-        // Automatically create table and verify columns. Better set to false after site launch.
-        // This value is overwritten by the $app->getParam('db_create_tables') setting if it is available.
-        'create_table' => true,
-
-        // Original namespace set during __construct().
-        // 'namespace' => '',
-    );
-
+class Prefs {
+
+    /**
+     * Where these preferences can be used. To differentiate between preferences
+     * for a specific script, application, or global.
+     * @var string $scope
+     */
+    var $scope = 'global';
+
+    /**
+     * Indicator whether we save in the database or not.
+     * @var boolean $_perpetual
+     */
+    var $_perpetual = false;
+
+    /**
+     * Hash containing connection parameters.
+     * @var array $params
+     */
+    var $params = array();
+    
+    
     /**
      * Prefs constructor.
      */
-    public function __construct($namespace='', array $params=null)
-    {
-        $app =& App::getInstance();
-
-        $this->_ns = $namespace;
-
-        // Save the original namespace for the DB pref_namespace column. $this->_ns, used in the SESSION variable, will change based on the user_id.
-        $this->setParam(array('namespace' => $namespace));
-
-        // Get create tables config from global context.
-        if (!is_null($app->getParam('db_create_tables'))) {
-            $this->setParam(array('create_table' => $app->getParam('db_create_tables')));
-        }
-
-        // Optional initial params.
-        $this->setParam($params);
-
-        if (isset($params['save_on_shutdown']) && $params['save_on_shutdown']) {
-            // Run Prefs->save() upon script completion if we're using the database storagetype.
-            // This only works if:
-            // - 'storagetype' is provided as a parameter to the constructor rather than via setParam() later.
-            // - $app->stop() is not called at the end of the script (which would close the PDO connection before the shutdown function runs).
-            if ('database' == $this->getParam('storagetype')) {
-                register_shutdown_function(array($this, 'save'));
-            }
-        }
-    }
-
-    /**
-     * Setup the database table for this class.
-     *
-     * @access  public
-     * @author  Quinn Comendant <quinn@strangecode.com>
-     * @since   04 Jun 2006 16:41:42
-     */
-    public function initDB($recreate_db=false)
-    {
-        $app =& App::getInstance();
-        $pdo =& \Strangecode\Codebase\PDO::getInstance();
-
-        static $_db_tested = false;
-
-        if ($recreate_db || !$_db_tested && $this->getParam('create_table')) {
-            if ($recreate_db) {
-                $pdo->query(sprintf("DROP TABLE IF EXISTS `%s`", $pdo->sanitizeIdentifier($this->getParam('db_table'))));
-                $app->logMsg(sprintf('Dropping and recreating table %s.', $this->getParam('db_table')), LOG_INFO, __FILE__, __LINE__);
-            }
-            $stmt = $pdo->query(sprintf("
-                CREATE TABLE IF NOT EXISTS `%s` (
-                    `user_id` VARCHAR(32) NOT NULL DEFAULT '',
-                    `pref_namespace` VARCHAR(32) NOT NULL DEFAULT '',
-                    `pref_key` VARCHAR(64) NOT NULL DEFAULT '',
-                    `pref_value` TEXT,
-                    PRIMARY KEY (`user_id`, `pref_namespace`, `pref_key`)
-                )
-            ", $pdo->sanitizeIdentifier($this->getParam('db_table'))));
-
-            if (!$pdo->columnExists($this->getParam('db_table'), array(
-                'user_id',
-                'pref_namespace',
-                'pref_key',
-                'pref_value',
-            ), false, false)) {
-                $app->logMsg(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), LOG_ALERT, __FILE__, __LINE__);
-                trigger_error(sprintf('Database table %s has invalid columns. Please update this table manually.', $this->getParam('db_table')), E_USER_ERROR);
-            }
-        }
-        $_db_tested = true;
-    }
-
-    /**
-     * Set the params of this object.
-     *
-     * @param  array $params   Array of param keys and values to set.
-     */
-    public function setParam(array $params=null)
-    {
-        $app =& App::getInstance();
-
-        // CLI scripts can't use prefs stored in HTTP-based protocols.
-        if ($app->isCLI()
-        && isset($params['storagetype'])
-        && in_array($params['storagetype'], array('cookie', 'session'))) {
-            $app->logMsg(sprintf('Storage type %s not available for CLI', $params['storagetype']), LOG_DEBUG, __FILE__, __LINE__);
-        }
-
-        // Convert the legacy param 'persistent' to 'storagetype=database'.
-        // Old sites would set 'persistent' to true (use database) or false (use sessions).
-        // If it is true, we set storagetype=database here.
-        // If false, we rely on the default, sessions (which is assigned in the params).
-        if (isset($params['persistent']) && $params['persistent'] && !isset($params['storagetype'])) {
-            $params['storagetype'] = 'database';
-        }
-
-        // Append the user_id to the namespace to keep separate collections for different users.
-        if (isset($params['user_id']) && $params['user_id']) {
-            // $this->getParam('namespace') should always be available since it is set in __construct().
-            $this->_ns = sprintf('%s-%s', $this->getParam('namespace'), $params['user_id']);
-        }
-
-        // Check max DB string lengths.
-        if ((isset($params['storagetype']) && $params['storagetype'] == 'database') || $this->getParam('storagetype') == 'database') {
-            if (isset($params['user_id']) && mb_strlen($params['user_id']) > 32) {
-                $app->logMsg(sprintf('Prefs user_id param longer than 32 characters: %s', $params['user_id']), LOG_ERR, __FILE__, __LINE__);
-            }
-            if (isset($params['namespace']) && mb_strlen($params['namespace']) > 32) {
-                $app->logMsg(sprintf('Prefs namespace longer than 32 characters: %s', $this->_ns), LOG_ERR, __FILE__, __LINE__);
-            }
-            if (isset($params['pref_key']) && mb_strlen($params['pref_key']) > 64) {
-                $app->logMsg(sprintf('Prefs pref_key param longer than 64 characters: %s', $params['pref_key']), LOG_ERR, __FILE__, __LINE__);
-            }
-        }
-
-        if (isset($params) && is_array($params)) {
-            // Merge new parameters with old overriding only those passed.
-            $this->_params = array_merge($this->_params, $params);
-        }
-    }
-
-    /**
-     * Return the value of a parameter, if it exists.
-     *
-     * @access public
-     * @param string $param        Which parameter to return.
-     * @return mixed               Configured parameter value.
-     */
-    public function getParam($param)
-    {
-        $app =& App::getInstance();
-
-        if (array_key_exists($param, $this->_params)) {
-            return $this->_params[$param];
-        } else {
-            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
-            return null;
-        }
-    }
-
-    /*
-    * Setup the SESSION storage array. This method is called at the beginning of each method that accesses $_SESSION['_prefs'].
-    *
-    * @access   public
-    * @param
-    * @return
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @since    02 Oct 2018 15:35:09
-    */
-    private function _init()
-    {
-        if ('cookie' != $this->getParam('storagetype') && !isset($_SESSION['_prefs'][$this->_ns])) {
-            $this->clear();
-        }
-    }
-
-    /**
-     * Sets the default values for preferences. If a preference is not explicitly
-     * set, the value set here will be used. Can be called multiple times to merge additional
-     * defaults together. This is mostly only useful for the database storagetype, when you have
-     * values you want to use as default, and those are not stored to the database (so the defaults
-     * can be changed later and apply to all users who haven't make s specific setting).
-     * For the cookie storagetype, using setDefaults just sets cookies but only if a cookie with
-     * the same name is not already set.
-     *
-     * @param  array $defaults  Array of key-value pairs
-     */
-    public function setDefaults($defaults)
-    {
-        $app =& App::getInstance();
-
-        $this->_init();
-
-        if (isset($defaults) && is_array($defaults)) {
-            switch ($this->getParam('storagetype')) {
-            case 'session':
-            case 'database':
-                $_SESSION['_prefs'][$this->_ns]['defaults'] = array_merge($_SESSION['_prefs'][$this->_ns]['defaults'], $defaults);
-                break;
-
-            case 'cookie':
-                foreach ($defaults as $key => $val) {
-                    if (!$this->exists($key)) {
-                        $this->set($key, $val);
-                    }
-                }
-                unset($key, $val);
-                break;
-            }
-        } else {
-            $app->logMsg(sprintf('Wrong data-type passed to Prefs->setDefaults().', null), LOG_NOTICE, __FILE__, __LINE__);
-        }
-    }
-
-    /**
-     * Store a key-value pair.
-     * 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.
-     *
-     * @param  string $key          The name of the preference to modify.
-     * @param  string $val          The new value for this preference.
-     */
-    public function set($key, $val)
-    {
-        $app =& App::getInstance();
-
-        if (!is_string($key)) {
-            $app->logMsg(sprintf('Key is not a string-compatible type (%s)', getDump($key)), LOG_NOTICE, __FILE__, __LINE__);
+    function Prefs($dbh=false, $params=array())
+    {
+        $this->params = $params;
+        $_perpetual = false; // Until database routines are completed.
+    }
+
+    /**
+     * Sets the default value of a preference. The pref will be set only if
+     * is not set already. 
+     *
+     * @param  string $pref      The name of the preference to modify.
+     * @param  string $val       The new value for this preference.
+     * @param  string $scope     The scope for this preference.
+     *
+     * @return boolean  True if the value was successfully set.
+     */
+    function setDefault($pref, $val, $scope=null)
+    {
+        if (!isset($scope)) {
+            $scope =& $this->scope;
+        }
+        
+        // No empty values allowed.
+        if ('' == $pref || '' == $val || '' == $scope) {
             return false;
         }
-        if ('' == trim($key)) {
-            $app->logMsg(sprintf('Key is empty (along with value: %s)', $val), LOG_NOTICE, __FILE__, __LINE__);
+        
+        // Initialized the prefs array.
+        if (!isset($_SESSION['_prefs'])) {
+            $_SESSION['_prefs'] = array();
+        }
+        
+        // In case boolean or null values are passed as a string.
+        if ($val == 'true') {
+            $val = true;
+        } else if ($val == 'false') {
+            $val = false;
+        } else if ($val == 'null') {
+            $val = null;
+        }
+
+        // Set it only if not set already.
+        if (!isset($_SESSION['_prefs'][$scope][$pref])) {
+            $_SESSION['_prefs'][$scope][$pref] = $val;
+            return true;
+        }
+    }
+
+    /**
+     * Sets the given preferences to the specific value, 
+     *
+     * @param  string $pref      The name of the preference to modify.
+     * @param  string $val       The new value for this preference.
+     * @param  string $scope     The scope for this preference.
+     *
+     * @return boolean  True if the value was successfully set.
+     */
+    function setValue($pref, $val, $scope=null)
+    {
+        if (!isset($scope)) {
+            $scope =& $this->scope;
+        }
+        
+        // No empty values allowed.
+        if ('' == $pref || '' == $val || '' == $scope) {
             return false;
         }
-        if (!is_scalar($val) && !is_array($val) && !is_object($val)) {
-            $app->logMsg(sprintf('Value is not a compatible data type (%s=%s)', $key, getDump($val)), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        $this->_init();
-
-        switch ($this->getParam('storagetype')) {
-        // Both session and database prefs are saved in the session (for database, only temporarily until they are saved).
-        case 'session':
-        case 'database':
-            // Set a saved preference if...
-            // - there isn't a default.
-            // - or the new value is different than the default
-            // - or there is a previously existing saved key.
-            if (!(isset($_SESSION['_prefs'][$this->_ns]['defaults']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['defaults']))
-            || $_SESSION['_prefs'][$this->_ns]['defaults'][$key] != $val
-            || $this->exists($key)) {
-                $_SESSION['_prefs'][$this->_ns]['saved'][$key] = $val;
-                $app->logMsg(sprintf('Setting session/database preference %s => %s', $key, getDump($val, true)), LOG_DEBUG, __FILE__, __LINE__);
-            } else {
-                $app->logMsg(sprintf('Not setting session/database preference %s => %s', $key, getDump($val, true)), LOG_DEBUG, __FILE__, __LINE__);
-            }
-            break;
-
-        case 'cookie':
-            $name = $this->_getCookieName($key);
-            $val = json_encode($val);
-            $app->setCookie($name, $val, $this->getParam('cookie_expire'), $this->getParam('cookie_path'), $this->getParam('cookie_domain'));
-            $_COOKIE[$name] = $val;
-            $app->logMsg(sprintf('Setting cookie preference %s => %s', $key, $val), LOG_DEBUG, __FILE__, __LINE__);
-            break;
-        }
-
-    }
-
-    /**
-     * Returns the value of the requested preference. Saved values take precedence, but if none is set
-     * a default value is returned, or if not that, null.
-     *
-     * @param string $key       The name of the preference to retrieve (or null to retrieve all keys).
+        
+        // Initialized the prefs array.
+        if (!isset($_SESSION['_prefs'])) {
+            $_SESSION['_prefs'] = array();
+        }
+        
+        // In case boolean or null values are passed as a string.
+        if ($val == 'true') {
+            $val = true;
+        } else if ($val == 'false') {
+            $val = false;
+        } else if ($val == 'null') {
+            $val = null;
+        }
+
+        $_SESSION['_prefs'][$scope][$pref] = $val;
+        return true;
+    }
+    
+    /**
+     * Returns the value of the requested preference.
+     *
+     * @param string $pref      The name of the preference to retrieve.
+     * @param string $scope     The scope for this preference.
+     *
      * @return string           The value of the preference.
      */
-    public function get($key=null)
-    {
-        $app =& App::getInstance();
-
-        $this->_init();
-
-        switch ($this->getParam('storagetype')) {
-        case 'session':
-        case 'database':
-            if (is_null($key) && isset($_SESSION['_prefs'][$this->_ns]['saved'])) {
-                return $_SESSION['_prefs'][$this->_ns]['saved'];
-            }
-            if ($this->exists($key)) {
-                $app->logMsg(sprintf('Found %s in saved', $key), LOG_DEBUG, __FILE__, __LINE__);
-                return $_SESSION['_prefs'][$this->_ns]['saved'][$key];
-            }
-            if (isset($_SESSION['_prefs'][$this->_ns]['defaults']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['defaults'])) {
-                $app->logMsg(sprintf('Found %s in defaults', $key), LOG_DEBUG, __FILE__, __LINE__);
-                return $_SESSION['_prefs'][$this->_ns]['defaults'][$key];
-            }
-            $app->logMsg(sprintf('Key not found in prefs cache: %s', $key), LOG_DEBUG, __FILE__, __LINE__);
-            return null;
-
-        case 'cookie':
-            if (is_null($key)) {
-                $app->logMsg(sprintf('Unable to get(null) when using cookie storagetype.', null), LOG_WARNING, __FILE__, __LINE__);
-                return null;
-            }
-            $name = $this->_getCookieName($key);
-            if ($this->exists($key) && '' != $_COOKIE[$name]) {
-                $val = json_decode($_COOKIE[$name], true);
-                $app->logMsg(sprintf('Found %s in cookie: %s', $key, getDump($val)), LOG_DEBUG, __FILE__, __LINE__);
-                return $val;
-            }
-            $app->logMsg(sprintf('Did not find %s in cookie', $key), LOG_DEBUG, __FILE__, __LINE__);
-            return null;
-        }
-    }
-
+    function getValue($pref, $scope=null)
+    {
+        if (!isset($scope)) {
+            $scope =& $this->scope;
+        }
+        
+        return (isset($_SESSION['_prefs'][$scope][$pref])) ? $_SESSION['_prefs'][$scope][$pref] : null;
+    }
+    
     /**
      * To see if a preference has been set.
      *
-     * @param string $key       The name of the preference to check.
-     * @return boolean          True if the preference isset and not empty false otherwise.
-     */
-    public function exists($key)
-    {
-        $this->_init();
-
-        switch ($this->getParam('storagetype')) {
-        case 'session':
-        case 'database':
-            // isset() does not return TRUE for array keys that correspond to a NULL value, while array_key_exists() does.
-            return (isset($_SESSION['_prefs'][$this->_ns]['saved']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['saved']));
-
-        case 'cookie':
-            $name = $this->_getCookieName($key);
-            return (isset($_COOKIE) && array_key_exists($name, $_COOKIE));
-        }
-
-    }
-
-    /**
-     * Delete an existing preference value. This will also remove the value from the database, once save() is called.
-     *
-     * @param string $key       The name of the preference to delete.
-     */
-    public function delete($key)
-    {
-        $app =& App::getInstance();
-
-        $this->_init();
-
-        switch ($this->getParam('storagetype')) {
-        case 'session':
-        case 'database':
-            unset($_SESSION['_prefs'][$this->_ns]['saved'][$key]);
-            break;
-
-        case 'cookie':
-            if ($this->exists($key)) {
-                // Just set the existing value to an empty string, which expires in the past.
-                $name = $this->_getCookieName($key);
-                $app->setCookie($name, '', time() - 86400);
-                // Also unset the received cookie value, so it is unavailable.
-                unset($_COOKIE[$name]);
-            }
-            break;
-        }
-
-    }
-
-    /**
-     * Resets all existing values under this namespace. This should be executed with the same consideration as $auth->clear(), such as when logging out.
-     * Set $save true to persist the clear action to the storage (i.e., erase all stored prefs for this user).
-     */
-    public function clear($scope='all', $save=false)
-    {
-        $app =& App::getInstance();
-
-        switch ($scope) {
-        case 'all' :
-            switch ($this->getParam('storagetype')) {
-            case 'session':
-            case 'database':
-                $_SESSION['_prefs'][$this->_ns] = array(
-                    'loaded' => false,
-                    'load_datetime' => '1970-01-01',
-                    'defaults' => array(),
-                    'saved' => array(),
-                );
-                break;
-            case 'cookie':
-                foreach ($_COOKIE as $key => $value) {
-                    // All cookie keys with our internal prefix. Use only the last part as the key.
-                    if (preg_match('/^' . preg_quote(sprintf('_prefs-%s-', $this->_ns)) . '(.+)$/i', $key, $match)) {
-                        $this->delete($match[1]);
-                    }
-                }
-                break;
-            }
-            break;
-
-        case 'defaults' :
-            $_SESSION['_prefs'][$this->_ns]['defaults'] = array();
-            break;
-
-        case 'saved' :
-            $_SESSION['_prefs'][$this->_ns]['saved'] = array();
-            break;
-        }
-
-        if ($save) {
-            $this->save(true);
-            $app->logMsg(sprintf('Deleted all %s %s prefs for user_id %s', $this->getParam('storagetype'), $this->_ns, $this->getParam('user_id')), LOG_INFO, __FILE__, __LINE__);
-        } else {
-            $app->logMsg(sprintf('Cleared %s %s prefs', $scope, $this->_ns), LOG_DEBUG, __FILE__, __LINE__);
-        }
-    }
-
-    /*
-    * Retrieves all prefs from the database and stores them in the $_SESSION.
-    *
-    * @access   public
-    * @param    bool    $force  Set to always load from database, regardless if _isLoaded() or not.
-    * @return   bool    True if loading succeeded.
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @version  1.0
-    * @since    04 Jun 2006 16:56:53
-    */
-    public function load($force=false)
-    {
-        $app =& App::getInstance();
-        $pdo =& \Strangecode\Codebase\PDO::getInstance();
-
-        // Skip this method if not using the db.
-        if ('database' != $this->getParam('storagetype')) {
-            $app->logMsg('Prefs->load() does nothing unless using a database storagetype.', LOG_DEBUG, __FILE__, __LINE__);
+     * @param string $pref      The name of the preference to check.
+     * @param string $scope     The scope for this preference.
+     *
+     * @return boolean          True if the preference isset and not empty
+     *                          false otherwise.
+     */
+    function exists($pref, $scope=null)
+    {
+        if (!isset($scope)) {
+            $scope =& $this->scope;
+        }
+        
+        return isset($_SESSION['_prefs'][$scope][$pref]);
+    }
+    
+    /**
+     * Clear a set preference value.
+     *
+     * @param string $pref      The name of the preference to check.
+     * @param string $scope     The scope for this preference.
+     */
+    function clearValue($pref, $scope=null)
+    {
+        if (!isset($scope)) {
+            $scope =& $this->scope;
+        }
+        
+        if (isset($_SESSION['_prefs'][$scope][$pref])) {
+            unset($_SESSION['_prefs'][$scope][$pref]);
+        }
+    }
+
+    /**
+     * Retrieves the requested set of preferences from the user's database
+     * entry.
+     *
+     * @param optional array $prefs  An array listing the preferences to
+     *                     retrieve. If not specified, retrieve all of the
+     *                     preferences listed in the $prefs hash.
+     *
+     * @return mixed       True on success or a PEAR_Error object on failure. 
+     */
+    function retrieve()
+    {
+        // Check that we don't have the preferences loaded yet.
+        if ($_SESSION['_prefs']['loaded'] == true || !$_perpetual) {
             return true;
         }
 
-        $this->initDB();
-
-        $this->_init();
-
-        // Prefs already loaded for this session.
-        if (!$force && $this->_isLoaded()) {
+        // FIXME: Database query goes here....
+        return false;
+        
+        $_SESSION['_prefs']['loaded'] = true;
+    }
+
+    /**
+     * Stores preferences to SQL server.
+     *
+     * @param array $prefs (optional) An array listing the preferences to be
+     *                     stored.  If not specified, store all of the
+     *                     preferences listed in the $prefs hash.
+     *
+     * @return mixed       True on success or a PEAR_Error object on failure.
+     */
+    function store($prefs=array())
+    {
+        // If we are not storing prefs in perpetually.
+        if (!$_perpetual) {
             return true;
         }
-
-        // User_id must not be empty.
-        if ('' == $this->getParam('user_id')) {
-            $app->logMsg(sprintf('Cannot load prefs because user_id not set.', null), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Clear existing cache.
-        $this->clear('saved');
-
-        // Retrieve all prefs for this user and namespace.
-        $stmt = $pdo->prepare(sprintf("SELECT `pref_key`, `pref_value` FROM `%s` WHERE `user_id` = ? AND `pref_namespace` = ? LIMIT 100000", $pdo->sanitizeIdentifier($this->getParam('db_table'))));
-        $stmt->execute([$this->getParam('user_id'), $this->getParam('namespace')]);
-        while (list($key, $val) = $stmt->fetch(\PDO::FETCH_NUM)) {
-            $_SESSION['_prefs'][$this->_ns]['saved'][$key] = unserialize($val);
-        }
-
-        $app->logMsg(sprintf('Loaded %s prefs from database.', sizeof($_SESSION['_prefs'][$this->_ns]['saved'])), LOG_DEBUG, __FILE__, __LINE__);
-
-        // Data loaded only once per session.
-        $_SESSION['_prefs'][$this->_ns]['loaded'] = true;
-        $_SESSION['_prefs'][$this->_ns]['load_datetime'] = date('Y-m-d H:i:s');
-
-        return true;
-    }
-
-    /*
-    * Returns true if the prefs had been loaded from the database into the $_SESSION recently.
-    * This function is simply a check so the database isn't access every page load.
-    *
-    * @access   private
-    * @return   bool    True if prefs are loaded.
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @version  1.0
-    * @since    04 Jun 2006 17:12:44
-    */
-    protected function _isLoaded()
-    {
-        if ('database' != $this->getParam('storagetype')) {
-            $app->logMsg('Prefs->_isLoaded() does nothing unless using a database storagetype.', LOG_DEBUG, __FILE__, __LINE__);
-            return true;
-        }
-
-        $this->_init();
-
-        if (isset($_SESSION['_prefs'][$this->_ns]['load_datetime'])
-        && strtotime($_SESSION['_prefs'][$this->_ns]['load_datetime']) > time() - $this->getParam('load_timeout')
-        && isset($_SESSION['_prefs'][$this->_ns]['loaded'])
-        && true === $_SESSION['_prefs'][$this->_ns]['loaded']) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /*
-    * Saves all prefs stored in the $_SESSION into the database.
-    *
-    * @access   public
-    * @return   bool    True if prefs exist and were saved.
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @version  1.0
-    * @since    04 Jun 2006 17:19:56
-    */
-    public function save($allow_empty=false)
-    {
-        $app =& App::getInstance();
-        $pdo =& \Strangecode\Codebase\PDO::getInstance();
-
-        // Skip this method if not using the db.
-        if ('database' != $this->getParam('storagetype')) {
-            $app->logMsg('Prefs->save() does nothing unless using a database storagetype.', LOG_DEBUG, __FILE__, __LINE__);
-            return true;
-        }
-
-        // User_id must not be empty.
-        if ('' == $this->getParam('user_id')) {
-            $app->logMsg(sprintf('Cannot save prefs because user_id not set.', null), LOG_DEBUG, __FILE__, __LINE__);
-            return false;
-        }
-
-        $this->initDB();
-
-        $this->_init();
-
-        if (isset($_SESSION['_prefs'][$this->_ns]['saved']) && is_array($_SESSION['_prefs'][$this->_ns]['saved']) && ($allow_empty || !empty($_SESSION['_prefs'][$this->_ns]['saved']))) {
-            // Delete old prefs from database.
-            $stmt = $pdo->prepare(sprintf("DELETE FROM `%s` WHERE `user_id` = ? AND `pref_namespace` = ?", $pdo->sanitizeIdentifier($this->getParam('db_table'))));
-            $stmt->execute([$this->getParam('user_id'), $this->getParam('namespace')]);
-
-            // Insert new prefs.
-            $insert_values = array();
-            foreach ($_SESSION['_prefs'][$this->_ns]['saved'] as $key => $val) {
-                $insert_values[] = sprintf("(%s, %s, %s, %s)",
-                    $pdo->quote($this->getParam('user_id')),
-                    $pdo->quote($this->getParam('namespace')),
-                    $pdo->quote($key),
-                    $pdo->quote(serialize($val))
-                );
-            }
-            if (!empty($insert_values)) {
-                $stmt = $pdo->query(sprintf("
-                    INSERT INTO `%s`
-                    (`user_id`, `pref_namespace`, `pref_key`, `pref_value`)
-                    VALUES
-                    %s
-                ", $pdo->sanitizeIdentifier($this->getParam('db_table')), join(', ', $insert_values)));
-                $app->logMsg(sprintf('Saved %s prefs to database for user_id %s.', sizeof($insert_values), $this->getParam('user_id')), LOG_DEBUG, __FILE__, __LINE__);
-            }
-
-            return true;
-        }
-
+        
+        /*
+         * If a list of preferences to store hasn't been provided in
+         * $prefs, assume all preferences are desired.
+         */
+        if (empty($prefs)) {
+            $prefs =& $_SESSION['_prefs'];
+        } else if ($_SESSION['_prefs']['loaded'] == true) {
+            $prefs = array_merge($_SESSION['_prefs'], $prefs);
+        }
+        
+        if (!is_array($prefs) || empty($prefs)) {
+            App::raiseMsg(_("No preferences are available."), MSG_ERR, __FILE__, __LINE__);
+            App::dieBoomerangURL();
+        }
+        
+        // FIXME: Database query goes here....
         return false;
-    }
-
-    /*
-    *
-    *
-    * @access   public
-    * @param
-    * @return
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @version  1.0
-    * @since    02 May 2014 18:17:04
-    */
-    protected function _getCookieName($key)
-    {
-        $app =& App::getInstance();
-
-        if (mb_strpos($key, sprintf('_prefs-%s', $this->_ns)) === 0) {
-            $app->logMsg(sprintf('Invalid key name (%s). Leave off "_prefs-%s-" and it should work.', $key, $this->_ns), LOG_NOTICE, __FILE__, __LINE__);
-        }
-        // Use standardized class data names: _ + classname + namespace + variablekey
-        // (namespace = namespace + user_id)
-        return sprintf('_prefs-%s-%s', $this->_ns, $key);
+
+    }
+
+    /**
+     * Perform cleanup operations.
+     */
+    function cleanup()
+    {
+        $_SESSION['_prefs'] = array();
     }
 }
 
+
+
+
+?>
