From: Michael M Slusarz Date: Mon, 8 Nov 2010 22:49:57 +0000 (-0700) Subject: Finish Horde_Prefs rewrite X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=e42b0c9a2e41ab5d6e42ebec540ce70af56a1f38;p=horde.git Finish Horde_Prefs rewrite Main focus: ability to to stack storage drivers to allow for multiple drivers to build a preferences scope. Horde now uses 3 storage drivers to build the final prefs hash: the configuration file, prefs backend, and hooks. Caching needed to be separated from storage since the two objects do *not* store the same data. Caching is intended to store the entire preference scope, storage only handles discrete preference values. Default/dirty bits are now entirely handled internally by the Scope object. Remove all external charset conversion API for prefs. Charset conversion, if needed, should be done entirely within the storage driver (prefs now assumes all in-memory prefs are in UTF-8). --- diff --git a/framework/Core/lib/Horde/Core/Factory/Prefs.php b/framework/Core/lib/Horde/Core/Factory/Prefs.php index 4d0fec07c..8d72ead7b 100644 --- a/framework/Core/lib/Horde/Core/Factory/Prefs.php +++ b/framework/Core/lib/Horde/Core/Factory/Prefs.php @@ -55,20 +55,14 @@ class Horde_Core_Factory_Prefs * Return the Horde_Prefs:: instance. * * @param string $scope The scope for this set of preferences. - * @param array $opts See Horde_Prefs::__construct(). Additional - * options: - *
-     * 'session' - (boolean) Use the session driver.
-     *             DEFAULT: false
-     * 
+ * @param array $opts See Horde_Prefs::__construct(). * * @return Horde_Prefs The singleton instance. */ public function create($scope = 'horde', array $opts = array()) { - if (empty($GLOBALS['conf']['prefs']['driver']) || - !empty($opts['session'])) { - $driver = 'Horde_Core_Prefs_Storage_Session'; + if (empty($GLOBALS['conf']['prefs']['driver'])) { + $driver = null; $params = array(); } else { $driver = 'Horde_Prefs_Storage_' . ucfirst($GLOBALS['conf']['prefs']['driver']); @@ -77,7 +71,6 @@ class Horde_Core_Factory_Prefs $opts = array_merge(array( 'cache' => true, - 'charset' => 'UTF-8', 'logger' => $this->_injector->getInstance('Horde_Log_Logger'), 'password' => '', 'sizecallback' => ((isset($GLOBALS['conf']['prefs']['maxsize'])) ? array($this, 'sizeCallback') : null), @@ -108,22 +101,31 @@ class Horde_Core_Factory_Prefs case 'Horde_Prefs_Storage_Sql': $params['db'] = $this->_injector->getInstance('Horde_Db_Adapter'); - $opts['charset'] = $params['db']->getOption('charset'); break; } - $drivers = array( - new $driver($opts['user'], $params) - ); + $config_driver = new Horde_Core_Prefs_Storage_Configuration($opts['user']); + $hooks_driver = new Horde_Core_Prefs_Storage_Hooks($opts['user'], array('conf_ob' => $config_driver)); + + $drivers = $driver + ? array( + $config_driver, + new $driver($opts['user'], $params), + $hooks_driver + ) + : array( + $config_driver, + $hooks_driver + ); if ($opts['cache']) { - $opts['cache'] = new Horde_Core_Prefs_Storage_Session($opts['user']); + $opts['cache'] = new Horde_Core_Prefs_Cache_Session($opts['user']); } else { unset($opts['cache']); } try { - $this->_instances[$sig] = new Horde_Core_Prefs($scope, $drivers, $opts); + $this->_instances[$sig] = new Horde_Prefs($scope, $drivers, $opts); } catch (Horde_Prefs_Exception $e) { if (!$GLOBALS['session']->get('horde', 'no_prefs')) { $GLOBALS['session']->set('horde', 'no_prefs', true); @@ -131,8 +133,10 @@ class Horde_Core_Factory_Prefs $GLOBALS['notification']->push(Horde_Core_Translation::t("The preferences backend is currently unavailable and your preferences have not been loaded. You may continue to use the system with default preferences.")); } } - unset($opts['cache']); - $this->_instances[$sig] = new Horde_Core_Prefs($scope, new Horde_Core_Prefs_Storage_Session($opts['user']), $opts); + + /* Store data in the cached session object. */ + $opts['cache'] = new Horde_Core_Prefs_Cache_Session($opts['user']); + $this->_instances[$sig] = new Horde_Prefs($scope, array($config_driver, $hooks_driver), $opts); } } diff --git a/framework/Core/lib/Horde/Core/Prefs.php b/framework/Core/lib/Horde/Core/Prefs.php deleted file mode 100644 index 0ff57b47c..000000000 --- a/framework/Core/lib/Horde/Core/Prefs.php +++ /dev/null @@ -1,112 +0,0 @@ - - * @category Horde - * @license http://www.fsf.org/copyleft/lgpl.html LGPL - * @package Core - */ -class Horde_Core_Prefs extends Horde_Prefs -{ - /** - * Hash holding preferences with hook functions defined. - * - * @var array - */ - protected $_hooks = array(); - - /** - */ - protected function _setValue($pref, $val, $convert = true) - { - if (!parent::_setValue($pref, $val, $convert)) { - return false; - } - - /* If this preference has a change hook, call it now. */ - try { - Horde::callHook('prefs_change', array($pref), $this->_getPrefScope($pref)); - } catch (Horde_Exception_HookNotSet $e) {} - - return true; - } - - /** - * Populates the $_scopes hash with the default values as loaded from - * an application's prefs.php file. - */ - protected function _loadScopePre($scope) - { - /* Read the configuration file. The $_prefs array holds the default - * values. */ - try { - $result = Horde::loadConfiguration('prefs.php', array('_prefs'), $scope); - if (empty($result) || !isset($result['_prefs'])) { - return; - } - } catch (Horde_Exception $e) { - return; - } - - foreach ($result['_prefs'] as $name => $pref) { - if (!isset($pref['value'])) { - continue; - } - - $name = str_replace('.', '_', $name); - - $mask = self::IS_DEFAULT; - if (!empty($pref['locked'])) { - $mask |= self::LOCKED; - } - - $this->_scopes[$scope][$name] = array( - 'm' => $mask, - 'v' => $pref['value'] - ); - - if (!empty($pref['hook'])) { - $this->_hooks[$scope][] = $name; - } - } - } - - /** - * After preferences have been loaded, set any locked or empty - * preferences that have hooks to the result of the hook. - */ - protected function _loadScopePost($scope) - { - if (empty($this->_hooks[$scope])) { - return; - } - - foreach ($this->_hooks[$scope] as $name) { - if ($this->isLocked($name) || - $this->isDefault($name) || - empty($this->_scopes[$scope][$name]['v'])) { - try { - $val = Horde::callHook('prefs_init', array($name, $this->getUser()), $scope); - } catch (Horde_Exception_HookNotSet $e) { - continue; - } - - $this->_scopes[$scope][$name]['v'] = $this->isDefault($name) - ? $val - : $this->convertToDriver($val); - - if (!$this->isLocked($name)) { - $this->setDirty($pref, true); - } - } - } - } - -} diff --git a/framework/Core/lib/Horde/Core/Prefs/Cache/Session.php b/framework/Core/lib/Horde/Core/Prefs/Cache/Session.php new file mode 100644 index 000000000..6bb8fdbb5 --- /dev/null +++ b/framework/Core/lib/Horde/Core/Prefs/Cache/Session.php @@ -0,0 +1,44 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Core + */ +class Horde_Core_Prefs_Cache_Session extends Horde_Prefs_Cache +{ + const SESS_KEY = 'prefs_cache/'; + + /** + */ + public function get($scope) + { + global $session; + + return $session->exists('horde', self::SESS_KEY . $scope) + ? $session->get('horde', self::SESS_KEY . $scope) + : false; + } + + /** + */ + public function store($scope_ob) + { + $GLOBALS['session']->set('horde', self::SESS_KEY . $scope_ob->scope, $scope_ob); + } + + /** + */ + public function remove($scope = null) + { + $GLOBALS['session']->remove('horde', self::SESS_KEY . strval($scope)); + } + +} diff --git a/framework/Core/lib/Horde/Core/Prefs/Storage/Configuration.php b/framework/Core/lib/Horde/Core/Prefs/Storage/Configuration.php new file mode 100644 index 000000000..d3f5a53bb --- /dev/null +++ b/framework/Core/lib/Horde/Core/Prefs/Storage/Configuration.php @@ -0,0 +1,72 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Core + */ +class Horde_Core_Prefs_Storage_Configuration extends Horde_Prefs_Storage +{ + /** + * The list of preference hooks defined. + * + * @var array + */ + public $hooks = array(); + + /** + */ + public function get($scope_ob) + { + /* Read the configuration file. + * Values are in the $_prefs array. */ + try { + $result = Horde::loadConfiguration('prefs.php', array('_prefs'), $scope_ob->scope); + if (empty($result) || !isset($result['_prefs'])) { + return false; + } + } catch (Horde_Exception $e) { + return false; + } + + foreach ($result['_prefs'] as $name => $pref) { + if (!isset($pref['value'])) { + continue; + } + + $scope_ob->set($name, $pref['value']); + if (!empty($pref['locked'])) { + $scope_ob->setLocked($name, true); + } + + if (!empty($pref['hook'])) { + $this->hooks[$scope_ob->scope][] = $name; + } + } + + return $scope_ob; + } + + /** + */ + public function store($scope_ob) + { + // Configuration files are read-only. + } + + /** + */ + public function remove($scope = null, $pref = null) + { + // Configuration files are read-only. + } + +} diff --git a/framework/Core/lib/Horde/Core/Prefs/Storage/Hooks.php b/framework/Core/lib/Horde/Core/Prefs/Storage/Hooks.php new file mode 100644 index 000000000..6332abe8d --- /dev/null +++ b/framework/Core/lib/Horde/Core/Prefs/Storage/Hooks.php @@ -0,0 +1,60 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Core + */ +class Horde_Core_Prefs_Storage_Hooks extends Horde_Prefs_Storage +{ + /** + */ + public function get($scope_ob) + { + $conf_ob = $this->_params['conf_ob']; + + if (empty($conf_ob->hooks[$scope_ob->scope])) { + return $scope_ob; + } + + foreach ($conf_ob->_hooks[$scope_ob->scope] as $name) { + try { + $scope_ob->set($name, Horde::callHook('prefs_init', array($name, $this->_params['user']), $scope_ob->scope)); + } catch (Horde_Exception_HookNotSet $e) {} + } + + return $scope_ob; + } + + /** + */ + public function store($scope_ob) + { + // Hooks are read-only. + } + + /** + */ + public function onChange($scope, $pref) + { + try { + Horde::callHook('prefs_change', array($pref), $scope); + } catch (Horde_Exception_HookNotSet $e) {} + } + + /** + */ + public function remove($scope = null, $pref = null) + { + // Hooks are read-only. + } + +} diff --git a/framework/Core/lib/Horde/Core/Prefs/Storage/Session.php b/framework/Core/lib/Horde/Core/Prefs/Storage/Session.php deleted file mode 100644 index 47040a675..000000000 --- a/framework/Core/lib/Horde/Core/Prefs/Storage/Session.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @category Horde - * @license http://www.fsf.org/copyleft/lgpl.html LGPL - * @package Core - */ -class Horde_Core_Prefs_Storage_Session extends Horde_Prefs_Storage -{ - const SESS_KEY = 'prefs_session/'; - - /** - */ - public function get($scope) - { - global $session; - - return $session->exists('horde', self::SESS_KEY . $scope) - ? $session->get('horde', self::SESS_KEY . $scope) - : false; - } - - /** - */ - public function store($prefs) - { - foreach ($prefs as $scope => $vals) { - if (($old_vals = $this->get($scope)) === false) { - $old_vals = array(); - } - $GLOBALS['session']->set('horde', self::SESS_KEY . $scope, array_merge($old_vals, $vals)); - } - } - - /** - */ - public function remove($scope = null, $pref = null) - { - global $session; - - if (is_null($scope)) { - $session->remove('horde', self::SESS_KEY); - } elseif (is_null($pref)) { - $session->remove('horde', self::SESS_KEY . $this->_scope); - } elseif ((($vals = $this->get($scope)) !== false) && - isset($vals[$pref])) { - unset($vals[$pref]); - $session->set('horde', self::SESS_KEY . $scope, $vals); - } - } - -} diff --git a/framework/Core/package.xml b/framework/Core/package.xml index 17f49b063..47c3b0b90 100644 --- a/framework/Core/package.xml +++ b/framework/Core/package.xml @@ -195,8 +195,12 @@ Application Framework. - + + + + + @@ -237,7 +241,6 @@ Application Framework. - @@ -712,7 +715,6 @@ Application Framework. - @@ -796,7 +798,9 @@ Application Framework. - + + + diff --git a/framework/Prefs/lib/Horde/Prefs.php b/framework/Prefs/lib/Horde/Prefs.php index d911c1b64..c5cd30b0c 100644 --- a/framework/Prefs/lib/Horde/Prefs.php +++ b/framework/Prefs/lib/Horde/Prefs.php @@ -16,31 +16,17 @@ */ class Horde_Prefs implements ArrayAccess { - /** Preference is administratively locked. */ - const LOCKED = 1; - - /** Preference value is the application default. - * DEFAULT is a reserved PHP constant. */ - const IS_DEFAULT = 2; - /* The default scope name. */ const DEFAULT_SCOPE = 'horde'; /** * Caching object. * - * @var Horde_Prefs_Storage + * @var Horde_Prefs_Cache */ protected $_cache; /** - * List of dirty prefs. - * - * @var array - */ - protected $_dirty = array(); - - /** * General library options. * * @var array @@ -56,23 +42,16 @@ class Horde_Prefs implements ArrayAccess /** * String containing the name of the current scope. This is used - * to differentiate between sets of preferences. By default, preferences - * belong to the "global" (Horde) scope. + * to differentiate between sets of preferences. By default, preferences + * belong to this scope. * * @var string */ protected $_scope = self::DEFAULT_SCOPE; /** - * Preferences list. Stored by scope name. Each preference has the - * following format: - *
-     * [pref_name] => array(
-     *     [d] => (string) Default value
-     *     [m] => (integer) Pref mask
-     *     [v] => (string) Current pref value
-     * )
-     * 
+ * Scope list. Keys are scope names, values are Horde_Prefs_Scope + * objects. * * @var array */ @@ -94,14 +73,8 @@ class Horde_Prefs implements ArrayAccess * objects. * @param array $opts Additional confguration options: *
-     * REQUIRED:
-     * ---------
-     * charset - (string) Default charset.
-     *
-     * OPTIONAL:
-     * ---------
-     * cache - (string) The class name defining the cache driver to use.
-     *         DEFAULT: Caching is not used
+     * cache - (Horde_Prefs_Cache) The cache driver to use.
+     *         DEFAULT: No caching.
      * logger - (Horde_Log_Logger) Logging object.
      *          DEFAULT: NONE
      * password - (string) The password associated with 'user'.
@@ -112,31 +85,23 @@ class Horde_Prefs implements ArrayAccess
      * user - (string) The name of the user who owns this set of preferences.
      *        DEFAULT: NONE
      * 
- * - * @throws InvalidArgumentException */ public function __construct($scope, $storage = null, array $opts = array()) { - if (!isset($opts['charset'])) { - throw new InvalidArgumentException(__CLASS__ . ': Missing charset parameter.'); - } - $this->_opts = array_merge($this->_opts, $opts); - $default = __CLASS__ . '_Storage_Null'; - $this->_cache = isset($this->_opts['cache']) ? $this->_opts['cache'] - : new $default($this->getUser()); + : new Horde_Prefs_Cache_Null($this->getUser()); + $this->_scope = $scope; + if (is_null($storage)) { - $this->_storage = array(new $default($this->getUser())); - } else { - if (!is_array($storage)) { - $storage = array($storage); - } - $this->_storage = $storage; + $storage = array(new Horde_Prefs_Storage_Null($this->getUser())); + } elseif (!is_array($storage)) { + $storage = array($storage); } + $this->_storage = $storage; register_shutdown_function(array($this, 'store')); @@ -144,16 +109,6 @@ class Horde_Prefs implements ArrayAccess } /** - * Returns the charset used by the concrete preference backend. - * - * @return string The preference backend's charset. - */ - public function getCharset() - { - return $this->_opts['charset']; - } - - /** * Return the user who owns these preferences. * * @return string The user these preferences are for. @@ -174,40 +129,14 @@ class Horde_Prefs implements ArrayAccess } /** - * Change scope without explicitly retrieving preferences. - * - * @param string $scope The new scope. - */ - public function setScope($scope) - { - $this->_scope = $scope; - } - - /** * Removes a preference entry from the $prefs hash. * * @param string $pref The name of the preference to remove. */ public function remove($pref) { - $scope = $this->_getPrefScope($pref); - unset( - $this->_dirty[$scope][$pref], - $this->_scopes[$scope][$pref] - ); - - foreach ($this->_storage as $storage) { - try { - $storage->remove($scope, $pref); - } catch (Horde_Prefs_Exception $e) { - // TODO: logging - } - } - - try { - $this->_cache->remove($scope, $pref); - } catch (Horde_Prefs_Exception $e) { - // TODO: logging + if ($scope = $this->_getScope($pref)) { + $this->_scopes[$scope]->remove($pref); } } @@ -215,96 +144,40 @@ class Horde_Prefs implements ArrayAccess * Sets the given preference to the specified value if the preference is * modifiable. * - * @param string $pref The name of the preference to modify. - * @param string $val The new value for this preference. - * @param boolean $convert If true the preference value gets converted - * from the current charset to the backend's - * charset. + * @param string $pref The preference name to modify. + * @param string $val The preference value (UTF-8). + * @param array $opts Additional options: + *
+     * nosave - (boolean) If true, the preference will not be saved to the
+     *          storage backend(s).
+     * 
* * @return boolean True if the value was successfully set, false on a * failure. * @throws Horde_Prefs_Exception */ - public function setValue($pref, $val, $convert = true) + public function setValue($pref, $val, array $opts = array()) { - $scope = $this->_getPrefScope($pref); - - /* Exit early if this preference is locked or doesn't exist. */ - if (!isset($this->_scopes[$scope][$pref]) || $this->isLocked($pref)) { + /* Exit early if preference doesn't exist or is locked. */ + if (!($scope = $this->_getScope($pref)) || + $this->_scopes[$scope]->isLocked($pref)) { return false; } - if (!$this->_setValue($pref, $val, $convert)) { - return false; - } - - $this->_cache->store(array( - $scope => array( - $pref => $this->_scopes[$scope][$pref] - ) - )); - - return true; - } - - /** - * Shortcut to setValue(). - */ - public function __set($name, $value) - { - return $this->setValue($name, $value); - } - - /** - * Sets the given preferences ($pref) to the specified value - * ($val), whether or not the preference is user-modifiable, unset - * the default bit, and set the dirty bit. - * - * @param string $pref The name of the preference to modify. - * @param string $val The new value for this preference. - * @param boolean $convert If true the preference value gets converted - * from the current charset to the backend's - * charset. - * - * @return boolean True if the value was successfully set, false on a - * failure. - */ - protected function _setValue($pref, $val, $convert = true) - { - if ($convert) { - $val = $this->convertToDriver($val); - } - - $scope = $this->_getPrefScope($pref); - - // If the preference's value is already equal to $val, don't - // bother changing it. Changing it would set the "dirty" bit, - // causing an unnecessary update later. - if (isset($this->_scopes[$scope][$pref]) && - (($this->_scopes[$scope][$pref]['v'] == $val) && - !$this->isDefault($pref))) { - return true; - } - - // Check to see if the value exceeds the allowable storage - // limit. + // Check to see if the value exceeds the allowable storage limit. if ($this->_opts['sizecallback'] && call_user_func($this->_opts['sizecallback'], $pref, strlen($val))) { return false; } - // Assign the new value, unset the "default" bit, and set the - // "dirty" bit. - $ptr = &$this->_scopes[$scope][$pref]; - if (empty($ptr['m'])) { - $ptr['m'] = 0; + $this->_scopes[$scope]->set($pref, $val); + if (!empty($opts['nosave'])) { + $this->_scopes[$scope]->setDirty($pref, false); } - if (!isset($ptr['d'])) { - $ptr['d'] = $ptr['v']; + + foreach ($this->_storage as $storage) { + $storage->onChange($scope, $pref); } - $ptr['v'] = $val; - $this->setDefault($pref, false); - $this->setDirty($pref, true); if ($this->_opts['logger']) { $this->_opts['logger']->log(__CLASS__ . ': Storing preference value (' . $pref . ')', 'DEBUG'); @@ -314,32 +187,26 @@ class Horde_Prefs implements ArrayAccess } /** + * Shortcut to setValue(). + */ + public function __set($name, $value) + { + return $this->setValue($name, $value); + } + + /** * Returns the value of the requested preference. * - * @param string $pref The name of the preference to retrieve. - * @param boolean $convert If true the preference value gets converted - * from the backend's charset to the current - * charset. + * @param string $pref The preference name. * - * @return string The value of the preference, null if it doesn't exist. + * @return string The value of the preference (UTF-8), null if it doesn't + * exist. */ - public function getValue($pref, $convert = true) + public function getValue($pref) { - $scope = $this->_getPrefScope($pref); - - $value = isset($this->_scopes[$scope][$pref]['v']) - ? $this->_scopes[$scope][$pref]['v'] + return ($scope = $this->_getScope($pref)) + ? $this->_scopes[$scope]->get($pref) : null; - - if ($convert && - !is_null($value) && - !$this->isDefault($pref)) { - /* Default values have the current UI charset. - * Stored values have the backend charset. */ - $value = $this->convertFromDriver($value); - } - - return $value; } /** @@ -351,67 +218,44 @@ class Horde_Prefs implements ArrayAccess } /** - * Modifies the "locked" bit for the given preference. + * Mark a preference as locked. * - * @param string $pref The name of the preference to modify. - * @param boolean $bool The new boolean value for the "locked" bit. + * @param string $pref The preference name. + * @param boolean $locked Is the preference locked? */ public function setLocked($pref, $bool) { - $this->_setMask($pref, $bool, self::LOCKED); + if ($scope = $this->_getScope($pref)) { + $this->_scopes[$scope]->setLocked($pref, $bool); + } } /** - * Returns the state of the "locked" bit for the given preference. + * Is a preference locked? * - * @param string $pref The name of the preference to check. + * @param string $pref The preference name. * - * @return boolean The boolean state of $pref's "locked" bit. + * @return boolean Whether the preference is locked. */ public function isLocked($pref) { - return $this->_getMask($pref, self::LOCKED); - } - - /** - * Modifies the "dirty" bit for the given preference. - * - * @param string $pref The name of the preference to modify. - * @param boolean $bool The new boolean value for the "dirty" bit. - */ - public function setDirty($pref, $bool) - { - $scope = $this->_getPrefScope($pref); - - if ($bool) { - $this->_dirty[$scope][$pref] = $this->_scopes[$scope][$pref]; - } else { - unset($this->_dirty[$scope][$pref]); - } + return ($scope = $this->_getScope($pref)) + ? $this->_scopes[$scope]->isLocked($pref) + : false; } /** - * Returns the state of the "dirty" bit for the given preference. + * Is a preference marked dirty? * - * @param string $pref The name of the preference to check. + * @param string $pref The preference name. * - * @return boolean The boolean state of $pref's "dirty" bit. + * @return boolean True if the preference is marked dirty. */ public function isDirty($pref) { - $scope = $this->_getPrefScope($pref); - return isset($this->_dirty[$scope][$pref]); - } - - /** - * Modifies the "default" bit for the given preference. - * - * @param string $pref The name of the preference to modify. - * @param boolean $bool The new boolean value for the "default" bit. - */ - public function setDefault($pref, $bool) - { - $this->_setMask($pref, $bool, self::IS_DEFAULT); + return ($scope = $this->_getScope($pref)) + ? $this->_scopes[$scope]->isDirty($pref) + : false; } /** @@ -423,11 +267,9 @@ class Horde_Prefs implements ArrayAccess */ public function getDefault($pref) { - $scope = $this->_getPrefScope($pref); - - return isset($this->_scopes[$scope][$pref]['d']) - ? $this->_scopes[$scope][$pref]['d'] - : ''; + return ($scope = $this->_getScope($pref)) + ? $this->_scopes[$scope]->getDefault($pref) + : null; } /** @@ -440,59 +282,29 @@ class Horde_Prefs implements ArrayAccess */ public function isDefault($pref) { - return $this->_getMask($pref, self::IS_DEFAULT); - } - - /** - * Sets the value for a given mask. - * - * @param string $pref The name of the preference to modify. - * @param boolean $bool The new boolean value for the "default" bit. - * @param integer $mask The mask to add. - */ - protected function _setMask($pref, $bool, $mask) - { - $scope = $this->_getPrefScope($pref); - - if (isset($this->_scopes[$scope][$pref]) && - ($bool != $this->_getMask($pref, $mask))) { - if ($bool) { - $this->_scopes[$scope][$pref]['m'] |= $mask; - } else { - $this->_scopes[$scope][$pref]['m'] &= ~$mask; - } - } - } - - /** - * Gets the boolean state for a given mask. - * - * @param string $pref The name of the preference to modify. - * @param integer $mask The mask to get. - * - * @return boolean The boolean state for the given mask. - */ - protected function _getMask($pref, $mask) - { - $scope = $this->_getPrefScope($pref); - - return isset($this->_scopes[$scope][$pref]['m']) - ? (bool)($this->_scopes[$scope][$pref]['m'] & $mask) + return ($scope = $this->_getScope($pref)) + ? $this->_scopes[$scope]->isDefault($pref) : false; } /** - * Returns the scope of the given preference. + * Returns the scope of a preference. * - * @param string $pref The name of the preference to examine. + * @param string $pref The preference name. * - * @return string The scope of the $pref. + * @return mixed The scope of the preference, or null if it doesn't + * exist. */ - protected function _getPrefScope($pref) + protected function _getScope($pref) { - return (isset($this->_scopes[$this->_scope][$pref]) || !isset($this->_scopes[self::DEFAULT_SCOPE][$pref])) - ? $this->_scope - : self::DEFAULT_SCOPE; + if ($this->_scopes[$this->_scope]->exists($pref)) { + return $this->_scope; + } elseif (($this->_scope != self::DEFAULT_SCOPE) && + ($this->_scopes[self::DEFAULT_SCOPE]->exists($pref))) { + return self::DEFAULT_SCOPE; + } + + return null; } /** @@ -506,7 +318,7 @@ class Horde_Prefs implements ArrayAccess if (is_null($scope)) { $scope = $this->getScope(); } else { - $this->setScope($scope); + $this->_scope = $scope; } $this->_loadScope(self::DEFAULT_SCOPE); @@ -527,9 +339,6 @@ class Horde_Prefs implements ArrayAccess return; } - // Basic initialization so _something_ is always set. - $this->_scopes[$scope] = array(); - // Now check the prefs cache for existing values. try { if (($cached = $this->_cache->get($scope)) !== false) { @@ -538,127 +347,57 @@ class Horde_Prefs implements ArrayAccess } } catch (Horde_Prefs_Exception $e) {} - $this->_loadScopePre($scope); + $scope_ob = new Horde_Prefs_Scope($scope); + $scope_ob->init = true; foreach ($this->_storage as $storage) { - if (($prefs = $storage->get($scope)) !== false) { - foreach ($prefs as $name => $val) { - if (isset($this->_scopes[$scope][$name])) { - if ($this->isDefault($name)) { - $this->_scopes[$scope][$name]['d'] = $this->_scopes[$scope][$name]['v']; - } - } else { - $this->_scopes[$scope][$name] = array( - 'm' => 0 - ); - } - $this->_scopes[$scope][$name]['v'] = $val; - $this->setDefault($name, false); - } - } + $scope_ob = $storage->get($scope_ob); } - $this->_loadScopePost($scope); - - /* Update the cache. */ - $this->_cache->store(array($scope => $this->_scopes[$scope])); - } - - /** - * Actions to perform before a scope is loaded from storage. - * - * @param string $scope The scope to load. - */ - protected function _loadScopePre($scope) - { - } + $scope_ob->init = false; - /** - * Actions to perform after a scope is loaded from storage. - * - * @param string $scope The loaded scope. - */ - protected function _loadScopePost($scope) - { + $this->_scopes[$scope] = $scope_ob; + $this->_cache->store($scope_ob); } /** * This function will be run at the end of every request as a shutdown - * function (registered by the constructor). All prefs with the - * dirty bit set will be saved to the storage backend. + * function (registered by the constructor). All dirty prefs will be + * saved to the storage backend. */ public function store() { - if (!empty($this->_dirty)) { - foreach ($this->_storage as $storage) { - try { - $storage->store($this->_dirty); - - /* Clear the dirty flag. */ - foreach ($this->_dirty as $k => $v) { - foreach (array_keys($v) as $name) { - $this->setDirty($name, false); - } - } - } catch (Horde_Prefs_Exception $e) {} + foreach ($this->_scopes as $scope) { + if ($scope->isDirty()) { + foreach ($this->_storage as $storage) { + $storage->store($scope); + } + + $this->_cache->store($scope); } } } /** - * This function provides common cleanup functions for all of the driver - * implementations. + * Cleanup (e.g. remove) scope(s). * - * @param boolean $all Clean up all Horde preferences. + * @param boolean $all Cleanup all scopes. If false, clean present scope + * only. */ public function cleanup($all = false) { - /* Perform a Horde-wide cleanup? */ if ($all) { - /* Destroy the contents of the preferences hash. */ - $this->_dirty = $this->_scopes = array(); - - /* Destroy the contents of the preferences cache. */ - try { - $this->_cache->remove(); - } catch (Horde_Prefs_Exception $e) {} + /* Destroy all scopes. */ + $this->_scopes = array(); + $scope = null; } else { - $scope = $this->getScope(); - - $this->_dirty[$scope] = $this->_scopes[$scope] = array(); - /* Remove this scope from the preferences cache. */ - try { - $this->_cache->remove($scope); - } catch (Horde_Prefs_Exception $e) {} + unset($this->_scopes[$this->_scope]); + $scope = $this->_scope; } - } - /** - * Converts a value from the driver's charset to the specified charset. - * - * @param mixed $value A value to convert. - * - * @return mixed The converted value. - */ - public function convertFromDriver($value) - { - return is_bool($value) - ? $value - : Horde_String::convertCharset($value, $this->getCharset(), 'UTF-8'); - } - - /** - * Converts a value from the specified charset to the driver's charset. - * - * @param mixed $value A value to convert. - * - * @return mixed The converted value. - */ - public function convertToDriver($value) - { - return is_bool($value) - ? $value - : Horde_String::convertCharset($value, 'UTF-8', $this->getCharset()); + try { + $this->_cache->remove($scope); + } catch (Horde_Prefs_Exception $e) {} } /* ArrayAccess methods. */ diff --git a/framework/Prefs/lib/Horde/Prefs/Cache.php b/framework/Prefs/lib/Horde/Prefs/Cache.php new file mode 100644 index 000000000..89e84adc2 --- /dev/null +++ b/framework/Prefs/lib/Horde/Prefs/Cache.php @@ -0,0 +1,67 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Prefs + */ +abstract class Horde_Prefs_Cache +{ + /** + * Configuration parameters. + * 'user' is always available as an entry. + * + * @var string + */ + protected $_params = array(); + + /** + * Constructor. + * + * @param string $user The username. + * @param array $params Additional configuration parameters. + */ + public function __construct($user, array $params = array()) + { + $this->_params = array_merge($this->_params, $params); + $this->_params['user'] = $user; + } + + /** + * Retrieves the requested preferences scope from the cache backend. + * + * @param string $scope Scope specifier. + * + * @return mixed Returns false if no data is available, otherwise the + * Horde_Prefs_Scope object. + * @throws Horde_Prefs_Exception + */ + abstract public function get($scope); + + /** + * Stores preferences in the cache backend. + * + * @param Horde_Prefs_Scope $scope_ob The scope object to store. + * + * @throws Horde_Prefs_Exception + */ + abstract public function store($scope_ob); + + /** + * Removes preferences from the cache. + * + * @param string $scope The scope to remove. If null, clears entire + * cache. + * + * @throws Horde_Prefs_Exception + */ + abstract public function remove($scope = null); + +} diff --git a/framework/Prefs/lib/Horde/Prefs/Cache/Null.php b/framework/Prefs/lib/Horde/Prefs/Cache/Null.php new file mode 100644 index 000000000..cfe656247 --- /dev/null +++ b/framework/Prefs/lib/Horde/Prefs/Cache/Null.php @@ -0,0 +1,36 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Prefs + */ +class Horde_Prefs_Cache_Null extends Horde_Prefs_Cache +{ + /** + */ + public function get($scope) + { + return false; + } + + /** + */ + public function store($scope_ob) + { + } + + /** + */ + public function remove($scope = null) + { + } + +} diff --git a/framework/Prefs/lib/Horde/Prefs/Cache/Session.php b/framework/Prefs/lib/Horde/Prefs/Cache/Session.php new file mode 100644 index 000000000..0d2cb6a52 --- /dev/null +++ b/framework/Prefs/lib/Horde/Prefs/Cache/Session.php @@ -0,0 +1,60 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Prefs + */ +class Horde_Prefs_Cache_Session extends Horde_Prefs_Cache +{ + /** + * Session key. + * + * @var string + */ + protected $_key; + + /** + */ + public function __construct($user, array $params = array()) + { + parent::__construct($user, $params); + + $this->_key = 'horde_prefs_cache_' . $this->_params['user']; + } + + /** + */ + public function get($scope) + { + return isset($_SESSION[$this->_key][$scope]) + ? $_SESSION[$this->_key][$scope] + : false; + } + + /** + */ + public function store($scope_ob) + { + $_SESSION[$this->_key][$scope_ob->getScope()] = $scope_ob; + } + + /** + */ + public function remove($scope = null) + { + if (is_null($scope)) { + unset($_SESSION[$this->_key]); + } else { + unset($_SESSION[$this->_key][$scope]); + } + } + +} diff --git a/framework/Prefs/lib/Horde/Prefs/Identity.php b/framework/Prefs/lib/Horde/Prefs/Identity.php index b4ce7bf46..c8b5bdf12 100644 --- a/framework/Prefs/lib/Horde/Prefs/Identity.php +++ b/framework/Prefs/lib/Horde/Prefs/Identity.php @@ -91,10 +91,8 @@ class Horde_Prefs_Identity $this->_prefs = $params['prefs']; $this->_user = $params['user']; - if (!($this->_identities = @unserialize($this->_prefs->getValue($this->_prefnames['identities'], false)))) { + if (!($this->_identities = @unserialize($this->_prefs->getValue($this->_prefnames['identities'])))) { $this->_identities = $this->_prefs->getDefault($this->_prefnames['identities']); - } elseif (is_array($this->_identities)) { - $this->_identities = $this->_prefs->convertFromDriver($this->_identities); } $this->setDefault($this->_prefs->getValue($this->_prefnames['default_identity'])); @@ -124,8 +122,7 @@ class Horde_Prefs_Identity if (is_array($value)) { $value = implode("\n", $value); } - $this->_prefs->setValue($key, $value); - $this->_prefs->setDirty($key, false); + $this->_prefs->setValue($key, $value, array('nosave' => true)); } } } diff --git a/framework/Prefs/lib/Horde/Prefs/Scope.php b/framework/Prefs/lib/Horde/Prefs/Scope.php new file mode 100644 index 000000000..0bf1c2756 --- /dev/null +++ b/framework/Prefs/lib/Horde/Prefs/Scope.php @@ -0,0 +1,271 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Prefs + */ +class Horde_Prefs_Scope implements Serializable +{ + /** + * Is the object being initialized? + * + * @var boolean + */ + public $init = false; + + /** + * The scope name. + * + * @var string + */ + public $scope; + + /** + * List of dirty prefs. + * + * @var array + */ + protected $_dirty = array(); + + /** + * Preferences list. Each preference has the following format: + *
+     * [pref_name] => array(
+     *     [d] => (string) Default value
+     *            If not present, 'v' is the default value.
+     *     [l] => (boolean) Locked
+     *            If not present, pref is not locked.
+     *     [v] => (string) Current pref value
+     * )
+     * 
+ * + * @var array + */ + protected $_prefs = array(); + + /** + * Constructor. + * + * @param string $scope The scope for this set of preferences. + */ + public function __construct($scope) + { + $this->scope = $scope; + } + + /** + * Removes a preference entry. + * + * @param string $pref The name of the preference to remove. + * + * @return boolean True if preference was removed. + */ + public function remove($pref) + { + if (!isset($this->_prefs[$pref])) { + return false; + } + + unset($this->_prefs[$pref]); + if (!$this->init) { + $this->setDirty($pref, true); + } + + return true; + } + + /** + * Sets the value for a preference. + * + * @param string $pref The preference name. + * @param string $val The preference value. + */ + public function set($pref, $val) + { + if (isset($this->_prefs[$pref])) { + $ptr = &$this->_prefs[$pref]; + + if ($val != $ptr['v']) { + if (isset($ptr['d']) && ($val == $ptr['d'])) { + unset($ptr['d']); + } else { + $ptr['d'] = $ptr['v']; + } + $ptr['v'] = $val; + + if (!$this->init) { + $this->setDirty($pref, true); + } + } + } else { + $this->_prefs[$pref] = array( + 'v' => $val + ); + + if (!$this->init) { + $this->setDirty($pref, true); + } + } + } + + /** + * Does a preference exist in this scope? + * + * @return boolean True if the preference exists. + */ + public function exists($pref) + { + return isset($this->_prefs[$pref]); + } + + /** + * Returns the value of a preference. + * + * @param string $pref The preference name to retrieve. + * + * @return string The value of the preference, null if it doesn't exist. + */ + public function get($pref) + { + return isset($this->_prefs[$pref]['v']) + ? $this->_prefs[$pref]['v'] + : null; + } + + /** + * Mark a preference as locked. + * + * @param string $pref The preference name. + * @param boolean $locked Is the preference locked? + */ + public function setLocked($pref, $locked) + { + if (isset($this->_prefs[$pref])) { + $ptr = &$this->_prefs[$pref]; + + if ($locked) { + if (!isset($ptr['l'])) { + $ptr['l'] = true; + if (!$this->init) { + $this->setDirty($pref, true); + } + } + } elseif (isset($ptr['l'])) { + unset($ptr['l']); + if (!$this->init) { + $this->setDirty($pref, true); + } + } + } + } + + /** + * Is a preference locked? + * + * @param string $pref The preference name. + * + * @return boolean Whether the preference is locked. + */ + public function isLocked($pref) + { + return !empty($this->_prefs[$pref]['l']); + } + + /** + * Is a preference's value the default? + * + * @param string $pref The preference name. + * + * @return boolean True if the preference contains the default value. + */ + public function isDefault($pref) + { + return !isset($this->_prefs[$pref]['d']); + } + + /** + * Returns the default value of a preference. + * + * @param string $pref The preference name. + * + * @return string The preference's default value. + */ + public function getDefault($pref) + { + if (!$this->isDefault($pref)) { + return $this->_prefs[$pref]['d']; + } + + return isset($this->_prefs[$pref]) + ? $this->_prefs[$pref]['v'] + : null; + } + + /** + * Get the list of dirty preferences. + * + * @return array The list of dirty preferences. + */ + public function getDirty() + { + return array_keys($this->_dirty); + } + + /** + * Is a preference marked dirty? + * + * @param mixed $pref The preference name. If null, will return true if + * scope contains at least one dirty pref. + * + * @return boolean True if the preference is marked dirty. + */ + public function isDirty($pref = null) + { + return is_null($pref) + ? !empty($this->_dirty) + : isset($this->_dirty[$pref]); + } + + /** + * Set the dirty flag for a preference + * + * @param string $pref The preference name. + * @param boolean $dirty True to mark the pref as dirty. + */ + public function setDirty($pref, $dirty) + { + if ($dirty) { + $this->_dirty[$pref] = true; + } else { + unset($this->_dirty[$pref]); + } + } + + /* Serializable methods. */ + + /** + */ + public function serialize() + { + return serialize(array( + $this->scope, + $this->_prefs + )); + } + + /** + */ + public function unserialize($data) + { + list($this->scope, $this->_prefs) = unserialize($data); + } + +} diff --git a/framework/Prefs/lib/Horde/Prefs/Storage.php b/framework/Prefs/lib/Horde/Prefs/Storage.php index a2c28bd4f..2f99ebdd7 100644 --- a/framework/Prefs/lib/Horde/Prefs/Storage.php +++ b/framework/Prefs/lib/Horde/Prefs/Storage.php @@ -37,28 +37,37 @@ abstract class Horde_Prefs_Storage /** * Retrieves the requested preferences scope from the storage backend. * - * @param string $scope Scope specifier. + * @param Horde_Prefs_Scope $scope_ob The scope object. * - * @return mixed Keys are pref names, values are pref values. Returns - * false if no data is available. - * @throws Horde_Db_Exception + * @return Horde_Prefs_Scope The modified scope object. + * @throws Horde_Prefs_Exception */ - abstract public function get($scope); + abstract public function get($scope_ob); /** - * Stores preferences in the storage backend. + * Stores changed preferences in the storage backend. * - * @param array $prefs The preference list. + * @param Horde_Prefs_Scope $scope_ob The scope object. * - * @throws Horde_Db_Exception + * @throws Horde_Prefs_Exception + */ + abstract public function store($scope_ob); + + /** + * Called whenever a preference value is changed. + * + * @param string $scope Scope specifier. + * @param string $pref The preference name. */ - abstract public function store($prefs); + public function onChange($scope, $pref) + { + } /** * Removes preferences from the backend. * * @param string $scope The scope of the prefs to clear. If null, clears - * entire cache. + * all scopes. * @param string $pref The pref to clear. If null, clears the entire * scope. * diff --git a/framework/Prefs/lib/Horde/Prefs/Storage/File.php b/framework/Prefs/lib/Horde/Prefs/Storage/File.php index e10a30fff..a94c82f09 100644 --- a/framework/Prefs/lib/Horde/Prefs/Storage/File.php +++ b/framework/Prefs/lib/Horde/Prefs/Storage/File.php @@ -59,18 +59,36 @@ class Horde_Prefs_Storage_File extends Horde_Prefs_Storage /** */ - public function get($scope) + public function get($scope_ob) { - if (!isset($this->_params['directory'])) { - return false; + if ($this->_loadFileCache() && + isset($this->_fileCache[$scope_ob->scope])) { + foreach ($this->_fileCache[$scope_ob->scope] as $name => $val) { + $scope_ob->set($name, $val); + } } + return $scope_ob; + } + + /** + * Load the preferences from the files. + * + * @return boolean True on success. + * @throws Horde_Prefs_Exception + */ + protected function _loadFileCache() + { if (is_null($this->_fileCache)) { // Try to read if (!file_exists($this->_fullpath)) { + $this->_fileCache = array( + '__file_version' => self::VERSION + ); return false; } - $this->_fileCache = unserialize(file_get_contents($this->_fullpath)); + + $this->_fileCache = @unserialize(file_get_contents($this->_fullpath)); // Check version number. We can call format transformations hooks // in the future. @@ -78,44 +96,29 @@ class Horde_Prefs_Storage_File extends Horde_Prefs_Storage !array_key_exists('__file_version', $this->_fileCache) || !($this->_fileCache['__file_version'] == self::VERSION)) { if ($this->_fileCache['__file_version'] == 1) { - $this->transformV1V2(); + $this->updateFileFormat(); } else { throw new Horde_Prefs_Exception(sprintf('Wrong version number found: %s (should be %d)', $this->_fileCache['__file_version'], self::VERSION)); } } } - // Check if the scope exists - if (empty($scope) || !isset($this->_fileCache[$scope])) { - return false; - } - - $ret = array(); - - foreach ($this->_fileCache[$scope] as $name => $val) { - $ret[$name] = $val; - } - - return $ret; + return true; } /** */ - public function store($prefs) + public function store($scope_ob) { - if (!isset($this->_params['directory'])) { - return; - } - - // Read in all existing preferences, if any. - $this->get(''); - if (!is_array($this->_fileCache)) { - $this->_fileCache = array('__file_version' => self::VERSION); - } - - foreach ($prefs as $scope => $p) { - foreach ($p as $name => $val) { - $this->_fileCache[$scope][$name] = $pref['v']; + $this->_loadFileCache(); + + /* Driver has no support for storing locked status. */ + foreach ($scope_ob->getDirty() as $name) { + $value = $scope_ob->get($name); + if (is_null($value)) { + unset($this->_fileCache[$scope_ob->scope][$name]); + } else { + $this->_fileCache[$scope_ob->scope][$name] = $value; } } @@ -137,20 +140,20 @@ class Horde_Prefs_Storage_File extends Horde_Prefs_Storage /* Helper functions. */ /** - * Transforms the broken version 1 format into version 2. + * Updates format of file. */ - public function transformV1V2() + public function updateFileFormat() { - $version2 = array('__file_version' => 2); + $new_vers = array('__file_version' => self::VERSION); + unset($this->_fileCache['__file_version']); + foreach ($this->_fileCache as $scope => $prefs) { - if ($scope != '__file_version') { - foreach ($prefs as $name => $pref) { - $version2[$scope][$name] = $pref['v']; - } + foreach ($prefs as $name => $pref) { + $new_vers[$scope][$name] = $pref['v']; } } - $this->_fileCache = $version2; + $this->_fileCache = $new_vers; } } diff --git a/framework/Prefs/lib/Horde/Prefs/Storage/Imsp.php b/framework/Prefs/lib/Horde/Prefs/Storage/Imsp.php index 805cff294..a64a2c98c 100644 --- a/framework/Prefs/lib/Horde/Prefs/Storage/Imsp.php +++ b/framework/Prefs/lib/Horde/Prefs/Storage/Imsp.php @@ -29,42 +29,37 @@ class Horde_Prefs_Storage_Imsp extends Horde_Prefs_Storage /** */ - public function get($scope) + public function get($scope_ob) { $this->_connect(); - $prefs = $this->_imsp->get($scope . '.*'); + $prefs = $this->_imsp->get($scope_ob->scope . '.*'); if ($prefs instanceof PEAR_Error) { throw new Horde_Prefs_Exception($prefs); } - $ret = array(); - foreach ($prefs as $name => $val) { - $name = str_replace($scope . '.', '', $name); + $name = str_replace($scope_ob->scope . '.', '', $name); if ($val != '-') { - $ret[$name] = $val; + $scope_ob->set($name, $val); } } + + return $scope_ob; } /** */ - public function store($prefs) + public function store($scope_ob) { $this->_connect(); - foreach ($prefs as $scope => $p) { - foreach ($p as $name => $pref) { - $value = $pref['v']; - if (empty($value)) { - $value = '-'; - } - - $result = $this->_imsp->set($scope . '.' . $name, $value); - if ($result instanceof PEAR_Error) { - throw new Horde_Prefs_Exception($result); - } + /* Driver has no support for storing locked status. */ + foreach ($scope_ob->getDirty() as $name) { + $value = $scope_ob->get($name); + $result = $this->_imsp->set($scope_ob->scope . '.' . $name, $value ? $value : '-'); + if ($result instanceof PEAR_Error) { + throw new Horde_Prefs_Exception($result); } } } diff --git a/framework/Prefs/lib/Horde/Prefs/Storage/KolabImap.php b/framework/Prefs/lib/Horde/Prefs/Storage/KolabImap.php index cac031eca..d33c2b92c 100644 --- a/framework/Prefs/lib/Horde/Prefs/Storage/KolabImap.php +++ b/framework/Prefs/lib/Horde/Prefs/Storage/KolabImap.php @@ -9,6 +9,7 @@ * * @author Gunnar Wrobel * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL * @package Prefs */ class Horde_Prefs_Storage_KolabImap extends Horde_Prefs_Storage @@ -29,32 +30,32 @@ class Horde_Prefs_Storage_KolabImap extends Horde_Prefs_Storage /** */ - public function get($scope) + public function get($scope_ob) { $this->_connect(); - $pref = $this->_getPref($scope); + $pref = $this->_getPref($scope_ob->scope); if (is_null($pref)) { /* No preferences saved yet. */ return false; } - $ret = array(); - foreach ($pref['pref'] as $prefstr) { // If the string doesn't contain a colon delimiter, skip it. if (strpos($prefstr, ':') !== false) { // Split the string into its name:value components. list($name, $val) = explode(':', $prefstr, 2); - $ret[$name] = base64_decode($val); + $pref_ob->set($name, base64_decode($val)); } } + + return $pref_ob; } /** */ - public function store($prefs) + public function store($scope_ob) { $this->_connect(); @@ -62,33 +63,33 @@ class Horde_Prefs_Storage_KolabImap extends Horde_Prefs_Storage // to be stored on the IMAP server. Because we have to update // all of the values of a multi-value entry wholesale, we // can't just pick out the dirty preferences; we must update - // every scope that has dirty preferences. - foreach ($prefs as $scope => $vals) { - $new_values = array(); - foreach ($vals as $name => $pref) { - $new_values[] = $name . ':' . base64_encode($pref['v']); - } + // the entire dirty scope. + $new_vals = array(); - $pref = $this->_getPref($scope); + /* Driver does not support storing locked status. */ + foreach ($scope_ob->getDirty() as $name) { + $new_vals[] = $name . ':' . base64_encode($scope_ob->get($name)); + } - if (is_null($pref)) { - $old_uid = null; - $prefs_uid = $this->_connection->_storage->generateUID(); - } else { - $old_uid = $pref['uid']; - $prefs_uid = $pref['uid']; - } + $pref = $this->_getPref($scope_ob->scope); + + if (is_null($pref)) { + $old_uid = null; + $prefs_uid = $this->_connection->_storage->generateUID(); + } else { + $old_uid = $pref['uid']; + $prefs_uid = $pref['uid']; + } - $object = array( - 'uid' => $prefs_uid, - 'application' => $scope, - 'pref' => $new_values - ); + $object = array( + 'application' => $scope_ob->scope, + 'pref' => $new_vals, + 'uid' => $prefs_uid + ); - $result = $this->_connection->_storage->save($object, $old_uid); - if ($result instanceof PEAR_Error) { - throw new Horde_Prefs_Exception($result); - } + $result = $this->_connection->_storage->save($object, $old_uid); + if ($result instanceof PEAR_Error) { + throw new Horde_Prefs_Exception($result); } } diff --git a/framework/Prefs/lib/Horde/Prefs/Storage/Ldap.php b/framework/Prefs/lib/Horde/Prefs/Storage/Ldap.php index 9dc0735ff..de154ff8e 100644 --- a/framework/Prefs/lib/Horde/Prefs/Storage/Ldap.php +++ b/framework/Prefs/lib/Horde/Prefs/Storage/Ldap.php @@ -74,15 +74,17 @@ class Horde_Prefs_Storage_Ldap extends Horde_Prefs_Storage /** */ - public function get($scope) + public function get($scope_ob) { $this->_connect(); // Search for the multi-valued field containing the array of // preferences. - $search = @ldap_search($this->_connection, $this->_params['basedn'], - $this->_params['uid'] . '=' . $this->params['user'], - array($scope . 'Prefs')); + $search = @ldap_search( + $this->_connection, + $this->_params['basedn'], + $this->_params['uid'] . '=' . $this->params['user'], + array($scope_ob->scope . 'Prefs')); if ($search === false) { throw new Horde_Prefs_Exception(sprintf('Error while searching for the user\'s prefs: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection))); } @@ -94,31 +96,29 @@ class Horde_Prefs_Storage_Ldap extends Horde_Prefs_Storage // Preferences are stored as colon-separated name:value pairs. // Each pair is stored as its own attribute off of the multi- - // value attribute named in: $scope . 'Prefs' + // value attribute named in: $scope_ob->scope . 'Prefs' // ldap_get_entries() converts attribute indexes to lowercase. - $field = Horde_String::lower($scope . 'prefs'); + $field = Horde_String::lower($scope_ob->scope . 'prefs'); $prefs = isset($result[0][$field]) ? $result[0][$field] : array(); - $ret = array(); - foreach ($prefs as $prefstr) { // If the string doesn't contain a colon delimiter, skip it. if (strpos($prefstr, ':') !== false) { // Split the string into its name:value components. list($name, $val) = explode(':', $prefstr, 2); - $ret[$name] = base64_decode($val); + $scope_ob->set($name, base64_decode($val)); } } - return $ret; + return $scope_ob; } /** */ - public function store($prefs) + public function store($scope_ob) { $this->_connect(); @@ -126,20 +126,23 @@ class Horde_Prefs_Storage_Ldap extends Horde_Prefs_Storage // to be stored on the LDAP server. Because we have to update // all of the values of a multi-value entry wholesale, we // can't just pick out the dirty preferences; we must update - // every scope that has dirty preferences. - $new_values = array(); - foreach ($prefs as $scope => $vals) { - foreach ($vals as $name => $pref) { - $new_values[$scope . 'Prefs'][] = $name . ':' . base64_encode($pref['v']); - } + // the entire dirty scope. + $new_vals = array(); + + /* Driver has no support for storing locked status. */ + foreach ($scope_ob->getDirty() as $name) { + $new_vals[$scope_ob->scope . 'Prefs'][] = $name . ':' . base64_encode($scope_ob->get($name)); } // Entries must have the objectclasses 'top' and 'hordeperson' // to successfully store LDAP prefs. Check for both of them, // and add them if necessary. - $search = @ldap_search($this->_connection, $this->_params['basedn'], - $this->_params['uid'] . '=' . $this->prefs['user'], - array('objectclass')); + $search = @ldap_search( + $this->_connection, + $this->_params['basedn'], + $this->_params['uid'] . '=' . $this->prefs['user'], + array('objectclass') + ); if ($search === false) { throw new Horde_Prefs_Exception(sprintf('Error searching the directory for required objectClasses: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection))); } @@ -150,10 +153,9 @@ class Horde_Prefs_Storage_Ldap extends Horde_Prefs_Storage } if ($result['count'] > 0) { - $top = false; - $hordeperson = false; + $hordeperson = $top = false; - for ($i = 0; $i < $result[0]['objectclass']['count']; $i++) { + for ($i = 0; $i < $result[0]['objectclass']['count']; ++$i) { if ($result[0]['objectclass'][$i] == 'top') { $top = true; } elseif ($result[0]['objectclass'][$i] == 'hordePerson') { @@ -172,8 +174,7 @@ class Horde_Prefs_Storage_Ldap extends Horde_Prefs_Storage } // Send the hash to the LDAP server. - $result = @ldap_mod_replace($this->_connection, $this->_dn, - $new_values); + $result = @ldap_mod_replace($this->_connection, $this->_dn, $new_vals); if ($result === false) { throw new Horde_Prefs_Exception(sprintf('Unable to modify user\'s objectClass for preferences: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection))); } diff --git a/framework/Prefs/lib/Horde/Prefs/Storage/Null.php b/framework/Prefs/lib/Horde/Prefs/Storage/Null.php index b082fded2..de833f9f4 100644 --- a/framework/Prefs/lib/Horde/Prefs/Storage/Null.php +++ b/framework/Prefs/lib/Horde/Prefs/Storage/Null.php @@ -16,14 +16,14 @@ class Horde_Prefs_Storage_Null extends Horde_Prefs_Storage { /** */ - public function get($scope) + public function get($scope_ob) { - return false; + return $scope_ob; } /** */ - public function store($prefs) + public function store($scope_ob) { } diff --git a/framework/Prefs/lib/Horde/Prefs/Storage/Session.php b/framework/Prefs/lib/Horde/Prefs/Storage/Session.php deleted file mode 100644 index 265320e73..000000000 --- a/framework/Prefs/lib/Horde/Prefs/Storage/Session.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @category Horde - * @license http://www.fsf.org/copyleft/lgpl.html LGPL - * @package Prefs - */ -class Horde_Prefs_Storage_Session extends Horde_Prefs_Storage -{ - /** - * Session key. - * - * @var string - */ - protected $_key; - - /** - */ - public function __construct($user, array $params = array()) - { - parent::__construct($user, $params); - - $this->_key = 'horde_prefs_' . $this->_params['user']; - } - - /** - */ - public function get($scope) - { - return isset($_SESSION[$this->_key][$scope]) - ? $_SESSION[$this->_key][$scope] - : false; - } - - /** - */ - public function store($prefs) - { - foreach ($prefs as $scope => $vals) { - $_SESSION[$this->_key][$scope] = isset($_SESSION[$this->_key][$scope]) - ? array_merge($_SESSION[$this->_key][$scope], $vals) - : array(); - } - } - - /** - */ - public function remove($scope = null, $pref = null) - { - if (is_null($scope)) { - unset($_SESSION[$this->_key]); - } elseif (is_null($pref)) { - unset($_SESSION[$this->_key][$scope]); - } else { - unset($_SESSION[$this->_key][$scope][$pref]); - } - } - -} diff --git a/framework/Prefs/lib/Horde/Prefs/Storage/Sql.php b/framework/Prefs/lib/Horde/Prefs/Storage/Sql.php index fdca35dd3..9c5f33833 100644 --- a/framework/Prefs/lib/Horde/Prefs/Storage/Sql.php +++ b/framework/Prefs/lib/Horde/Prefs/Storage/Sql.php @@ -52,12 +52,13 @@ class Horde_Prefs_Storage_Sql extends Horde_Prefs_Storage /** */ - public function get($scope) + public function get($scope_ob) { + $charset = $this->_db->getOption('charset'); $query = 'SELECT pref_scope, pref_name, pref_value FROM ' . $this->_params['table'] . ' ' . 'WHERE pref_uid = ? AND pref_scope = ?'; - $values = array($this->_params['user'], $scope); + $values = array($this->_params['user'], $scope_ob->scope); try { $result = $this->_db->selectAll($query, $values); @@ -65,8 +66,6 @@ class Horde_Prefs_Storage_Sql extends Horde_Prefs_Storage throw Horde_Prefs_Exception($e); } - $ret = array(); - foreach ($result as $row) { $name = trim($row['pref_name']); @@ -82,33 +81,48 @@ class Horde_Prefs_Storage_Sql extends Horde_Prefs_Storage break; } - $ret[$name] = $row['pref_value']; + $scope_ob->set($name, Horde_String::convertCharset($row['pref_value'], $charset, 'UTF-8')); } - return $ret; + return $scope_ob; } /** */ - public function store($prefs) + public function store($scope_ob) { + $charset = $this->_db->getOption('charset'); + // For each preference, check for an existing table row and // update it if it's there, or create a new one if it's not. - foreach ($prefs as $scope => $p) { - foreach ($p as $name => $pref) { + foreach ($scope_ob->getDirty() as $name) { + $value = $scope_ob->get($name); + $values = array($this->_params['user'], $name, $scope_ob->scope); + + if (is_null($value)) { + $query = 'DELETE FROM ' . $this->_params['table'] . + ' WHERE pref_uid = ? AND pref_name = ?' . + ' AND pref_scope = ?'; + + try { + $this->_db->delete($query, $values); + } catch (Horde_Db_Exception $e) { + throw new Horde_Prefs_Exception($e); + } + } else { // Does a row already exist for this preference? $query = 'SELECT 1 FROM ' . $this->_params['table'] . ' WHERE pref_uid = ? AND pref_name = ?' . ' AND pref_scope = ?'; - $values = array($this->_params['user'], $name, $scope); try { $check = $this->_db->selectValue($query, $values); } catch (Horde_Db_Exception $e) { - throw Horde_Prefs_Exception($e); + throw new Horde_Prefs_Exception($e); } - $value = strval(isset($pref['v']) ? $pref['v'] : null); + /* Driver has no support for storing locked status. */ + $value = Horde_String::convertCharset($value, 'UTF-8', $charset); switch ($this->_db->adapterName()) { case 'PDO_PostgreSQL': @@ -124,7 +138,7 @@ class Horde_Prefs_Storage_Sql extends Horde_Prefs_Storage '(?, ?, ?, ?)'; $values = array( $this->_params['user'], - $scope, + $scope_ob->scope, $name, $value ); @@ -145,7 +159,7 @@ class Horde_Prefs_Storage_Sql extends Horde_Prefs_Storage $value, $this->_params['user'], $name, - $scope + $scope_ob->scope ); try { diff --git a/framework/Prefs/package.xml b/framework/Prefs/package.xml index d0330ee77..3f7898b5a 100644 --- a/framework/Prefs/package.xml +++ b/framework/Prefs/package.xml @@ -21,7 +21,8 @@ beta LGPL - * Removed Horde_Prefs_Storage_Kolab driver. + * Abstract caching code into Horde_Prefs_Cache. + * Removed Horde_Prefs_Storage_Kolab driver. * Abstract storage code into Horde_Prefs_Storage. * Add array access API to Horde_Prefs. * Remove dependency on horde/Core. @@ -34,18 +35,23 @@ + + + + - + + @@ -352,17 +358,20 @@ + + + + - diff --git a/hermes/entry.php b/hermes/entry.php index 061bc8c96..0c4fb2c1d 100644 --- a/hermes/entry.php +++ b/hermes/entry.php @@ -17,9 +17,9 @@ $vars = Horde_Variables::getDefaultVariables(); if (!$vars->exists('id') && $vars->exists('timer')) { $timer_id = $vars->get('timer'); - $timers = @unserialize($prefs->getValue('running_timers', false)); + $timers = @unserialize($prefs->getValue('running_timers')); if ($timers && isset($timers[$timer_id])) { - $tname = Horde_String::convertCharset($timers[$timer_id]['name'], $prefs->getCharset(), 'UTF-8'); + $tname = $timers[$timer_id]['name']; $tformat = $prefs->getValue('twentyFour') ? 'G:i' : 'g:i a'; $vars->set('hours', round((float)(time() - $timer_id) / 3600, 2)); if ($prefs->getValue('add_description')) { @@ -27,7 +27,7 @@ if (!$vars->exists('id') && $vars->exists('timer')) { } $notification->push(sprintf(_("The stop watch \"%s\" has been stopped."), $tname), 'horde.success'); unset($timers[$timer_id]); - $prefs->setValue('running_timers', serialize($timers), false); + $prefs->setValue('running_timers', serialize($timers)); } } diff --git a/hermes/lib/Application.php b/hermes/lib/Application.php index b01cf4e35..3a0961101 100644 --- a/hermes/lib/Application.php +++ b/hermes/lib/Application.php @@ -138,13 +138,13 @@ class Hermes_Application extends Horde_Registry_Application ) ); - if ($timers = @unserialize($GLOBALS['prefs']->getValue('running_timers', false))) { + if ($timers = @unserialize($GLOBALS['prefs']->getValue('running_timers'))) { foreach ($timers as $i => $timer) { $hours = round((float)(time() - $i) / 3600, 2); $tree->addNode( $parent . '__timer_' . $i, $parent, - Horde_String::convertCharset($timer['name'], $prefs->getCharset(), 'UTF-8') . sprintf(" (%s)", $hours), + $timer['name'] . sprintf(" (%s)", $hours), 1, false, array( diff --git a/hermes/start.php b/hermes/start.php index fb3425578..e06841627 100644 --- a/hermes/start.php +++ b/hermes/start.php @@ -18,7 +18,7 @@ $form = new Horde_Form($vars, _("Stop Watch")); $form->addVariable(_("Stop watch description"), 'description', 'text', true); if ($form->validate($vars)) { - $timers = $prefs->getValue('running_timers', false); + $timers = $prefs->getValue('running_timers'); if (empty($timers)) { $timers = array(); } else { @@ -28,11 +28,9 @@ if ($form->validate($vars)) { } } $now = time(); - $timers[$now] = array('name' => Horde_String::convertCharset($vars->get('description'), - 'UTF-8', - $prefs->getCharset()), + $timers[$now] = array('name' => $vars->get('description'), 'time' => $now); - $prefs->setValue('running_timers', serialize($timers), false); + $prefs->setValue('running_timers', serialize($timers)); echo Horde::wrapInlineScript(array( 'alert(\'' . addslashes(sprintf(_("The stop watch \"%s\" has been started and will appear in the sidebar at the next refresh."), $vars->get('description'))), diff --git a/horde/config/hooks.php.dist b/horde/config/hooks.php.dist index 34db3d1c4..09f29a7bf 100644 --- a/horde/config/hooks.php.dist +++ b/horde/config/hooks.php.dist @@ -28,24 +28,14 @@ * * Setting value * ------------- - * If - * 'hook' => true - * exists for a preference (config/prefs.php), the prefs_init hook will be run - * on login to allow alteration of the default value. This hook receives the - * preference name and the username as parameters and uses the return value - * from the hook as the new preference value. + * If the 'hook' parameter is non-empty for a preference (config/prefs.php), + * the prefs_init hook will be run on login to allow alteration of the value. + * This hook receives the preference name and the username as parameters and + * uses the return value from the hook as the new preference value. * * This hook is ONLY executed on login and preferences are cached during a * users' session. * - * Any preference that is NOT LOCKED, that is set by a hook, WILL BE SAVED - * WITH THAT VALUE. This means: - * 1) Users will get the results of the hook set for them in their - * preferences. - * 2) The next time they login and load their preferences, the hook will NOT - * be called. However, if the preference is locked, the result of the hook - * will never be saved. - * * Authentication/Login Hooks * ========================== * There are three special hooks called during the initial authentication diff --git a/horde/config/prefs.php.dist b/horde/config/prefs.php.dist index e5ec93776..634f9e005 100644 --- a/horde/config/prefs.php.dist +++ b/horde/config/prefs.php.dist @@ -46,13 +46,6 @@ * false: Basic preference; shown regardless of preferences mode. * DEFAULT: false * - * locked - (boolean) Allow preference to be changed from the preferences screen? - * VALUES: - * true: Do not show this preference in the UI and don't allow - * changing by any mechanism. - * false: Show this preference in the UI and allow changing. - * DEFAULT: false - * * help - (string) The help file identifier for this preference. * VALUES: * If present, a help icon will be displayed next to the preference. @@ -60,6 +53,18 @@ * a popup window. * DEFAULT: No help icon is displayed * + * hook - (boolean) If true, the prefs_init hook will be run for this entry. + * VALUES: true/false + * DEFAULT: false + * + * locked - (boolean) Allow preference to be changed from the preferences + * screen? + * VALUES: + * true: Do not show this preference in the UI and don't allow + * changing by any mechanism. + * false: Show this preference in the UI and allow changing. + * DEFAULT: false + * * The UI display for a preference is controlled by the 'type' key. This key * controls how the preference is displayed on the preferences screen. If this * key is not present, the preference is treated as type 'implict'. The diff --git a/horde/lib/LoginTasks/SystemTask/UpgradeFromHorde3.php b/horde/lib/LoginTasks/SystemTask/UpgradeFromHorde3.php deleted file mode 100644 index 9e02e2ae7..000000000 --- a/horde/lib/LoginTasks/SystemTask/UpgradeFromHorde3.php +++ /dev/null @@ -1,47 +0,0 @@ - - * @package Horde - */ -class Horde_LoginTasks_SystemTask_UpgradeFromHorde3 extends Horde_LoginTasks_SystemTask -{ - /** - * The interval at which to run the task. - * - * @var integer - */ - public $interval = Horde_LoginTasks::ONCE; - - /** - * Perform all functions for this task. - */ - public function execute() - { - $this->_upgradeIdentityPrefs(); - } - - /** - * Upgrade to the new identity preferences. - */ - protected function _upgradeIdentityPrefs() - { - global $prefs; - - if (!$prefs->isDefault('identities') && - (!($this->_identities = @unserialize($prefs->getValue('identities', false))))) { - $identities = @unserialize($prefs->getValue('identities')); - if (!is_array($identities)) { - $identities = $prefs->getDefault('identities'); - } - $prefs->setValue('identities', serialize($identities), false); - } - } - -} diff --git a/imp/lib/Compose/Stationery.php b/imp/lib/Compose/Stationery.php index 4dc3d51a9..08c3dd679 100644 --- a/imp/lib/Compose/Stationery.php +++ b/imp/lib/Compose/Stationery.php @@ -32,9 +32,9 @@ class IMP_Compose_Stationery implements ArrayAccess, Countable, Iterator */ public function __construct() { - $slist = @unserialize($GLOBALS['prefs']->getValue('stationery', false)); + $slist = @unserialize($GLOBALS['prefs']->getValue('stationery')); $this->_stationery = is_array($slist) - ? Horde_String::convertCharset($slist, $GLOBALS['prefs']->getCharset(), 'UTF-8') + ? $slist : array(); } @@ -84,7 +84,7 @@ class IMP_Compose_Stationery implements ArrayAccess, Countable, Iterator */ protected function _save() { - $GLOBALS['prefs']->setValue('stationery', serialize(Horde_String::convertCharset($this->_stationery, 'UTF-8', $GLOBALS['prefs']->getCharset())), false); + $GLOBALS['prefs']->setValue('stationery', serialize($this->_stationery)); } /* ArrayAccess methods. */ diff --git a/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php b/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php index e79da1a01..f16c7d375 100644 --- a/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php +++ b/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php @@ -98,7 +98,6 @@ class IMP_LoginTasks_SystemTask_UpgradeFromImp4 extends Horde_LoginTasks_SystemT default: $prefs->setValue('forward_default', 'attach'); - $prefs->setDefault('forward_default', true); break; } } diff --git a/ingo/lib/Storage/Prefs.php b/ingo/lib/Storage/Prefs.php index 729b54f09..64448b028 100644 --- a/ingo/lib/Storage/Prefs.php +++ b/ingo/lib/Storage/Prefs.php @@ -42,8 +42,7 @@ class Ingo_Storage_Prefs extends Ingo_Storage switch ($field) { case self::ACTION_BLACKLIST: $ob = new Ingo_Storage_Blacklist(); - $data = @unserialize($prefs->getValue('blacklist')); - if ($data) { + if ($data = @unserialize($prefs->getValue('blacklist'))) { $ob->setBlacklist($data['a'], false); $ob->setBlacklistFolder($data['f']); } @@ -51,30 +50,21 @@ class Ingo_Storage_Prefs extends Ingo_Storage case self::ACTION_WHITELIST: $ob = new Ingo_Storage_Whitelist(); - $data = @unserialize($prefs->getValue('whitelist')); - if ($data) { + if ($data = @unserialize($prefs->getValue('whitelist'))) { $ob->setWhitelist($data, false); } break; case self::ACTION_FILTERS: $ob = new Ingo_Storage_Filters(); - $data = @unserialize($prefs->getValue('rules', false)); - if ($data === false) { - /* Convert rules from the old format. */ - $data = @unserialize($prefs->getValue('rules')); - } else { - $data = Horde_String::convertCharset($data, $prefs->getCharset(), 'UTF-8'); - } - if ($data) { + if ($data = @unserialize($prefs->getValue('rules'))) { $ob->setFilterlist($data); } break; case self::ACTION_FORWARD: $ob = new Ingo_Storage_Forward(); - $data = @unserialize($prefs->getValue('forward')); - if ($data) { + if ($data = @unserialize($prefs->getValue('forward'))) { $ob->setForwardAddresses($data['a'], false); $ob->setForwardKeep($data['k']); } @@ -82,14 +72,7 @@ class Ingo_Storage_Prefs extends Ingo_Storage case self::ACTION_VACATION: $ob = new Ingo_Storage_Vacation(); - $data = @unserialize($prefs->getValue('vacation', false)); - if ($data === false) { - /* Convert vacation from the old format. */ - $data = unserialize($prefs->getValue('vacation')); - } elseif (is_array($data)) { - $data = $prefs->convertFromDriver($data); - } - if ($data) { + if ($data = @unserialize($prefs->getValue('vacation'))) { $ob->setVacationAddresses($data['addresses'], false); $ob->setVacationDays($data['days']); $ob->setVacationExcludes($data['excludes'], false); @@ -107,8 +90,7 @@ class Ingo_Storage_Prefs extends Ingo_Storage case self::ACTION_SPAM: $ob = new Ingo_Storage_Spam(); - $data = @unserialize($prefs->getValue('spam')); - if ($data) { + if ($data = @unserialize($prefs->getValue('spam'))) { $ob->setSpamFolder($data['folder']); $ob->setSpamLevel($data['level']); } @@ -145,7 +127,7 @@ class Ingo_Storage_Prefs extends Ingo_Storage return $prefs->setValue('blacklist', serialize($data)); case self::ACTION_FILTERS: - return $prefs->setValue('rules', serialize(Horde_String::convertCharset($ob->getFilterList(), 'UTF-8', $prefs->getCharset())), false); + return $prefs->setValue('rules', serialize($ob->getFilterList())); case self::ACTION_FORWARD: $data = array( @@ -165,7 +147,7 @@ class Ingo_Storage_Prefs extends Ingo_Storage 'start' => $ob->getVacationStart(), 'end' => $ob->getVacationEnd(), ); - return $prefs->setValue('vacation', serialize($prefs->convertToDriver($data)), false); + return $prefs->setValue('vacation', serialize($data)); case self::ACTION_WHITELIST: return $prefs->setValue('whitelist', serialize($ob->getWhitelist()));