1<?php 2/** 3 * Copyright 2010-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file COPYING for license information (LGPL). If you 6 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 7 * 8 * @author Michael Slusarz <slusarz@horde.org> 9 * @category Horde 10 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 11 * @package Prefs 12 */ 13 14/** 15 * This class provides the storage for a preference scope. 16 * 17 * @author Michael Slusarz <slusarz@horde.org> 18 * @category Horde 19 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 20 * @package Prefs 21 */ 22class Horde_Prefs_Scope implements Iterator, Serializable 23{ 24 /** 25 * Is the object being initialized? 26 * 27 * @var boolean 28 */ 29 public $init = false; 30 31 /** 32 * The scope name. 33 * 34 * @var string 35 */ 36 public $scope; 37 38 /** 39 * List of dirty prefs. 40 * 41 * @var array 42 */ 43 protected $_dirty = array(); 44 45 /** 46 * Preferences list. Each preference has the following format: 47 * <pre> 48 * [pref_name] => array( 49 * [d] => (string) Default value 50 * If not present, 'v' is the default value. 51 * [l] => (boolean) Locked 52 * If not present, pref is not locked. 53 * [v] => (string) Current pref value 54 * ) 55 * 56 * For internal storage, if 'l' and 'v' are both not available: 57 * [pref_name] => (string) Current pref value 58 * </pre> 59 * 60 * @var array 61 */ 62 protected $_prefs = array(); 63 64 /** 65 * Constructor. 66 * 67 * @param string $scope The scope for this set of preferences. 68 */ 69 public function __construct($scope) 70 { 71 $this->scope = $scope; 72 } 73 74 /** 75 * Removes a preference entry. 76 * 77 * @param string $pref The name of the preference to remove. 78 * 79 * @return boolean True if preference was removed. 80 */ 81 public function remove($pref) 82 { 83 if (!($p = $this->_fromInternal($pref))) { 84 return false; 85 } 86 87 if (isset($p['d'])) { 88 $p['v'] = $p['d']; 89 unset($p['d']); 90 $this->_toInternal($pref, $p); 91 $this->setDirty($pref, false); 92 } 93 94 return true; 95 } 96 97 /** 98 * Sets the value for a preference. 99 * 100 * @param string $pref The preference name. 101 * @param string $val The preference value. 102 */ 103 public function set($pref, $val) 104 { 105 if ($p = $this->_fromInternal($pref)) { 106 if ($val != $p['v']) { 107 if (isset($p['d']) && ($val == $p['d'])) { 108 unset($p['d']); 109 } else { 110 $p['d'] = $p['v']; 111 } 112 $p['v'] = $val; 113 $this->_toInternal($pref, $p); 114 } 115 } else { 116 $this->_toInternal($pref, array('v' => $val)); 117 } 118 } 119 120 /** 121 * Does a preference exist in this scope? 122 * 123 * @return boolean True if the preference exists. 124 */ 125 public function exists($pref) 126 { 127 return isset($this->_prefs[$pref]); 128 } 129 130 /** 131 * Returns the value of a preference. 132 * 133 * @param string $pref The preference name to retrieve. 134 * 135 * @return string The value of the preference, null if it doesn't exist. 136 */ 137 public function get($pref) 138 { 139 return ($p = $this->_fromInternal($pref)) 140 ? $p['v'] 141 : null; 142 } 143 144 /** 145 * Mark a preference as locked. 146 * 147 * @param string $pref The preference name. 148 * @param boolean $locked Is the preference locked? 149 */ 150 public function setLocked($pref, $locked) 151 { 152 if ($p = $this->_fromInternal($pref)) { 153 if ($locked) { 154 if (!isset($p['l'])) { 155 $p['l'] = true; 156 $this->_toInternal($pref, $p); 157 } 158 } elseif (isset($p['l'])) { 159 unset($p['l']); 160 $this->_toInternal($pref, $p); 161 } 162 } 163 } 164 165 /** 166 * Is a preference locked? 167 * 168 * @param string $pref The preference name. 169 * 170 * @return boolean Whether the preference is locked. 171 */ 172 public function isLocked($pref) 173 { 174 return ($p = $this->_fromInternal($pref)) 175 ? !empty($p['l']) 176 : false; 177 } 178 179 /** 180 * Is a preference's value the default? 181 * 182 * @param string $pref The preference name. 183 * 184 * @return boolean True if the preference contains the default value. 185 */ 186 public function isDefault($pref) 187 { 188 return ($p = $this->_fromInternal($pref)) 189 ? !isset($p['d']) 190 : true; 191 } 192 193 /** 194 * Returns the default value of a preference. 195 * 196 * @param string $pref The preference name. 197 * 198 * @return string The preference's default value. 199 */ 200 public function getDefault($pref) 201 { 202 return ($p = $this->_fromInternal($pref)) 203 ? (isset($p['d']) ? $p['d'] : $p['v']) 204 : null; 205 } 206 207 /** 208 * Get the list of dirty preferences. 209 * 210 * @return array The list of dirty preferences. 211 */ 212 public function getDirty() 213 { 214 return array_keys($this->_dirty); 215 } 216 217 /** 218 * Is a preference marked dirty? 219 * 220 * @param mixed $pref The preference name. If null, will return true if 221 * scope contains at least one dirty pref. 222 * 223 * @return boolean True if the preference is marked dirty. 224 */ 225 public function isDirty($pref = null) 226 { 227 return is_null($pref) 228 ? !empty($this->_dirty) 229 : isset($this->_dirty[$pref]); 230 } 231 232 /** 233 * Set the dirty flag for a preference 234 * 235 * @param string $pref The preference name. 236 * @param boolean $dirty True to mark the pref as dirty. 237 */ 238 public function setDirty($pref, $dirty) 239 { 240 if ($dirty) { 241 $this->_dirty[$pref] = true; 242 } else { 243 unset($this->_dirty[$pref]); 244 } 245 } 246 247 /** 248 */ 249 protected function _fromInternal($pref) 250 { 251 if (!isset($this->_prefs[$pref])) { 252 return false; 253 } 254 255 return is_array($this->_prefs[$pref]) 256 ? $this->_prefs[$pref] 257 : array('v' => $this->_prefs[$pref]); 258 } 259 260 /** 261 */ 262 protected function _toInternal($pref, array $value) 263 { 264 if (!isset($value['d']) && !isset($value['l'])) { 265 $value = $value['v']; 266 } 267 268 $this->_prefs[$pref] = $value; 269 270 if (!$this->init) { 271 $this->setDirty($pref, true); 272 } 273 } 274 275 /* Iterator methods. */ 276 277 /** 278 */ 279 public function current() 280 { 281 return $this->_fromInternal($this->key()); 282 } 283 284 /** 285 */ 286 public function key() 287 { 288 return key($this->_prefs); 289 } 290 291 /** 292 */ 293 public function next() 294 { 295 return next($this->_prefs); 296 } 297 298 /** 299 */ 300 public function rewind() 301 { 302 return reset($this->_prefs); 303 } 304 305 /** 306 */ 307 public function valid() 308 { 309 return !is_null(key($this->_prefs)); 310 } 311 312 /* Serializable methods. */ 313 314 /** 315 */ 316 public function serialize() 317 { 318 return json_encode(array( 319 $this->scope, 320 $this->_prefs 321 )); 322 } 323 324 /** 325 */ 326 public function unserialize($data) 327 { 328 list($this->scope, $this->_prefs) = json_decode($data, true); 329 } 330 331} 332