Source of file AbstractAdapter.php
Size: 45,243 Bytes - Last Modified: 2014-03-12T23:21:18+01:00
/home/theseer/Downloads/ZendFramework-2.3.0/library/Zend/Cache/Storage/Adapter/AbstractAdapter.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581 | <?php /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\Cache\Storage\Adapter; use ArrayObject; use SplObjectStorage; use stdClass; use Traversable; use Zend\Cache\Exception; use Zend\Cache\Storage\Capabilities; use Zend\Cache\Storage\Event; use Zend\Cache\Storage\ExceptionEvent; use Zend\Cache\Storage\Plugin; use Zend\Cache\Storage\PostEvent; use Zend\Cache\Storage\StorageInterface; use Zend\EventManager\EventManager; use Zend\EventManager\EventManagerInterface; use Zend\EventManager\EventsCapableInterface; abstract class AbstractAdapter implements StorageInterface, EventsCapableInterface { /** * The used EventManager if any * * @var null|EventManagerInterface */ protected $events = null; /** * Event handles of this adapter * @var array */ protected $eventHandles = array(); /** * The plugin registry * * @var SplObjectStorage Registered plugins */ protected $pluginRegistry; /** * Capabilities of this adapter * * @var null|Capabilities */ protected $capabilities = null; /** * Marker to change capabilities * * @var null|object */ protected $capabilityMarker; /** * options * * @var mixed */ protected $options; /** * Constructor * * @param null|array|Traversable|AdapterOptions $options * @throws Exception\ExceptionInterface */ public function __construct($options = null) { if ($options) { $this->setOptions($options); } } /** * Destructor * * detach all registered plugins to free * event handles of event manager * * @return void */ public function __destruct() { foreach ($this->getPluginRegistry() as $plugin) { $this->removePlugin($plugin); } if ($this->eventHandles) { $events = $this->getEventManager(); foreach ($this->eventHandles as $handle) { $events->detach($handle); } } } /* configuration */ /** * Set options. * * @param array|Traversable|AdapterOptions $options * @return AbstractAdapter * @see getOptions() */ public function setOptions($options) { if ($this->options !== $options) { if (!$options instanceof AdapterOptions) { $options = new AdapterOptions($options); } if ($this->options) { $this->options->setAdapter(null); } $options->setAdapter($this); $this->options = $options; $event = new Event('option', $this, new ArrayObject($options->toArray())); $this->getEventManager()->trigger($event); } return $this; } /** * Get options. * * @return AdapterOptions * @see setOptions() */ public function getOptions() { if (!$this->options) { $this->setOptions(new AdapterOptions()); } return $this->options; } /** * Enable/Disable caching. * * Alias of setWritable and setReadable. * * @see setWritable() * @see setReadable() * @param bool $flag * @return AbstractAdapter */ public function setCaching($flag) { $flag = (bool) $flag; $options = $this->getOptions(); $options->setWritable($flag); $options->setReadable($flag); return $this; } /** * Get caching enabled. * * Alias of getWritable and getReadable. * * @see getWritable() * @see getReadable() * @return bool */ public function getCaching() { $options = $this->getOptions(); return ($options->getWritable() && $options->getReadable()); } /* Event/Plugin handling */ /** * Get the event manager * * @return EventManagerInterface */ public function getEventManager() { if ($this->events === null) { $this->events = new EventManager(array(__CLASS__, get_class($this))); } return $this->events; } /** * Trigger a pre event and return the event response collection * * @param string $eventName * @param ArrayObject $args * @return \Zend\EventManager\ResponseCollection All handler return values */ protected function triggerPre($eventName, ArrayObject $args) { return $this->getEventManager()->trigger(new Event($eventName . '.pre', $this, $args)); } /** * Triggers the PostEvent and return the result value. * * @param string $eventName * @param ArrayObject $args * @param mixed $result * @return mixed */ protected function triggerPost($eventName, ArrayObject $args, & $result) { $postEvent = new PostEvent($eventName . '.post', $this, $args, $result); $eventRs = $this->getEventManager()->trigger($postEvent); if ($eventRs->stopped()) { return $eventRs->last(); } return $postEvent->getResult(); } /** * Trigger an exception event * * If the ExceptionEvent has the flag "throwException" enabled throw the * exception after trigger else return the result. * * @param string $eventName * @param ArrayObject $args * @param mixed $result * @param \Exception $exception * @throws Exception\ExceptionInterface * @return mixed */ protected function triggerException($eventName, ArrayObject $args, & $result, \Exception $exception) { $exceptionEvent = new ExceptionEvent($eventName . '.exception', $this, $args, $result, $exception); $eventRs = $this->getEventManager()->trigger($exceptionEvent); if ($exceptionEvent->getThrowException()) { throw $exceptionEvent->getException(); } if ($eventRs->stopped()) { return $eventRs->last(); } return $exceptionEvent->getResult(); } /** * Check if a plugin is registered * * @param Plugin\PluginInterface $plugin * @return bool */ public function hasPlugin(Plugin\PluginInterface $plugin) { $registry = $this->getPluginRegistry(); return $registry->contains($plugin); } /** * Register a plugin * * @param Plugin\PluginInterface $plugin * @param int $priority * @return AbstractAdapter Fluent interface * @throws Exception\LogicException */ public function addPlugin(Plugin\PluginInterface $plugin, $priority = 1) { $registry = $this->getPluginRegistry(); if ($registry->contains($plugin)) { throw new Exception\LogicException(sprintf( 'Plugin of type "%s" already registered', get_class($plugin) )); } $plugin->attach($this->getEventManager(), $priority); $registry->attach($plugin); return $this; } /** * Unregister an already registered plugin * * @param Plugin\PluginInterface $plugin * @return AbstractAdapter Fluent interface * @throws Exception\LogicException */ public function removePlugin(Plugin\PluginInterface $plugin) { $registry = $this->getPluginRegistry(); if ($registry->contains($plugin)) { $plugin->detach($this->getEventManager()); $registry->detach($plugin); } return $this; } /** * Return registry of plugins * * @return SplObjectStorage */ public function getPluginRegistry() { if (!$this->pluginRegistry instanceof SplObjectStorage) { $this->pluginRegistry = new SplObjectStorage(); } return $this->pluginRegistry; } /* reading */ /** * Get an item. * * @param string $key * @param bool $success * @param mixed $casToken * @return mixed Data on success, null on failure * @throws Exception\ExceptionInterface * * @triggers getItem.pre(PreEvent) * @triggers getItem.post(PostEvent) * @triggers getItem.exception(ExceptionEvent) */ public function getItem($key, & $success = null, & $casToken = null) { if (!$this->getOptions()->getReadable()) { $success = false; return null; } $this->normalizeKey($key); $argn = func_num_args(); $args = array( 'key' => & $key, ); if ($argn > 1) { $args['success'] = & $success; } if ($argn > 2) { $args['casToken'] = & $casToken; } $args = new ArrayObject($args); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } if ($args->offsetExists('success') && $args->offsetExists('casToken')) { $result = $this->internalGetItem($args['key'], $args['success'], $args['casToken']); } elseif ($args->offsetExists('success')) { $result = $this->internalGetItem($args['key'], $args['success']); } else { $result = $this->internalGetItem($args['key']); } return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to get an item. * * @param string $normalizedKey * @param bool $success * @param mixed $casToken * @return mixed Data on success, null on failure * @throws Exception\ExceptionInterface */ abstract protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null); /** * Get multiple items. * * @param array $keys * @return array Associative array of keys and values * @throws Exception\ExceptionInterface * * @triggers getItems.pre(PreEvent) * @triggers getItems.post(PostEvent) * @triggers getItems.exception(ExceptionEvent) */ public function getItems(array $keys) { if (!$this->getOptions()->getReadable()) { return array(); } $this->normalizeKeys($keys); $args = new ArrayObject(array( 'keys' => & $keys, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalGetItems($args['keys']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to get multiple items. * * @param array $normalizedKeys * @return array Associative array of keys and values * @throws Exception\ExceptionInterface */ protected function internalGetItems(array & $normalizedKeys) { $success = null; $result = array(); foreach ($normalizedKeys as $normalizedKey) { $value = $this->internalGetItem($normalizedKey, $success); if ($success) { $result[$normalizedKey] = $value; } } return $result; } /** * Test if an item exists. * * @param string $key * @return bool * @throws Exception\ExceptionInterface * * @triggers hasItem.pre(PreEvent) * @triggers hasItem.post(PostEvent) * @triggers hasItem.exception(ExceptionEvent) */ public function hasItem($key) { if (!$this->getOptions()->getReadable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalHasItem($args['key']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to test if an item exists. * * @param string $normalizedKey * @return bool * @throws Exception\ExceptionInterface */ protected function internalHasItem(& $normalizedKey) { $success = null; $this->internalGetItem($normalizedKey, $success); return $success; } /** * Test multiple items. * * @param array $keys * @return array Array of found keys * @throws Exception\ExceptionInterface * * @triggers hasItems.pre(PreEvent) * @triggers hasItems.post(PostEvent) * @triggers hasItems.exception(ExceptionEvent) */ public function hasItems(array $keys) { if (!$this->getOptions()->getReadable()) { return array(); } $this->normalizeKeys($keys); $args = new ArrayObject(array( 'keys' => & $keys, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalHasItems($args['keys']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to test multiple items. * * @param array $normalizedKeys * @return array Array of found keys * @throws Exception\ExceptionInterface */ protected function internalHasItems(array & $normalizedKeys) { $result = array(); foreach ($normalizedKeys as $normalizedKey) { if ($this->internalHasItem($normalizedKey)) { $result[] = $normalizedKey; } } return $result; } /** * Get metadata of an item. * * @param string $key * @return array|bool Metadata on success, false on failure * @throws Exception\ExceptionInterface * * @triggers getMetadata.pre(PreEvent) * @triggers getMetadata.post(PostEvent) * @triggers getMetadata.exception(ExceptionEvent) */ public function getMetadata($key) { if (!$this->getOptions()->getReadable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalGetMetadata($args['key']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to get metadata of an item. * * @param string $normalizedKey * @return array|bool Metadata on success, false on failure * @throws Exception\ExceptionInterface */ protected function internalGetMetadata(& $normalizedKey) { if (!$this->internalHasItem($normalizedKey)) { return false; } return array(); } /** * Get multiple metadata * * @param array $keys * @return array Associative array of keys and metadata * @throws Exception\ExceptionInterface * * @triggers getMetadatas.pre(PreEvent) * @triggers getMetadatas.post(PostEvent) * @triggers getMetadatas.exception(ExceptionEvent) */ public function getMetadatas(array $keys) { if (!$this->getOptions()->getReadable()) { return array(); } $this->normalizeKeys($keys); $args = new ArrayObject(array( 'keys' => & $keys, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalGetMetadatas($args['keys']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to get multiple metadata * * @param array $normalizedKeys * @return array Associative array of keys and metadata * @throws Exception\ExceptionInterface */ protected function internalGetMetadatas(array & $normalizedKeys) { $result = array(); foreach ($normalizedKeys as $normalizedKey) { $metadata = $this->internalGetMetadata($normalizedKey); if ($metadata !== false) { $result[$normalizedKey] = $metadata; } } return $result; } /* writing */ /** * Store an item. * * @param string $key * @param mixed $value * @return bool * @throws Exception\ExceptionInterface * * @triggers setItem.pre(PreEvent) * @triggers setItem.post(PostEvent) * @triggers setItem.exception(ExceptionEvent) */ public function setItem($key, $value) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, 'value' => & $value, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalSetItem($args['key'], $args['value']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to store an item. * * @param string $normalizedKey * @param mixed $value * @return bool * @throws Exception\ExceptionInterface */ abstract protected function internalSetItem(& $normalizedKey, & $value); /** * Store multiple items. * * @param array $keyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface * * @triggers setItems.pre(PreEvent) * @triggers setItems.post(PostEvent) * @triggers setItems.exception(ExceptionEvent) */ public function setItems(array $keyValuePairs) { if (!$this->getOptions()->getWritable()) { return array_keys($keyValuePairs); } $this->normalizeKeyValuePairs($keyValuePairs); $args = new ArrayObject(array( 'keyValuePairs' => & $keyValuePairs, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalSetItems($args['keyValuePairs']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array_keys($keyValuePairs); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to store multiple items. * * @param array $normalizedKeyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface */ protected function internalSetItems(array & $normalizedKeyValuePairs) { $failedKeys = array(); foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { if (!$this->internalSetItem($normalizedKey, $value)) { $failedKeys[] = $normalizedKey; } } return $failedKeys; } /** * Add an item. * * @param string $key * @param mixed $value * @return bool * @throws Exception\ExceptionInterface * * @triggers addItem.pre(PreEvent) * @triggers addItem.post(PostEvent) * @triggers addItem.exception(ExceptionEvent) */ public function addItem($key, $value) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, 'value' => & $value, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalAddItem($args['key'], $args['value']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to add an item. * * @param string $normalizedKey * @param mixed $value * @return bool * @throws Exception\ExceptionInterface */ protected function internalAddItem(& $normalizedKey, & $value) { if ($this->internalHasItem($normalizedKey)) { return false; } return $this->internalSetItem($normalizedKey, $value); } /** * Add multiple items. * * @param array $keyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface * * @triggers addItems.pre(PreEvent) * @triggers addItems.post(PostEvent) * @triggers addItems.exception(ExceptionEvent) */ public function addItems(array $keyValuePairs) { if (!$this->getOptions()->getWritable()) { return array_keys($keyValuePairs); } $this->normalizeKeyValuePairs($keyValuePairs); $args = new ArrayObject(array( 'keyValuePairs' => & $keyValuePairs, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalAddItems($args['keyValuePairs']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array_keys($keyValuePairs); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to add multiple items. * * @param array $normalizedKeyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface */ protected function internalAddItems(array & $normalizedKeyValuePairs) { $result = array(); foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { if (!$this->internalAddItem($normalizedKey, $value)) { $result[] = $normalizedKey; } } return $result; } /** * Replace an existing item. * * @param string $key * @param mixed $value * @return bool * @throws Exception\ExceptionInterface * * @triggers replaceItem.pre(PreEvent) * @triggers replaceItem.post(PostEvent) * @triggers replaceItem.exception(ExceptionEvent) */ public function replaceItem($key, $value) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, 'value' => & $value, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalReplaceItem($args['key'], $args['value']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to replace an existing item. * * @param string $normalizedKey * @param mixed $value * @return bool * @throws Exception\ExceptionInterface */ protected function internalReplaceItem(& $normalizedKey, & $value) { if (!$this->internalhasItem($normalizedKey)) { return false; } return $this->internalSetItem($normalizedKey, $value); } /** * Replace multiple existing items. * * @param array $keyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface * * @triggers replaceItems.pre(PreEvent) * @triggers replaceItems.post(PostEvent) * @triggers replaceItems.exception(ExceptionEvent) */ public function replaceItems(array $keyValuePairs) { if (!$this->getOptions()->getWritable()) { return array_keys($keyValuePairs); } $this->normalizeKeyValuePairs($keyValuePairs); $args = new ArrayObject(array( 'keyValuePairs' => & $keyValuePairs, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalReplaceItems($args['keyValuePairs']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array_keys($keyValuePairs); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to replace multiple existing items. * * @param array $normalizedKeyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface */ protected function internalReplaceItems(array & $normalizedKeyValuePairs) { $result = array(); foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { if (!$this->internalReplaceItem($normalizedKey, $value)) { $result[] = $normalizedKey; } } return $result; } /** * Set an item only if token matches * * It uses the token received from getItem() to check if the item has * changed before overwriting it. * * @param mixed $token * @param string $key * @param mixed $value * @return bool * @throws Exception\ExceptionInterface * @see getItem() * @see setItem() */ public function checkAndSetItem($token, $key, $value) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'token' => & $token, 'key' => & $key, 'value' => & $value, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalCheckAndSetItem($args['token'], $args['key'], $args['value']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to set an item only if token matches * * @param mixed $token * @param string $normalizedKey * @param mixed $value * @return bool * @throws Exception\ExceptionInterface * @see getItem() * @see setItem() */ protected function internalCheckAndSetItem(& $token, & $normalizedKey, & $value) { $oldValue = $this->internalGetItem($normalizedKey); if ($oldValue !== $token) { return false; } return $this->internalSetItem($normalizedKey, $value); } /** * Reset lifetime of an item * * @param string $key * @return bool * @throws Exception\ExceptionInterface * * @triggers touchItem.pre(PreEvent) * @triggers touchItem.post(PostEvent) * @triggers touchItem.exception(ExceptionEvent) */ public function touchItem($key) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalTouchItem($args['key']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to reset lifetime of an item * * @param string $normalizedKey * @return bool * @throws Exception\ExceptionInterface */ protected function internalTouchItem(& $normalizedKey) { $success = null; $value = $this->internalGetItem($normalizedKey, $success); if (!$success) { return false; } return $this->internalReplaceItem($normalizedKey, $value); } /** * Reset lifetime of multiple items. * * @param array $keys * @return array Array of not updated keys * @throws Exception\ExceptionInterface * * @triggers touchItems.pre(PreEvent) * @triggers touchItems.post(PostEvent) * @triggers touchItems.exception(ExceptionEvent) */ public function touchItems(array $keys) { if (!$this->getOptions()->getWritable()) { return $keys; } $this->normalizeKeys($keys); $args = new ArrayObject(array( 'keys' => & $keys, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalTouchItems($args['keys']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { return $this->triggerException(__FUNCTION__, $args, $keys, $e); } } /** * Internal method to reset lifetime of multiple items. * * @param array $normalizedKeys * @return array Array of not updated keys * @throws Exception\ExceptionInterface */ protected function internalTouchItems(array & $normalizedKeys) { $result = array(); foreach ($normalizedKeys as $normalizedKey) { if (!$this->internalTouchItem($normalizedKey)) { $result[] = $normalizedKey; } } return $result; } /** * Remove an item. * * @param string $key * @return bool * @throws Exception\ExceptionInterface * * @triggers removeItem.pre(PreEvent) * @triggers removeItem.post(PostEvent) * @triggers removeItem.exception(ExceptionEvent) */ public function removeItem($key) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalRemoveItem($args['key']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to remove an item. * * @param string $normalizedKey * @return bool * @throws Exception\ExceptionInterface */ abstract protected function internalRemoveItem(& $normalizedKey); /** * Remove multiple items. * * @param array $keys * @return array Array of not removed keys * @throws Exception\ExceptionInterface * * @triggers removeItems.pre(PreEvent) * @triggers removeItems.post(PostEvent) * @triggers removeItems.exception(ExceptionEvent) */ public function removeItems(array $keys) { if (!$this->getOptions()->getWritable()) { return $keys; } $this->normalizeKeys($keys); $args = new ArrayObject(array( 'keys' => & $keys, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalRemoveItems($args['keys']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { return $this->triggerException(__FUNCTION__, $args, $keys, $e); } } /** * Internal method to remove multiple items. * * @param array $normalizedKeys * @return array Array of not removed keys * @throws Exception\ExceptionInterface */ protected function internalRemoveItems(array & $normalizedKeys) { $result = array(); foreach ($normalizedKeys as $normalizedKey) { if (!$this->internalRemoveItem($normalizedKey)) { $result[] = $normalizedKey; } } return $result; } /** * Increment an item. * * @param string $key * @param int $value * @return int|bool The new value on success, false on failure * @throws Exception\ExceptionInterface * * @triggers incrementItem.pre(PreEvent) * @triggers incrementItem.post(PostEvent) * @triggers incrementItem.exception(ExceptionEvent) */ public function incrementItem($key, $value) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, 'value' => & $value, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalIncrementItem($args['key'], $args['value']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to increment an item. * * @param string $normalizedKey * @param int $value * @return int|bool The new value on success, false on failure * @throws Exception\ExceptionInterface */ protected function internalIncrementItem(& $normalizedKey, & $value) { $success = null; $value = (int) $value; $get = (int) $this->internalGetItem($normalizedKey, $success); $newValue = $get + $value; if ($success) { $this->internalReplaceItem($normalizedKey, $newValue); } else { $this->internalAddItem($normalizedKey, $newValue); } return $newValue; } /** * Increment multiple items. * * @param array $keyValuePairs * @return array Associative array of keys and new values * @throws Exception\ExceptionInterface * * @triggers incrementItems.pre(PreEvent) * @triggers incrementItems.post(PostEvent) * @triggers incrementItems.exception(ExceptionEvent) */ public function incrementItems(array $keyValuePairs) { if (!$this->getOptions()->getWritable()) { return array(); } $this->normalizeKeyValuePairs($keyValuePairs); $args = new ArrayObject(array( 'keyValuePairs' => & $keyValuePairs, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalIncrementItems($args['keyValuePairs']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to increment multiple items. * * @param array $normalizedKeyValuePairs * @return array Associative array of keys and new values * @throws Exception\ExceptionInterface */ protected function internalIncrementItems(array & $normalizedKeyValuePairs) { $result = array(); foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { $newValue = $this->internalIncrementItem($normalizedKey, $value); if ($newValue !== false) { $result[$normalizedKey] = $newValue; } } return $result; } /** * Decrement an item. * * @param string $key * @param int $value * @return int|bool The new value on success, false on failure * @throws Exception\ExceptionInterface * * @triggers decrementItem.pre(PreEvent) * @triggers decrementItem.post(PostEvent) * @triggers decrementItem.exception(ExceptionEvent) */ public function decrementItem($key, $value) { if (!$this->getOptions()->getWritable()) { return false; } $this->normalizeKey($key); $args = new ArrayObject(array( 'key' => & $key, 'value' => & $value, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalDecrementItem($args['key'], $args['value']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to decrement an item. * * @param string $normalizedKey * @param int $value * @return int|bool The new value on success, false on failure * @throws Exception\ExceptionInterface */ protected function internalDecrementItem(& $normalizedKey, & $value) { $success = null; $value = (int) $value; $get = (int) $this->internalGetItem($normalizedKey, $success); $newValue = $get - $value; if ($success) { $this->internalReplaceItem($normalizedKey, $newValue); } else { $this->internalAddItem($normalizedKey, $newValue); } return $newValue; } /** * Decrement multiple items. * * @param array $keyValuePairs * @return array Associative array of keys and new values * @throws Exception\ExceptionInterface * * @triggers incrementItems.pre(PreEvent) * @triggers incrementItems.post(PostEvent) * @triggers incrementItems.exception(ExceptionEvent) */ public function decrementItems(array $keyValuePairs) { if (!$this->getOptions()->getWritable()) { return array(); } $this->normalizeKeyValuePairs($keyValuePairs); $args = new ArrayObject(array( 'keyValuePairs' => & $keyValuePairs, )); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalDecrementItems($args['keyValuePairs']); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = array(); return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to decrement multiple items. * * @param array $normalizedKeyValuePairs * @return array Associative array of keys and new values * @throws Exception\ExceptionInterface */ protected function internalDecrementItems(array & $normalizedKeyValuePairs) { $result = array(); foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { $newValue = $this->decrementItem($normalizedKey, $value); if ($newValue !== false) { $result[$normalizedKey] = $newValue; } } return $result; } /* status */ /** * Get capabilities of this adapter * * @return Capabilities * @triggers getCapabilities.pre(PreEvent) * @triggers getCapabilities.post(PostEvent) * @triggers getCapabilities.exception(ExceptionEvent) */ public function getCapabilities() { $args = new ArrayObject(); try { $eventRs = $this->triggerPre(__FUNCTION__, $args); if ($eventRs->stopped()) { return $eventRs->last(); } $result = $this->internalGetCapabilities(); return $this->triggerPost(__FUNCTION__, $args, $result); } catch (\Exception $e) { $result = false; return $this->triggerException(__FUNCTION__, $args, $result, $e); } } /** * Internal method to get capabilities of this adapter * * @return Capabilities */ protected function internalGetCapabilities() { if ($this->capabilities === null) { $this->capabilityMarker = new stdClass(); $this->capabilities = new Capabilities($this, $this->capabilityMarker); } return $this->capabilities; } /* internal */ /** * Validates and normalizes a key * * @param string $key * @return void * @throws Exception\InvalidArgumentException On an invalid key */ protected function normalizeKey(& $key) { $key = (string) $key; if ($key === '') { throw new Exception\InvalidArgumentException( "An empty key isn't allowed" ); } elseif (($p = $this->getOptions()->getKeyPattern()) && !preg_match($p, $key)) { throw new Exception\InvalidArgumentException( "The key '{$key}' doesn't match agains pattern '{$p}'" ); } } /** * Validates and normalizes multiple keys * * @param array $keys * @return void * @throws Exception\InvalidArgumentException On an invalid key */ protected function normalizeKeys(array & $keys) { if (!$keys) { throw new Exception\InvalidArgumentException( "An empty list of keys isn't allowed" ); } array_walk($keys, array($this, 'normalizeKey')); $keys = array_values(array_unique($keys)); } /** * Validates and normalizes an array of key-value pairs * * @param array $keyValuePairs * @return void * @throws Exception\InvalidArgumentException On an invalid key */ protected function normalizeKeyValuePairs(array & $keyValuePairs) { $normalizedKeyValuePairs = array(); foreach ($keyValuePairs as $key => $value) { $this->normalizeKey($key); $normalizedKeyValuePairs[$key] = $value; } $keyValuePairs = $normalizedKeyValuePairs; } } |