composer package updates
[openemr.git] / vendor / zendframework / zend-cache / src / Storage / Adapter / AbstractAdapter.php
blobe54841843f2a678b4faca144fc415635392b3f69
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Cache\Storage\Adapter;
12 use ArrayObject;
13 use SplObjectStorage;
14 use stdClass;
15 use Traversable;
16 use Zend\Cache\Exception;
17 use Zend\Cache\Storage\Capabilities;
18 use Zend\Cache\Storage\Event;
19 use Zend\Cache\Storage\ExceptionEvent;
20 use Zend\Cache\Storage\Plugin;
21 use Zend\Cache\Storage\PostEvent;
22 use Zend\Cache\Storage\StorageInterface;
23 use Zend\EventManager\EventManager;
24 use Zend\EventManager\EventManagerInterface;
25 use Zend\EventManager\EventsCapableInterface;
27 abstract class AbstractAdapter implements StorageInterface, EventsCapableInterface
29 /**
30 * The used EventManager if any
32 * @var null|EventManagerInterface
34 protected $events = null;
36 /**
37 * Event handles of this adapter
38 * @var array
40 protected $eventHandles = [];
42 /**
43 * The plugin registry
45 * @var SplObjectStorage Registered plugins
47 protected $pluginRegistry;
49 /**
50 * Capabilities of this adapter
52 * @var null|Capabilities
54 protected $capabilities = null;
56 /**
57 * Marker to change capabilities
59 * @var null|object
61 protected $capabilityMarker;
63 /**
64 * options
66 * @var mixed
68 protected $options;
70 /**
71 * Constructor
73 * @param null|array|Traversable|AdapterOptions $options
74 * @throws Exception\ExceptionInterface
76 public function __construct($options = null)
78 if ($options) {
79 $this->setOptions($options);
83 /**
84 * Destructor
86 * detach all registered plugins to free
87 * event handles of event manager
89 * @return void
91 public function __destruct()
93 foreach ($this->getPluginRegistry() as $plugin) {
94 $this->removePlugin($plugin);
97 if ($this->eventHandles) {
98 $events = $this->getEventManager();
99 foreach ($this->eventHandles as $handle) {
100 $events->detach($handle);
105 /* configuration */
108 * Set options.
110 * @param array|Traversable|AdapterOptions $options
111 * @return AbstractAdapter Provides a fluent interface
112 * @see getOptions()
114 public function setOptions($options)
116 if ($this->options !== $options) {
117 if (! $options instanceof AdapterOptions) {
118 $options = new AdapterOptions($options);
121 if ($this->options) {
122 $this->options->setAdapter(null);
124 $options->setAdapter($this);
125 $this->options = $options;
127 $event = new Event('option', $this, new ArrayObject($options->toArray()));
129 $this->getEventManager()->triggerEvent($event);
131 return $this;
135 * Get options.
137 * @return AdapterOptions
138 * @see setOptions()
140 public function getOptions()
142 if (! $this->options) {
143 $this->setOptions(new AdapterOptions());
145 return $this->options;
149 * Enable/Disable caching.
151 * Alias of setWritable and setReadable.
153 * @see setWritable()
154 * @see setReadable()
155 * @param bool $flag
156 * @return AbstractAdapter Provides a fluent interface
158 public function setCaching($flag)
160 $flag = (bool) $flag;
161 $options = $this->getOptions();
162 $options->setWritable($flag);
163 $options->setReadable($flag);
164 return $this;
168 * Get caching enabled.
170 * Alias of getWritable and getReadable.
172 * @see getWritable()
173 * @see getReadable()
174 * @return bool
176 public function getCaching()
178 $options = $this->getOptions();
179 return ($options->getWritable() && $options->getReadable());
182 /* Event/Plugin handling */
185 * Get the event manager
187 * @return EventManagerInterface
189 public function getEventManager()
191 if ($this->events === null) {
192 $this->events = new EventManager();
193 $this->events->setIdentifiers([__CLASS__, get_class($this)]);
195 return $this->events;
199 * Trigger a pre event and return the event response collection
201 * @param string $eventName
202 * @param ArrayObject $args
203 * @return \Zend\EventManager\ResponseCollection All handler return values
205 protected function triggerPre($eventName, ArrayObject $args)
207 return $this->getEventManager()->triggerEvent(new Event($eventName . '.pre', $this, $args));
211 * Triggers the PostEvent and return the result value.
213 * @param string $eventName
214 * @param ArrayObject $args
215 * @param mixed $result
216 * @return mixed
218 protected function triggerPost($eventName, ArrayObject $args, & $result)
220 $postEvent = new PostEvent($eventName . '.post', $this, $args, $result);
221 $eventRs = $this->getEventManager()->triggerEvent($postEvent);
223 return $eventRs->stopped()
224 ? $eventRs->last()
225 : $postEvent->getResult();
229 * Trigger an exception event
231 * If the ExceptionEvent has the flag "throwException" enabled throw the
232 * exception after trigger else return the result.
234 * @param string $eventName
235 * @param ArrayObject $args
236 * @param mixed $result
237 * @param \Exception $exception
238 * @throws Exception\ExceptionInterface
239 * @return mixed
241 protected function triggerException($eventName, ArrayObject $args, & $result, \Exception $exception)
243 $exceptionEvent = new ExceptionEvent($eventName . '.exception', $this, $args, $result, $exception);
244 $eventRs = $this->getEventManager()->triggerEvent($exceptionEvent);
246 if ($exceptionEvent->getThrowException()) {
247 throw $exceptionEvent->getException();
250 return $eventRs->stopped()
251 ? $eventRs->last()
252 : $exceptionEvent->getResult();
256 * Check if a plugin is registered
258 * @param Plugin\PluginInterface $plugin
259 * @return bool
261 public function hasPlugin(Plugin\PluginInterface $plugin)
263 $registry = $this->getPluginRegistry();
264 return $registry->contains($plugin);
268 * Register a plugin
270 * @param Plugin\PluginInterface $plugin
271 * @param int $priority
272 * @return AbstractAdapter Provides a fluent interface
273 * @throws Exception\LogicException
275 public function addPlugin(Plugin\PluginInterface $plugin, $priority = 1)
277 $registry = $this->getPluginRegistry();
278 if ($registry->contains($plugin)) {
279 throw new Exception\LogicException(sprintf(
280 'Plugin of type "%s" already registered',
281 get_class($plugin)
285 $plugin->attach($this->getEventManager(), $priority);
286 $registry->attach($plugin);
288 return $this;
292 * Unregister an already registered plugin
294 * @param Plugin\PluginInterface $plugin
295 * @return AbstractAdapter Provides a fluent interface
296 * @throws Exception\LogicException
298 public function removePlugin(Plugin\PluginInterface $plugin)
300 $registry = $this->getPluginRegistry();
301 if ($registry->contains($plugin)) {
302 $plugin->detach($this->getEventManager());
303 $registry->detach($plugin);
305 return $this;
309 * Return registry of plugins
311 * @return SplObjectStorage
313 public function getPluginRegistry()
315 if (! $this->pluginRegistry instanceof SplObjectStorage) {
316 $this->pluginRegistry = new SplObjectStorage();
318 return $this->pluginRegistry;
321 /* reading */
324 * Get an item.
326 * @param string $key
327 * @param bool $success
328 * @param mixed $casToken
329 * @return mixed Data on success, null on failure
330 * @throws Exception\ExceptionInterface
332 * @triggers getItem.pre(PreEvent)
333 * @triggers getItem.post(PostEvent)
334 * @triggers getItem.exception(ExceptionEvent)
336 public function getItem($key, & $success = null, & $casToken = null)
338 if (! $this->getOptions()->getReadable()) {
339 $success = false;
340 return;
343 $this->normalizeKey($key);
345 $argn = func_num_args();
346 $args = [
347 'key' => & $key,
349 if ($argn > 1) {
350 $args['success'] = & $success;
352 if ($argn > 2) {
353 $args['casToken'] = & $casToken;
355 $args = new ArrayObject($args);
357 try {
358 $eventRs = $this->triggerPre(__FUNCTION__, $args);
360 if ($eventRs->stopped()) {
361 $result = $eventRs->last();
362 } elseif ($args->offsetExists('success') && $args->offsetExists('casToken')) {
363 $result = $this->internalGetItem($args['key'], $args['success'], $args['casToken']);
364 } elseif ($args->offsetExists('success')) {
365 $result = $this->internalGetItem($args['key'], $args['success']);
366 } else {
367 $result = $this->internalGetItem($args['key']);
370 return $this->triggerPost(__FUNCTION__, $args, $result);
371 } catch (\Exception $e) {
372 $result = null;
373 $success = false;
374 return $this->triggerException(__FUNCTION__, $args, $result, $e);
379 * Internal method to get an item.
381 * @param string $normalizedKey
382 * @param bool $success
383 * @param mixed $casToken
384 * @return mixed Data on success, null on failure
385 * @throws Exception\ExceptionInterface
387 abstract protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null);
390 * Get multiple items.
392 * @param array $keys
393 * @return array Associative array of keys and values
394 * @throws Exception\ExceptionInterface
396 * @triggers getItems.pre(PreEvent)
397 * @triggers getItems.post(PostEvent)
398 * @triggers getItems.exception(ExceptionEvent)
400 public function getItems(array $keys)
402 if (! $this->getOptions()->getReadable()) {
403 return [];
406 $this->normalizeKeys($keys);
407 $args = new ArrayObject([
408 'keys' => & $keys,
411 try {
412 $eventRs = $this->triggerPre(__FUNCTION__, $args);
414 $result = $eventRs->stopped()
415 ? $eventRs->last()
416 : $this->internalGetItems($args['keys']);
418 return $this->triggerPost(__FUNCTION__, $args, $result);
419 } catch (\Exception $e) {
420 $result = [];
421 return $this->triggerException(__FUNCTION__, $args, $result, $e);
426 * Internal method to get multiple items.
428 * @param array $normalizedKeys
429 * @return array Associative array of keys and values
430 * @throws Exception\ExceptionInterface
432 protected function internalGetItems(array & $normalizedKeys)
434 $success = null;
435 $result = [];
436 foreach ($normalizedKeys as $normalizedKey) {
437 $value = $this->internalGetItem($normalizedKey, $success);
438 if ($success) {
439 $result[$normalizedKey] = $value;
443 return $result;
447 * Test if an item exists.
449 * @param string $key
450 * @return bool
451 * @throws Exception\ExceptionInterface
453 * @triggers hasItem.pre(PreEvent)
454 * @triggers hasItem.post(PostEvent)
455 * @triggers hasItem.exception(ExceptionEvent)
457 public function hasItem($key)
459 if (! $this->getOptions()->getReadable()) {
460 return false;
463 $this->normalizeKey($key);
464 $args = new ArrayObject([
465 'key' => & $key,
468 try {
469 $eventRs = $this->triggerPre(__FUNCTION__, $args);
471 $result = $eventRs->stopped()
472 ? $eventRs->last()
473 : $this->internalHasItem($args['key']);
475 return $this->triggerPost(__FUNCTION__, $args, $result);
476 } catch (\Exception $e) {
477 $result = false;
478 return $this->triggerException(__FUNCTION__, $args, $result, $e);
483 * Internal method to test if an item exists.
485 * @param string $normalizedKey
486 * @return bool
487 * @throws Exception\ExceptionInterface
489 protected function internalHasItem(& $normalizedKey)
491 $success = null;
492 $this->internalGetItem($normalizedKey, $success);
493 return $success;
497 * Test multiple items.
499 * @param array $keys
500 * @return array Array of found keys
501 * @throws Exception\ExceptionInterface
503 * @triggers hasItems.pre(PreEvent)
504 * @triggers hasItems.post(PostEvent)
505 * @triggers hasItems.exception(ExceptionEvent)
507 public function hasItems(array $keys)
509 if (! $this->getOptions()->getReadable()) {
510 return [];
513 $this->normalizeKeys($keys);
514 $args = new ArrayObject([
515 'keys' => & $keys,
518 try {
519 $eventRs = $this->triggerPre(__FUNCTION__, $args);
521 $result = $eventRs->stopped()
522 ? $eventRs->last()
523 : $this->internalHasItems($args['keys']);
525 return $this->triggerPost(__FUNCTION__, $args, $result);
526 } catch (\Exception $e) {
527 $result = [];
528 return $this->triggerException(__FUNCTION__, $args, $result, $e);
533 * Internal method to test multiple items.
535 * @param array $normalizedKeys
536 * @return array Array of found keys
537 * @throws Exception\ExceptionInterface
539 protected function internalHasItems(array & $normalizedKeys)
541 $result = [];
542 foreach ($normalizedKeys as $normalizedKey) {
543 if ($this->internalHasItem($normalizedKey)) {
544 $result[] = $normalizedKey;
547 return $result;
551 * Get metadata of an item.
553 * @param string $key
554 * @return array|bool Metadata on success, false on failure
555 * @throws Exception\ExceptionInterface
557 * @triggers getMetadata.pre(PreEvent)
558 * @triggers getMetadata.post(PostEvent)
559 * @triggers getMetadata.exception(ExceptionEvent)
561 public function getMetadata($key)
563 if (! $this->getOptions()->getReadable()) {
564 return false;
567 $this->normalizeKey($key);
568 $args = new ArrayObject([
569 'key' => & $key,
572 try {
573 $eventRs = $this->triggerPre(__FUNCTION__, $args);
575 $result = $eventRs->stopped()
576 ? $eventRs->last()
577 : $this->internalGetMetadata($args['key']);
579 return $this->triggerPost(__FUNCTION__, $args, $result);
580 } catch (\Exception $e) {
581 $result = false;
582 return $this->triggerException(__FUNCTION__, $args, $result, $e);
587 * Internal method to get metadata of an item.
589 * @param string $normalizedKey
590 * @return array|bool Metadata on success, false on failure
591 * @throws Exception\ExceptionInterface
593 protected function internalGetMetadata(& $normalizedKey)
595 if (! $this->internalHasItem($normalizedKey)) {
596 return false;
599 return [];
603 * Get multiple metadata
605 * @param array $keys
606 * @return array Associative array of keys and metadata
607 * @throws Exception\ExceptionInterface
609 * @triggers getMetadatas.pre(PreEvent)
610 * @triggers getMetadatas.post(PostEvent)
611 * @triggers getMetadatas.exception(ExceptionEvent)
613 public function getMetadatas(array $keys)
615 if (! $this->getOptions()->getReadable()) {
616 return [];
619 $this->normalizeKeys($keys);
620 $args = new ArrayObject([
621 'keys' => & $keys,
624 try {
625 $eventRs = $this->triggerPre(__FUNCTION__, $args);
627 $result = $eventRs->stopped()
628 ? $eventRs->last()
629 : $this->internalGetMetadatas($args['keys']);
631 return $this->triggerPost(__FUNCTION__, $args, $result);
632 } catch (\Exception $e) {
633 $result = [];
634 return $this->triggerException(__FUNCTION__, $args, $result, $e);
639 * Internal method to get multiple metadata
641 * @param array $normalizedKeys
642 * @return array Associative array of keys and metadata
643 * @throws Exception\ExceptionInterface
645 protected function internalGetMetadatas(array & $normalizedKeys)
647 $result = [];
648 foreach ($normalizedKeys as $normalizedKey) {
649 $metadata = $this->internalGetMetadata($normalizedKey);
650 if ($metadata !== false) {
651 $result[$normalizedKey] = $metadata;
654 return $result;
657 /* writing */
660 * Store an item.
662 * @param string $key
663 * @param mixed $value
664 * @return bool
665 * @throws Exception\ExceptionInterface
667 * @triggers setItem.pre(PreEvent)
668 * @triggers setItem.post(PostEvent)
669 * @triggers setItem.exception(ExceptionEvent)
671 public function setItem($key, $value)
673 if (! $this->getOptions()->getWritable()) {
674 return false;
677 $this->normalizeKey($key);
678 $args = new ArrayObject([
679 'key' => & $key,
680 'value' => & $value,
683 try {
684 $eventRs = $this->triggerPre(__FUNCTION__, $args);
686 $result = $eventRs->stopped()
687 ? $eventRs->last()
688 : $this->internalSetItem($args['key'], $args['value']);
690 return $this->triggerPost(__FUNCTION__, $args, $result);
691 } catch (\Exception $e) {
692 $result = false;
693 return $this->triggerException(__FUNCTION__, $args, $result, $e);
698 * Internal method to store an item.
700 * @param string $normalizedKey
701 * @param mixed $value
702 * @return bool
703 * @throws Exception\ExceptionInterface
705 abstract protected function internalSetItem(& $normalizedKey, & $value);
708 * Store multiple items.
710 * @param array $keyValuePairs
711 * @return array Array of not stored keys
712 * @throws Exception\ExceptionInterface
714 * @triggers setItems.pre(PreEvent)
715 * @triggers setItems.post(PostEvent)
716 * @triggers setItems.exception(ExceptionEvent)
718 public function setItems(array $keyValuePairs)
720 if (! $this->getOptions()->getWritable()) {
721 return array_keys($keyValuePairs);
724 $this->normalizeKeyValuePairs($keyValuePairs);
725 $args = new ArrayObject([
726 'keyValuePairs' => & $keyValuePairs,
729 try {
730 $eventRs = $this->triggerPre(__FUNCTION__, $args);
732 $result = $eventRs->stopped()
733 ? $eventRs->last()
734 : $this->internalSetItems($args['keyValuePairs']);
736 return $this->triggerPost(__FUNCTION__, $args, $result);
737 } catch (\Exception $e) {
738 $result = array_keys($keyValuePairs);
739 return $this->triggerException(__FUNCTION__, $args, $result, $e);
744 * Internal method to store multiple items.
746 * @param array $normalizedKeyValuePairs
747 * @return array Array of not stored keys
748 * @throws Exception\ExceptionInterface
750 protected function internalSetItems(array & $normalizedKeyValuePairs)
752 $failedKeys = [];
753 foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
754 if (! $this->internalSetItem($normalizedKey, $value)) {
755 $failedKeys[] = $normalizedKey;
758 return $failedKeys;
762 * Add an item.
764 * @param string $key
765 * @param mixed $value
766 * @return bool
767 * @throws Exception\ExceptionInterface
769 * @triggers addItem.pre(PreEvent)
770 * @triggers addItem.post(PostEvent)
771 * @triggers addItem.exception(ExceptionEvent)
773 public function addItem($key, $value)
775 if (! $this->getOptions()->getWritable()) {
776 return false;
779 $this->normalizeKey($key);
780 $args = new ArrayObject([
781 'key' => & $key,
782 'value' => & $value,
785 try {
786 $eventRs = $this->triggerPre(__FUNCTION__, $args);
788 $result = $eventRs->stopped()
789 ? $eventRs->last()
790 : $this->internalAddItem($args['key'], $args['value']);
792 return $this->triggerPost(__FUNCTION__, $args, $result);
793 } catch (\Exception $e) {
794 $result = false;
795 return $this->triggerException(__FUNCTION__, $args, $result, $e);
800 * Internal method to add an item.
802 * @param string $normalizedKey
803 * @param mixed $value
804 * @return bool
805 * @throws Exception\ExceptionInterface
807 protected function internalAddItem(& $normalizedKey, & $value)
809 if ($this->internalHasItem($normalizedKey)) {
810 return false;
812 return $this->internalSetItem($normalizedKey, $value);
816 * Add multiple items.
818 * @param array $keyValuePairs
819 * @return array Array of not stored keys
820 * @throws Exception\ExceptionInterface
822 * @triggers addItems.pre(PreEvent)
823 * @triggers addItems.post(PostEvent)
824 * @triggers addItems.exception(ExceptionEvent)
826 public function addItems(array $keyValuePairs)
828 if (! $this->getOptions()->getWritable()) {
829 return array_keys($keyValuePairs);
832 $this->normalizeKeyValuePairs($keyValuePairs);
833 $args = new ArrayObject([
834 'keyValuePairs' => & $keyValuePairs,
837 try {
838 $eventRs = $this->triggerPre(__FUNCTION__, $args);
840 $result = $eventRs->stopped()
841 ? $eventRs->last()
842 : $this->internalAddItems($args['keyValuePairs']);
844 return $this->triggerPost(__FUNCTION__, $args, $result);
845 } catch (\Exception $e) {
846 $result = array_keys($keyValuePairs);
847 return $this->triggerException(__FUNCTION__, $args, $result, $e);
852 * Internal method to add multiple items.
854 * @param array $normalizedKeyValuePairs
855 * @return array Array of not stored keys
856 * @throws Exception\ExceptionInterface
858 protected function internalAddItems(array & $normalizedKeyValuePairs)
860 $result = [];
861 foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
862 if (! $this->internalAddItem($normalizedKey, $value)) {
863 $result[] = $normalizedKey;
866 return $result;
870 * Replace an existing item.
872 * @param string $key
873 * @param mixed $value
874 * @return bool
875 * @throws Exception\ExceptionInterface
877 * @triggers replaceItem.pre(PreEvent)
878 * @triggers replaceItem.post(PostEvent)
879 * @triggers replaceItem.exception(ExceptionEvent)
881 public function replaceItem($key, $value)
883 if (! $this->getOptions()->getWritable()) {
884 return false;
887 $this->normalizeKey($key);
888 $args = new ArrayObject([
889 'key' => & $key,
890 'value' => & $value,
893 try {
894 $eventRs = $this->triggerPre(__FUNCTION__, $args);
896 $result = $eventRs->stopped()
897 ? $eventRs->last()
898 : $this->internalReplaceItem($args['key'], $args['value']);
900 return $this->triggerPost(__FUNCTION__, $args, $result);
901 } catch (\Exception $e) {
902 $result = false;
903 return $this->triggerException(__FUNCTION__, $args, $result, $e);
908 * Internal method to replace an existing item.
910 * @param string $normalizedKey
911 * @param mixed $value
912 * @return bool
913 * @throws Exception\ExceptionInterface
915 protected function internalReplaceItem(& $normalizedKey, & $value)
917 if (! $this->internalhasItem($normalizedKey)) {
918 return false;
921 return $this->internalSetItem($normalizedKey, $value);
925 * Replace multiple existing items.
927 * @param array $keyValuePairs
928 * @return array Array of not stored keys
929 * @throws Exception\ExceptionInterface
931 * @triggers replaceItems.pre(PreEvent)
932 * @triggers replaceItems.post(PostEvent)
933 * @triggers replaceItems.exception(ExceptionEvent)
935 public function replaceItems(array $keyValuePairs)
937 if (! $this->getOptions()->getWritable()) {
938 return array_keys($keyValuePairs);
941 $this->normalizeKeyValuePairs($keyValuePairs);
942 $args = new ArrayObject([
943 'keyValuePairs' => & $keyValuePairs,
946 try {
947 $eventRs = $this->triggerPre(__FUNCTION__, $args);
949 $result = $eventRs->stopped()
950 ? $eventRs->last()
951 : $this->internalReplaceItems($args['keyValuePairs']);
953 return $this->triggerPost(__FUNCTION__, $args, $result);
954 } catch (\Exception $e) {
955 $result = array_keys($keyValuePairs);
956 return $this->triggerException(__FUNCTION__, $args, $result, $e);
961 * Internal method to replace multiple existing items.
963 * @param array $normalizedKeyValuePairs
964 * @return array Array of not stored keys
965 * @throws Exception\ExceptionInterface
967 protected function internalReplaceItems(array & $normalizedKeyValuePairs)
969 $result = [];
970 foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
971 if (! $this->internalReplaceItem($normalizedKey, $value)) {
972 $result[] = $normalizedKey;
975 return $result;
979 * Set an item only if token matches
981 * It uses the token received from getItem() to check if the item has
982 * changed before overwriting it.
984 * @param mixed $token
985 * @param string $key
986 * @param mixed $value
987 * @return bool
988 * @throws Exception\ExceptionInterface
989 * @see getItem()
990 * @see setItem()
992 public function checkAndSetItem($token, $key, $value)
994 if (! $this->getOptions()->getWritable()) {
995 return false;
998 $this->normalizeKey($key);
999 $args = new ArrayObject([
1000 'token' => & $token,
1001 'key' => & $key,
1002 'value' => & $value,
1005 try {
1006 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1008 $result = $eventRs->stopped()
1009 ? $eventRs->last()
1010 : $this->internalCheckAndSetItem($args['token'], $args['key'], $args['value']);
1012 return $this->triggerPost(__FUNCTION__, $args, $result);
1013 } catch (\Exception $e) {
1014 $result = false;
1015 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1020 * Internal method to set an item only if token matches
1022 * @param mixed $token
1023 * @param string $normalizedKey
1024 * @param mixed $value
1025 * @return bool
1026 * @throws Exception\ExceptionInterface
1027 * @see getItem()
1028 * @see setItem()
1030 protected function internalCheckAndSetItem(& $token, & $normalizedKey, & $value)
1032 $oldValue = $this->internalGetItem($normalizedKey);
1033 if ($oldValue !== $token) {
1034 return false;
1037 return $this->internalSetItem($normalizedKey, $value);
1041 * Reset lifetime of an item
1043 * @param string $key
1044 * @return bool
1045 * @throws Exception\ExceptionInterface
1047 * @triggers touchItem.pre(PreEvent)
1048 * @triggers touchItem.post(PostEvent)
1049 * @triggers touchItem.exception(ExceptionEvent)
1051 public function touchItem($key)
1053 if (! $this->getOptions()->getWritable()) {
1054 return false;
1057 $this->normalizeKey($key);
1058 $args = new ArrayObject([
1059 'key' => & $key,
1062 try {
1063 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1065 $result = $eventRs->stopped()
1066 ? $eventRs->last()
1067 : $this->internalTouchItem($args['key']);
1069 return $this->triggerPost(__FUNCTION__, $args, $result);
1070 } catch (\Exception $e) {
1071 $result = false;
1072 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1077 * Internal method to reset lifetime of an item
1079 * @param string $normalizedKey
1080 * @return bool
1081 * @throws Exception\ExceptionInterface
1083 protected function internalTouchItem(& $normalizedKey)
1085 $success = null;
1086 $value = $this->internalGetItem($normalizedKey, $success);
1087 if (! $success) {
1088 return false;
1091 return $this->internalReplaceItem($normalizedKey, $value);
1095 * Reset lifetime of multiple items.
1097 * @param array $keys
1098 * @return array Array of not updated keys
1099 * @throws Exception\ExceptionInterface
1101 * @triggers touchItems.pre(PreEvent)
1102 * @triggers touchItems.post(PostEvent)
1103 * @triggers touchItems.exception(ExceptionEvent)
1105 public function touchItems(array $keys)
1107 if (! $this->getOptions()->getWritable()) {
1108 return $keys;
1111 $this->normalizeKeys($keys);
1112 $args = new ArrayObject([
1113 'keys' => & $keys,
1116 try {
1117 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1119 $result = $eventRs->stopped()
1120 ? $eventRs->last()
1121 : $this->internalTouchItems($args['keys']);
1123 return $this->triggerPost(__FUNCTION__, $args, $result);
1124 } catch (\Exception $e) {
1125 return $this->triggerException(__FUNCTION__, $args, $keys, $e);
1130 * Internal method to reset lifetime of multiple items.
1132 * @param array $normalizedKeys
1133 * @return array Array of not updated keys
1134 * @throws Exception\ExceptionInterface
1136 protected function internalTouchItems(array & $normalizedKeys)
1138 $result = [];
1139 foreach ($normalizedKeys as $normalizedKey) {
1140 if (! $this->internalTouchItem($normalizedKey)) {
1141 $result[] = $normalizedKey;
1144 return $result;
1148 * Remove an item.
1150 * @param string $key
1151 * @return bool
1152 * @throws Exception\ExceptionInterface
1154 * @triggers removeItem.pre(PreEvent)
1155 * @triggers removeItem.post(PostEvent)
1156 * @triggers removeItem.exception(ExceptionEvent)
1158 public function removeItem($key)
1160 if (! $this->getOptions()->getWritable()) {
1161 return false;
1164 $this->normalizeKey($key);
1165 $args = new ArrayObject([
1166 'key' => & $key,
1169 try {
1170 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1172 $result = $eventRs->stopped()
1173 ? $eventRs->last()
1174 : $this->internalRemoveItem($args['key']);
1176 return $this->triggerPost(__FUNCTION__, $args, $result);
1177 } catch (\Exception $e) {
1178 $result = false;
1179 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1184 * Internal method to remove an item.
1186 * @param string $normalizedKey
1187 * @return bool
1188 * @throws Exception\ExceptionInterface
1190 abstract protected function internalRemoveItem(& $normalizedKey);
1193 * Remove multiple items.
1195 * @param array $keys
1196 * @return array Array of not removed keys
1197 * @throws Exception\ExceptionInterface
1199 * @triggers removeItems.pre(PreEvent)
1200 * @triggers removeItems.post(PostEvent)
1201 * @triggers removeItems.exception(ExceptionEvent)
1203 public function removeItems(array $keys)
1205 if (! $this->getOptions()->getWritable()) {
1206 return $keys;
1209 $this->normalizeKeys($keys);
1210 $args = new ArrayObject([
1211 'keys' => & $keys,
1214 try {
1215 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1217 $result = $eventRs->stopped()
1218 ? $eventRs->last()
1219 : $this->internalRemoveItems($args['keys']);
1221 return $this->triggerPost(__FUNCTION__, $args, $result);
1222 } catch (\Exception $e) {
1223 return $this->triggerException(__FUNCTION__, $args, $keys, $e);
1228 * Internal method to remove multiple items.
1230 * @param array $normalizedKeys
1231 * @return array Array of not removed keys
1232 * @throws Exception\ExceptionInterface
1234 protected function internalRemoveItems(array & $normalizedKeys)
1236 $result = [];
1237 foreach ($normalizedKeys as $normalizedKey) {
1238 if (! $this->internalRemoveItem($normalizedKey)) {
1239 $result[] = $normalizedKey;
1242 return $result;
1246 * Increment an item.
1248 * @param string $key
1249 * @param int $value
1250 * @return int|bool The new value on success, false on failure
1251 * @throws Exception\ExceptionInterface
1253 * @triggers incrementItem.pre(PreEvent)
1254 * @triggers incrementItem.post(PostEvent)
1255 * @triggers incrementItem.exception(ExceptionEvent)
1257 public function incrementItem($key, $value)
1259 if (! $this->getOptions()->getWritable()) {
1260 return false;
1263 $this->normalizeKey($key);
1264 $args = new ArrayObject([
1265 'key' => & $key,
1266 'value' => & $value,
1269 try {
1270 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1272 $result = $eventRs->stopped()
1273 ? $eventRs->last()
1274 : $this->internalIncrementItem($args['key'], $args['value']);
1276 return $this->triggerPost(__FUNCTION__, $args, $result);
1277 } catch (\Exception $e) {
1278 $result = false;
1279 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1284 * Internal method to increment an item.
1286 * @param string $normalizedKey
1287 * @param int $value
1288 * @return int|bool The new value on success, false on failure
1289 * @throws Exception\ExceptionInterface
1291 protected function internalIncrementItem(& $normalizedKey, & $value)
1293 $success = null;
1294 $value = (int) $value;
1295 $get = (int) $this->internalGetItem($normalizedKey, $success);
1296 $newValue = $get + $value;
1298 if ($success) {
1299 $this->internalReplaceItem($normalizedKey, $newValue);
1300 } else {
1301 $this->internalAddItem($normalizedKey, $newValue);
1304 return $newValue;
1308 * Increment multiple items.
1310 * @param array $keyValuePairs
1311 * @return array Associative array of keys and new values
1312 * @throws Exception\ExceptionInterface
1314 * @triggers incrementItems.pre(PreEvent)
1315 * @triggers incrementItems.post(PostEvent)
1316 * @triggers incrementItems.exception(ExceptionEvent)
1318 public function incrementItems(array $keyValuePairs)
1320 if (! $this->getOptions()->getWritable()) {
1321 return [];
1324 $this->normalizeKeyValuePairs($keyValuePairs);
1325 $args = new ArrayObject([
1326 'keyValuePairs' => & $keyValuePairs,
1329 try {
1330 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1332 $result = $eventRs->stopped()
1333 ? $eventRs->last()
1334 : $this->internalIncrementItems($args['keyValuePairs']);
1336 return $this->triggerPost(__FUNCTION__, $args, $result);
1337 } catch (\Exception $e) {
1338 $result = [];
1339 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1344 * Internal method to increment multiple items.
1346 * @param array $normalizedKeyValuePairs
1347 * @return array Associative array of keys and new values
1348 * @throws Exception\ExceptionInterface
1350 protected function internalIncrementItems(array & $normalizedKeyValuePairs)
1352 $result = [];
1353 foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
1354 $newValue = $this->internalIncrementItem($normalizedKey, $value);
1355 if ($newValue !== false) {
1356 $result[$normalizedKey] = $newValue;
1359 return $result;
1363 * Decrement an item.
1365 * @param string $key
1366 * @param int $value
1367 * @return int|bool The new value on success, false on failure
1368 * @throws Exception\ExceptionInterface
1370 * @triggers decrementItem.pre(PreEvent)
1371 * @triggers decrementItem.post(PostEvent)
1372 * @triggers decrementItem.exception(ExceptionEvent)
1374 public function decrementItem($key, $value)
1376 if (! $this->getOptions()->getWritable()) {
1377 return false;
1380 $this->normalizeKey($key);
1381 $args = new ArrayObject([
1382 'key' => & $key,
1383 'value' => & $value,
1386 try {
1387 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1389 $result = $eventRs->stopped()
1390 ? $eventRs->last()
1391 : $this->internalDecrementItem($args['key'], $args['value']);
1393 return $this->triggerPost(__FUNCTION__, $args, $result);
1394 } catch (\Exception $e) {
1395 $result = false;
1396 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1401 * Internal method to decrement an item.
1403 * @param string $normalizedKey
1404 * @param int $value
1405 * @return int|bool The new value on success, false on failure
1406 * @throws Exception\ExceptionInterface
1408 protected function internalDecrementItem(& $normalizedKey, & $value)
1410 $success = null;
1411 $value = (int) $value;
1412 $get = (int) $this->internalGetItem($normalizedKey, $success);
1413 $newValue = $get - $value;
1415 if ($success) {
1416 $this->internalReplaceItem($normalizedKey, $newValue);
1417 } else {
1418 $this->internalAddItem($normalizedKey, $newValue);
1421 return $newValue;
1425 * Decrement multiple items.
1427 * @param array $keyValuePairs
1428 * @return array Associative array of keys and new values
1429 * @throws Exception\ExceptionInterface
1431 * @triggers incrementItems.pre(PreEvent)
1432 * @triggers incrementItems.post(PostEvent)
1433 * @triggers incrementItems.exception(ExceptionEvent)
1435 public function decrementItems(array $keyValuePairs)
1437 if (! $this->getOptions()->getWritable()) {
1438 return [];
1441 $this->normalizeKeyValuePairs($keyValuePairs);
1442 $args = new ArrayObject([
1443 'keyValuePairs' => & $keyValuePairs,
1446 try {
1447 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1449 $result = $eventRs->stopped()
1450 ? $eventRs->last()
1451 : $this->internalDecrementItems($args['keyValuePairs']);
1453 return $this->triggerPost(__FUNCTION__, $args, $result);
1454 } catch (\Exception $e) {
1455 $result = [];
1456 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1461 * Internal method to decrement multiple items.
1463 * @param array $normalizedKeyValuePairs
1464 * @return array Associative array of keys and new values
1465 * @throws Exception\ExceptionInterface
1467 protected function internalDecrementItems(array & $normalizedKeyValuePairs)
1469 $result = [];
1470 foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
1471 $newValue = $this->internalDecrementItem($normalizedKey, $value);
1472 if ($newValue !== false) {
1473 $result[$normalizedKey] = $newValue;
1476 return $result;
1479 /* status */
1482 * Get capabilities of this adapter
1484 * @return Capabilities
1485 * @triggers getCapabilities.pre(PreEvent)
1486 * @triggers getCapabilities.post(PostEvent)
1487 * @triggers getCapabilities.exception(ExceptionEvent)
1489 public function getCapabilities()
1491 $args = new ArrayObject();
1493 try {
1494 $eventRs = $this->triggerPre(__FUNCTION__, $args);
1496 $result = $eventRs->stopped()
1497 ? $eventRs->last()
1498 : $this->internalGetCapabilities();
1500 return $this->triggerPost(__FUNCTION__, $args, $result);
1501 } catch (\Exception $e) {
1502 $result = false;
1503 return $this->triggerException(__FUNCTION__, $args, $result, $e);
1508 * Internal method to get capabilities of this adapter
1510 * @return Capabilities
1512 protected function internalGetCapabilities()
1514 if ($this->capabilities === null) {
1515 $this->capabilityMarker = new stdClass();
1516 $this->capabilities = new Capabilities($this, $this->capabilityMarker);
1518 return $this->capabilities;
1521 /* internal */
1524 * Validates and normalizes a key
1526 * @param string $key
1527 * @return void
1528 * @throws Exception\InvalidArgumentException On an invalid key
1530 protected function normalizeKey(& $key)
1532 $key = (string) $key;
1534 if ($key === '') {
1535 throw new Exception\InvalidArgumentException(
1536 "An empty key isn't allowed"
1538 } elseif (($p = $this->getOptions()->getKeyPattern()) && ! preg_match($p, $key)) {
1539 throw new Exception\InvalidArgumentException(
1540 "The key '{$key}' doesn't match against pattern '{$p}'"
1546 * Validates and normalizes multiple keys
1548 * @param array $keys
1549 * @return void
1550 * @throws Exception\InvalidArgumentException On an invalid key
1552 protected function normalizeKeys(array & $keys)
1554 if (! $keys) {
1555 throw new Exception\InvalidArgumentException(
1556 "An empty list of keys isn't allowed"
1560 array_walk($keys, [$this, 'normalizeKey']);
1561 $keys = array_values(array_unique($keys));
1565 * Validates and normalizes an array of key-value pairs
1567 * @param array $keyValuePairs
1568 * @return void
1569 * @throws Exception\InvalidArgumentException On an invalid key
1571 protected function normalizeKeyValuePairs(array & $keyValuePairs)
1573 $normalizedKeyValuePairs = [];
1574 foreach ($keyValuePairs as $key => $value) {
1575 $this->normalizeKey($key);
1576 $normalizedKeyValuePairs[$key] = $value;
1578 $keyValuePairs = $normalizedKeyValuePairs;