PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Session/Storage/ArrayStorage.php

https://github.com/MontmereLimited/zf2
PHP | 345 lines | 165 code | 31 blank | 149 comment | 30 complexity | aa70f4ec035ab90003692a0948984bcf MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-webat this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Session
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /**
  21. * @namespace
  22. */
  23. namespace Zend\Session\Storage;
  24. use ArrayObject,
  25. Zend\Session\Storage as Storable,
  26. Zend\Session\Exception;
  27. /**
  28. * Array session storage
  29. *
  30. * Defines an ArrayObject interface for accessing session storage, with options
  31. * for setting metadata, locking, and marking as immutable.
  32. *
  33. * @category Zend
  34. * @package Zend_Session
  35. * @subpackage Storage
  36. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  37. * @license http://framework.zend.com/license/new-bsd New BSD License
  38. */
  39. class ArrayStorage extends ArrayObject implements Storable
  40. {
  41. /**
  42. * Is storage marked immutable?
  43. * @var bool
  44. */
  45. protected $_immutable = false;
  46. /**
  47. * Constructor
  48. *
  49. * Instantiates storage as an ArrayObject, allowing property access.
  50. * Also sets the initial request access time.
  51. *
  52. * @param array|ArrayAccess $input
  53. * @param int $flags
  54. * @param string $iteratorClass
  55. * @return void
  56. */
  57. public function __construct($input = array(), $flags = \ArrayObject::ARRAY_AS_PROPS, $iteratorClass = '\\ArrayIterator')
  58. {
  59. parent::__construct($input, $flags, $iteratorClass);
  60. $this->setMetadata('_REQUEST_ACCESS_TIME', microtime(true));
  61. }
  62. /**
  63. * Retrieve the request access time
  64. *
  65. * @return int
  66. */
  67. public function getRequestAccessTime()
  68. {
  69. return $this->getMetadata('_REQUEST_ACCESS_TIME');
  70. }
  71. /**
  72. * Set a value in the storage object
  73. *
  74. * If the object is marked as immutable, or the object or key is marked as
  75. * locked, raises an exception.
  76. *
  77. * @param string $key
  78. * @param mixed $value
  79. * @return void
  80. */
  81. public function offsetSet($key, $value)
  82. {
  83. if ($this->isImmutable()) {
  84. throw new Exception\RuntimeException('Cannot set key "' . $key . '" as storage is marked immutable');
  85. }
  86. if ($this->isLocked($key)) {
  87. throw new Exception\RuntimeException('Cannot set key "' . $key . '" due to locking');
  88. }
  89. return parent::offsetSet($key, $value);
  90. }
  91. /**
  92. * Lock this storage instance, or a key within it
  93. *
  94. * @param null|int|string $key
  95. * @return ArrayStorage
  96. */
  97. public function lock($key = null)
  98. {
  99. if (null === $key) {
  100. $this->setMetadata('_READONLY', true);
  101. return $this;
  102. }
  103. if (isset($this[$key])) {
  104. $this->setMetadata('_LOCKS', array($key => true));
  105. }
  106. return $this;
  107. }
  108. /**
  109. * Is the object or key marked as locked?
  110. *
  111. * @param null|int|string $key
  112. * @return bool
  113. */
  114. public function isLocked($key = null)
  115. {
  116. if ($this->isImmutable()) {
  117. // immutable trumps all
  118. return true;
  119. }
  120. if (null === $key) {
  121. // testing for global lock
  122. return $this->getMetadata('_READONLY');
  123. }
  124. $locks = $this->getMetadata('_LOCKS');
  125. $readOnly = $this->getMetadata('_READONLY');
  126. if ($readOnly && !$locks) {
  127. // global lock in play; all keys are locked
  128. return true;
  129. } elseif ($readOnly && $locks) {
  130. return array_key_exists($key, $locks);
  131. }
  132. // test for individual locks
  133. if (!$locks) {
  134. return false;
  135. }
  136. return array_key_exists($key, $locks);
  137. }
  138. /**
  139. * Unlock an object or key marked as locked
  140. *
  141. * @param null|int|string $key
  142. * @return ArrayStorage
  143. */
  144. public function unlock($key = null)
  145. {
  146. if (null === $key) {
  147. // Unlock everything
  148. $this->setMetadata('_READONLY', false);
  149. $this->setMetadata('_LOCKS', false);
  150. return $this;
  151. }
  152. $locks = $this->getMetadata('_LOCKS');
  153. if (!$locks) {
  154. if (!$this->getMetadata('_READONLY')) {
  155. return $this;
  156. }
  157. $array = $this->toArray();
  158. $keys = array_keys($array);
  159. $locks = array_flip($keys);
  160. unset($array, $keys);
  161. }
  162. if (array_key_exists($key, $locks)) {
  163. unset($locks[$key]);
  164. $this->setMetadata('_LOCKS', $locks, true);
  165. }
  166. return $this;
  167. }
  168. /**
  169. * Mark the storage container as immutable
  170. *
  171. * @return ArrayStorage
  172. */
  173. public function markImmutable()
  174. {
  175. $this->_immutable = true;
  176. return $this;
  177. }
  178. /**
  179. * Is the storage container marked as immutable?
  180. *
  181. * @return bool
  182. */
  183. public function isImmutable()
  184. {
  185. return $this->_immutable;
  186. }
  187. /**
  188. * Set storage metadata
  189. *
  190. * Metadata is used to store information about the data being stored in the
  191. * object. Some example use cases include:
  192. * - Setting expiry data
  193. * - Maintaining access counts
  194. * - localizing session storage
  195. * - etc.
  196. *
  197. * @param string $key
  198. * @param mixed $value
  199. * @param bool $overwriteArray Whether to overwrite or merge array values; by default, merges
  200. * @return ArrayStorage
  201. */
  202. public function setMetadata($key, $value, $overwriteArray = false)
  203. {
  204. if ($this->_immutable) {
  205. throw new Exception\InvalidArgumentException('Cannot set metadata key "' . $key . '" as storage is marked immutable');
  206. }
  207. if (!isset($this['__ZF'])) {
  208. $this['__ZF'] = array();
  209. }
  210. if (isset($this['__ZF'][$key]) && is_array($value)) {
  211. if ($overwriteArray) {
  212. $this['__ZF'][$key] = $value;
  213. } elseif (null === $value) {
  214. // unset($this['__ZF'][$key]) led to "indirect modification...
  215. // has no effect" errors, so explicitly pulling array and
  216. // unsetting key.
  217. $array = $this['__ZF'];
  218. unset($array[$key]);
  219. $this['__ZF'] = $array;
  220. unset($array);
  221. } else {
  222. $this['__ZF'][$key] = array_replace_recursive($this['__ZF'][$key], $value);
  223. }
  224. } else {
  225. if ((null === $value) && isset($this['__ZF'][$key])) {
  226. // unset($this['__ZF'][$key]) led to "indirect modification...
  227. // has no effect" errors, so explicitly pulling array and
  228. // unsetting key.
  229. $array = $this['__ZF'];
  230. unset($array[$key]);
  231. $this['__ZF'] = $array;
  232. unset($array);
  233. } elseif (null !== $value) {
  234. $this['__ZF'][$key] = $value;
  235. }
  236. }
  237. return $this;
  238. }
  239. /**
  240. * Retrieve metadata for the storage object or a specific metadata key
  241. *
  242. * Returns false if no metadata stored, or no metadata exists for the given
  243. * key.
  244. *
  245. * @param null|int|string $key
  246. * @return mixed
  247. */
  248. public function getMetadata($key = null)
  249. {
  250. if (!isset($this['__ZF'])) {
  251. return false;
  252. }
  253. if (null === $key) {
  254. return $this['__ZF'];
  255. }
  256. if (!array_key_exists($key, $this['__ZF'])) {
  257. return false;
  258. }
  259. return $this['__ZF'][$key];
  260. }
  261. /**
  262. * Clear the storage object or a subkey of the object
  263. *
  264. * @param null|int|string $key
  265. * @return ArrayStorage
  266. */
  267. public function clear($key = null)
  268. {
  269. if ($this->isImmutable()) {
  270. throw new Exception\RuntimeException('Cannot clear storage as it is marked immutable');
  271. }
  272. if (null === $key) {
  273. $this->exchangeArray(array());
  274. return $this;
  275. }
  276. if (!isset($this[$key])) {
  277. return $this;
  278. }
  279. // Clear key data
  280. unset($this[$key]);
  281. // Clear key metadata
  282. $this->setMetadata($key, null)
  283. ->unlock($key);
  284. return $this;
  285. }
  286. /**
  287. * Cast the object to an array
  288. *
  289. * Returns data only, no metadata.
  290. *
  291. * @return array
  292. */
  293. public function toArray()
  294. {
  295. $values = $this->getArrayCopy();
  296. if (isset($values['__ZF'])) {
  297. unset($values['__ZF']);
  298. }
  299. return $values;
  300. }
  301. /**
  302. * Load the storage from another array
  303. *
  304. * Overwrites any data that was previously set.
  305. *
  306. * @param array $array
  307. * @return ArrayStorage
  308. */
  309. public function fromArray(array $array)
  310. {
  311. $this->exchangeArray($array);
  312. return $this;
  313. }
  314. }