Overview

Packages

  • Prefs

Classes

  • Horde_Prefs
  • Horde_Prefs_Cache_Base
  • Horde_Prefs_Cache_Null
  • Horde_Prefs_Cache_Session
  • Horde_Prefs_CategoryManager
  • Horde_Prefs_Exception
  • Horde_Prefs_Identity
  • Horde_Prefs_Scope
  • Horde_Prefs_Storage_Base
  • Horde_Prefs_Storage_File
  • Horde_Prefs_Storage_Imsp
  • Horde_Prefs_Storage_KolabImap
  • Horde_Prefs_Storage_Ldap
  • Horde_Prefs_Storage_Null
  • Horde_Prefs_Storage_Sql
  • Horde_Prefs_Translation
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Horde_Prefs:: class provides a common abstracted interface into the
  4:  * various preferences storage mediums.  It also includes all of the
  5:  * functions for retrieving, storing, and checking preference values.
  6:  *
  7:  * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
  8:  *
  9:  * See the enclosed file COPYING for license information (LGPL). If you
 10:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 11:  *
 12:  * @author   Jon Parise <jon@horde.org>
 13:  * @category Horde
 14:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 15:  * @package  Prefs
 16:  */
 17: class Horde_Prefs implements ArrayAccess
 18: {
 19:     /* The default scope name. */
 20:     const DEFAULT_SCOPE = 'horde';
 21: 
 22:     /**
 23:      * Caching object.
 24:      *
 25:      * @var Horde_Prefs_Cache
 26:      */
 27:     protected $_cache;
 28: 
 29:     /**
 30:      * General library options.
 31:      *
 32:      * @var array
 33:      */
 34:     protected $_opts = array(
 35:         'cache' => null,
 36:         'logger' => null,
 37:         'password' => '',
 38:         'sizecallback' => null,
 39:         'storage' => null,
 40:         'user' => ''
 41:     );
 42: 
 43:     /**
 44:      * String containing the name of the current scope. This is used
 45:      * to differentiate between sets of preferences. By default, preferences
 46:      * belong to this scope.
 47:      *
 48:      * @var string
 49:      */
 50:     protected $_scope = self::DEFAULT_SCOPE;
 51: 
 52:     /**
 53:      * Scope list.  Keys are scope names, values are Horde_Prefs_Scope
 54:      * objects.
 55:      *
 56:      * @var array
 57:      */
 58:     protected $_scopes = array();
 59: 
 60:     /**
 61:      * The storage driver(s).
 62:      *
 63:      * @var array
 64:      */
 65:     protected $_storage;
 66: 
 67:     /**
 68:      * Constructor.
 69:      *
 70:      * @param string $scope   The scope for this set of preferences.
 71:      * @param mixed $storage  The storage object(s) to use. Either a single
 72:      *                        Horde_Prefs_Storage object, or an array of
 73:      *                        objects.
 74:      * @param array $opts     Additional confguration options:
 75:      * <pre>
 76:      * cache - (Horde_Prefs_Cache) The cache driver to use.
 77:      *         DEFAULT: No caching.
 78:      * logger - (Horde_Log_Logger) Logging object.
 79:      *          DEFAULT: NONE
 80:      * password - (string) The password associated with 'user'.
 81:      *            DEFAULT: NONE
 82:      * sizecallback - (callback) If set, called when setting a value in the
 83:      *                backend.
 84:      *                DEFAULT: NONE
 85:      * user - (string) The name of the user who owns this set of preferences.
 86:      *        DEFAULT: NONE
 87:      * </pre>
 88:      */
 89:     public function __construct($scope, $storage = null, array $opts = array())
 90:     {
 91:         $this->_opts = array_merge($this->_opts, $opts);
 92: 
 93:         $this->_cache = isset($this->_opts['cache'])
 94:             ? $this->_opts['cache']
 95:             : new Horde_Prefs_Cache_Null($this->getUser());
 96: 
 97:         $this->_scope = $scope;
 98: 
 99:         if (is_null($storage)) {
100:             $storage = array(new Horde_Prefs_Storage_Null($this->getUser()));
101:         } elseif (!is_array($storage)) {
102:             $storage = array($storage);
103:         }
104:         $this->_storage = $storage;
105: 
106:         register_shutdown_function(array($this, 'store'));
107: 
108:         $this->retrieve($scope);
109:     }
110: 
111:     /**
112:      * Return the user who owns these preferences.
113:      *
114:      * @return string  The user these preferences are for.
115:      */
116:     public function getUser()
117:     {
118:         return $this->_opts['user'];
119:     }
120: 
121:     /**
122:      * Get the current scope.
123:      *
124:      * @return string  The current scope (application).
125:      */
126:     public function getScope()
127:     {
128:         return $this->_scope;
129:     }
130: 
131:     /**
132:      * Returns the storage drivers.
133:      *
134:      * @return array  The storage drivers.
135:      */
136:     public function getStorage()
137:     {
138:         return $this->_storage;
139:     }
140: 
141:     /**
142:      * Removes a preference entry from the $prefs hash.
143:      *
144:      * @param string $pref  The name of the preference to remove.  If null,
145:      *                      removes all prefs.
146:      */
147:     public function remove($pref = null)
148:     {
149:         if (is_null($pref)) {
150:             foreach ($this->_scopes as $val) {
151:                 foreach (array_keys(iterator_to_array($val)) as $prefname) {
152:                     $val->remove($prefname);
153:                 }
154:             }
155:         } elseif ($scope = $this->_getScope($pref)) {
156:             $this->_scopes[$scope]->remove($pref);
157:         }
158:     }
159: 
160:     /**
161:      * Sets the given preference to the specified value if the preference is
162:      * modifiable.
163:      *
164:      * @param string $pref  The preference name to modify.
165:      * @param string $val   The preference value (UTF-8).
166:      * @param array $opts   Additional options:
167:      * <pre>
168:      * nosave - (boolean) If true, the preference will not be saved to the
169:      *          storage backend(s).
170:      * </pre>
171:      *
172:      * @return boolean  True if the value was successfully set, false on a
173:      *                  failure.
174:      * @throws Horde_Prefs_Exception
175:      */
176:     public function setValue($pref, $val, array $opts = array())
177:     {
178:         /* Exit early if preference doesn't exist or is locked. */
179:         if (!($scope = $this->_getScope($pref)) ||
180:             $this->_scopes[$scope]->isLocked($pref)) {
181:             return false;
182:         }
183: 
184:         // Check to see if the value exceeds the allowable storage limit.
185:         if ($this->_opts['sizecallback'] &&
186:             call_user_func($this->_opts['sizecallback'], $pref, strlen($val))) {
187:             return false;
188:         }
189: 
190:         $this->_scopes[$scope]->set($pref, $val);
191:         if (!empty($opts['nosave'])) {
192:             $this->_scopes[$scope]->setDirty($pref, false);
193:         }
194: 
195:         foreach ($this->_storage as $storage) {
196:             $storage->onChange($scope, $pref);
197:         }
198: 
199:         if ($this->_opts['logger']) {
200:             $this->_opts['logger']->log(__CLASS__ . ': Storing preference value (' . $pref . ')', 'DEBUG');
201:         }
202: 
203:         return true;
204:     }
205: 
206:     /**
207:      * Shortcut to setValue().
208:      */
209:     public function __set($name, $value)
210:     {
211:         return $this->setValue($name, $value);
212:     }
213: 
214:     /**
215:      * Returns the value of the requested preference.
216:      *
217:      * @param string $pref  The preference name.
218:      *
219:      * @return string  The value of the preference (UTF-8), null if it doesn't
220:      *                 exist.
221:      */
222:     public function getValue($pref)
223:     {
224:         return ($scope = $this->_getScope($pref))
225:             ? $this->_scopes[$scope]->get($pref)
226:             : null;
227:     }
228: 
229:     /**
230:      * Shortcut to getValue().
231:      */
232:     public function __get($name)
233:     {
234:         return $this->getValue($name);
235:     }
236: 
237:     /**
238:      * Mark a preference as locked.
239:      *
240:      * @param string $pref     The preference name.
241:      * @param boolean $locked  Is the preference locked?
242:      */
243:     public function setLocked($pref, $bool)
244:     {
245:         if ($scope = $this->_getScope($pref)) {
246:             $this->_scopes[$scope]->setLocked($pref, $bool);
247:         }
248:     }
249: 
250:     /**
251:      * Is a preference locked?
252:      *
253:      * @param string $pref  The preference name.
254:      *
255:      * @return boolean  Whether the preference is locked.
256:      */
257:     public function isLocked($pref)
258:     {
259:         return ($scope = $this->_getScope($pref))
260:             ? $this->_scopes[$scope]->isLocked($pref)
261:             : false;
262:     }
263: 
264:     /**
265:      * Is a preference marked dirty?
266:      *
267:      * @param string $pref  The preference name.
268:      *
269:      * @return boolean  True if the preference is marked dirty.
270:      */
271:     public function isDirty($pref)
272:     {
273:         return ($scope = $this->_getScope($pref))
274:             ? $this->_scopes[$scope]->isDirty($pref)
275:             : false;
276:     }
277: 
278:     /**
279:      * Returns the default value of the given preference.
280:      *
281:      * @param string $pref  The name of the preference to get the default for.
282:      *
283:      * @return string  The preference's default value.
284:      */
285:     public function getDefault($pref)
286:     {
287:         return ($scope = $this->_getScope($pref))
288:             ? $this->_scopes[$scope]->getDefault($pref)
289:             : null;
290:     }
291: 
292:     /**
293:      * Determines if the current preference value is the default value.
294:      *
295:      * @param string $pref  The name of the preference to check.
296:      *
297:      * @return boolean  True if the preference is the application default
298:      *                  value.
299:      */
300:     public function isDefault($pref)
301:     {
302:         return ($scope = $this->_getScope($pref))
303:             ? $this->_scopes[$scope]->isDefault($pref)
304:             : false;
305:     }
306: 
307:     /**
308:      * Returns the scope of a preference.
309:      *
310:      * @param string $pref  The preference name.
311:      *
312:      * @return mixed  The scope of the preference, or null if it doesn't
313:      *                exist.
314:      */
315:     protected function _getScope($pref)
316:     {
317:         if ($this->_scopes[$this->_scope]->exists($pref)) {
318:             return $this->_scope;
319:         } elseif (($this->_scope != self::DEFAULT_SCOPE) &&
320:             ($this->_scopes[self::DEFAULT_SCOPE]->exists($pref))) {
321:             return self::DEFAULT_SCOPE;
322:         }
323: 
324:         return null;
325:     }
326: 
327:     /**
328:      * Retrieves preferences for the current scope.
329:      *
330:      * @param string $scope  Optional scope specifier - if not present the
331:      *                       current scope will be used.
332:      */
333:     public function retrieve($scope = null)
334:     {
335:         if (is_null($scope)) {
336:             $scope = $this->getScope();
337:         } else {
338:             $this->_scope = $scope;
339:         }
340: 
341:         $this->_loadScope(self::DEFAULT_SCOPE);
342:         if ($scope != self::DEFAULT_SCOPE) {
343:             $this->_loadScope($scope);
344:         }
345:     }
346: 
347:     /**
348:      * Load a specific preference scope.
349:      *
350:      * @param string $scope  The scope to load.
351:      */
352:     protected function _loadScope($scope)
353:     {
354:         // Return if we've already loaded these prefs.
355:         if (!empty($this->_scopes[$scope])) {
356:             return;
357:         }
358: 
359:         // Now check the prefs cache for existing values.
360:         try {
361:             if ((($cached = $this->_cache->get($scope)) !== false) &&
362:                 ($cached instanceof Horde_Prefs_Scope)) {
363:                 $this->_scopes[$scope] = $cached;
364:                 return;
365:             }
366:         } catch (Horde_Prefs_Exception $e) {}
367: 
368:         $scope_ob = new Horde_Prefs_Scope($scope);
369:         $scope_ob->init = true;
370: 
371:         // Need to set object in scopes array now, since the storage object
372:         // might recursively call the prefs object.
373:         $this->_scopes[$scope] = $scope_ob;
374: 
375:         foreach ($this->_storage as $storage) {
376:             $scope_ob = $storage->get($scope_ob);
377:         }
378: 
379:         $scope_ob->init = false;
380: 
381:         $this->_cache->store($scope_ob);
382:     }
383: 
384:     /**
385:      * This function will be run at the end of every request as a shutdown
386:      * function (registered by the constructor).  All dirty prefs will be
387:      * saved to the storage backend.
388:      */
389:     public function store()
390:     {
391:         $backtrace = new Horde_Support_Backtrace();
392:         $from_shutdown = $backtrace->getNestingLevel() == 1;
393:         foreach ($this->_scopes as $scope) {
394:             if ($scope->isDirty()) {
395:                 foreach ($this->_storage as $storage) {
396:                     try {
397:                         $storage->store($scope);
398:                     } catch (Exception $e) {
399:                         if (!$from_shutdown) {
400:                             throw $e;
401:                         }
402:                     }
403:                 }
404: 
405:                 try {
406:                     $this->_cache->store($scope);
407:                 } catch (Exception $e) {
408:                     if (!$from_shutdown) {
409:                         throw $e;
410:                     }
411:                 }
412:             }
413:         }
414:     }
415: 
416:     /**
417:      * Cleanup (e.g. remove) scope(s).
418:      *
419:      * @param boolean $all  Cleanup all scopes. If false, clean present scope
420:      *                      only.
421:      */
422:     public function cleanup($all = false)
423:     {
424:         if ($all) {
425:             /* Destroy all scopes. */
426:             $this->_scopes = array();
427:             $scope = null;
428:         } else {
429:             unset($this->_scopes[$this->_scope]);
430:             $scope = $this->_scope;
431:         }
432: 
433:         try {
434:             $this->_cache->remove($scope);
435:         } catch (Horde_Prefs_Exception $e) {}
436:     }
437: 
438:     /* ArrayAccess methods. */
439: 
440:     public function offsetExists($offset)
441:     {
442:         return !is_null($this->getValue($offset));
443:     }
444: 
445:     public function offsetGet($offset)
446:     {
447:         return $this->getValue($offset);
448:     }
449: 
450:     public function offsetSet($offset, $value)
451:     {
452:         $this->setValue($offset, $value);
453:     }
454: 
455:     public function offsetUnset($offset)
456:     {
457:         $this->remove($offset);
458:     }
459: 
460: }
461: 
API documentation generated by ApiGen