| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 | 
							- <?php
 
- /*
 
-  * This file is part of php-cache organization.
 
-  *
 
-  * (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
 
-  *
 
-  * This source file is subject to the MIT license that is bundled
 
-  * with this source code in the file LICENSE.
 
-  */
 
- namespace Cache\Adapter\Common;
 
- use Cache\Adapter\Common\Exception\CacheException;
 
- use Cache\Adapter\Common\Exception\CachePoolException;
 
- use Cache\Adapter\Common\Exception\InvalidArgumentException;
 
- use Psr\Cache\CacheItemInterface;
 
- use Psr\Log\LoggerAwareInterface;
 
- use Psr\Log\LoggerInterface;
 
- use Psr\SimpleCache\CacheInterface;
 
- /**
 
-  * @author Aaron Scherer <aequasi@gmail.com>
 
-  * @author Tobias Nyholm <tobias.nyholm@gmail.com>
 
-  */
 
- abstract class AbstractCachePool implements PhpCachePool, LoggerAwareInterface, CacheInterface
 
- {
 
-     const SEPARATOR_TAG = '!';
 
-     /**
 
-      * @type LoggerInterface
 
-      */
 
-     private $logger;
 
-     /**
 
-      * @type PhpCacheItem[] deferred
 
-      */
 
-     protected $deferred = [];
 
-     /**
 
-      * @param PhpCacheItem $item
 
-      * @param int|null     $ttl  seconds from now
 
-      *
 
-      * @return bool true if saved
 
-      */
 
-     abstract protected function storeItemInCache(PhpCacheItem $item, $ttl);
 
-     /**
 
-      * Fetch an object from the cache implementation.
 
-      *
 
-      * If it is a cache miss, it MUST return [false, null, [], null]
 
-      *
 
-      * @param string $key
 
-      *
 
-      * @return array with [isHit, value, tags[], expirationTimestamp]
 
-      */
 
-     abstract protected function fetchObjectFromCache($key);
 
-     /**
 
-      * Clear all objects from cache.
 
-      *
 
-      * @return bool false if error
 
-      */
 
-     abstract protected function clearAllObjectsFromCache();
 
-     /**
 
-      * Remove one object from cache.
 
-      *
 
-      * @param string $key
 
-      *
 
-      * @return bool
 
-      */
 
-     abstract protected function clearOneObjectFromCache($key);
 
-     /**
 
-      * Get an array with all the values in the list named $name.
 
-      *
 
-      * @param string $name
 
-      *
 
-      * @return array
 
-      */
 
-     abstract protected function getList($name);
 
-     /**
 
-      * Remove the list.
 
-      *
 
-      * @param string $name
 
-      *
 
-      * @return bool
 
-      */
 
-     abstract protected function removeList($name);
 
-     /**
 
-      * Add a item key on a list named $name.
 
-      *
 
-      * @param string $name
 
-      * @param string $key
 
-      */
 
-     abstract protected function appendListItem($name, $key);
 
-     /**
 
-      * Remove an item from the list.
 
-      *
 
-      * @param string $name
 
-      * @param string $key
 
-      */
 
-     abstract protected function removeListItem($name, $key);
 
-     /**
 
-      * Make sure to commit before we destruct.
 
-      */
 
-     public function __destruct()
 
-     {
 
-         $this->commit();
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function getItem($key)
 
-     {
 
-         $this->validateKey($key);
 
-         if (isset($this->deferred[$key])) {
 
-             /** @type CacheItem $item */
 
-             $item = clone $this->deferred[$key];
 
-             $item->moveTagsToPrevious();
 
-             return $item;
 
-         }
 
-         $func = function () use ($key) {
 
-             try {
 
-                 return $this->fetchObjectFromCache($key);
 
-             } catch (\Exception $e) {
 
-                 $this->handleException($e, __FUNCTION__);
 
-             }
 
-         };
 
-         return new CacheItem($key, $func);
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function getItems(array $keys = [])
 
-     {
 
-         $items = [];
 
-         foreach ($keys as $key) {
 
-             $items[$key] = $this->getItem($key);
 
-         }
 
-         return $items;
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function hasItem($key)
 
-     {
 
-         try {
 
-             return $this->getItem($key)->isHit();
 
-         } catch (\Exception $e) {
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function clear()
 
-     {
 
-         // Clear the deferred items
 
-         $this->deferred = [];
 
-         try {
 
-             return $this->clearAllObjectsFromCache();
 
-         } catch (\Exception $e) {
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function deleteItem($key)
 
-     {
 
-         try {
 
-             return $this->deleteItems([$key]);
 
-         } catch (\Exception $e) {
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function deleteItems(array $keys)
 
-     {
 
-         $deleted = true;
 
-         foreach ($keys as $key) {
 
-             $this->validateKey($key);
 
-             // Delete form deferred
 
-             unset($this->deferred[$key]);
 
-             // We have to commit here to be able to remove deferred hierarchy items
 
-             $this->commit();
 
-             $this->preRemoveItem($key);
 
-             if (!$this->clearOneObjectFromCache($key)) {
 
-                 $deleted = false;
 
-             }
 
-         }
 
-         return $deleted;
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function save(CacheItemInterface $item)
 
-     {
 
-         if (!$item instanceof PhpCacheItem) {
 
-             $e = new InvalidArgumentException('Cache items are not transferable between pools. Item MUST implement PhpCacheItem.');
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-         $this->removeTagEntries($item);
 
-         $this->saveTags($item);
 
-         $timeToLive = null;
 
-         if (null !== $timestamp = $item->getExpirationTimestamp()) {
 
-             $timeToLive = $timestamp - time();
 
-             if ($timeToLive < 0) {
 
-                 return $this->deleteItem($item->getKey());
 
-             }
 
-         }
 
-         try {
 
-             return $this->storeItemInCache($item, $timeToLive);
 
-         } catch (\Exception $e) {
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function saveDeferred(CacheItemInterface $item)
 
-     {
 
-         $this->deferred[$item->getKey()] = $item;
 
-         return true;
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function commit()
 
-     {
 
-         $saved = true;
 
-         foreach ($this->deferred as $item) {
 
-             if (!$this->save($item)) {
 
-                 $saved = false;
 
-             }
 
-         }
 
-         $this->deferred = [];
 
-         return $saved;
 
-     }
 
-     /**
 
-      * @param string $key
 
-      *
 
-      * @throws InvalidArgumentException
 
-      */
 
-     protected function validateKey($key)
 
-     {
 
-         if (!is_string($key)) {
 
-             $e = new InvalidArgumentException(sprintf(
 
-                 'Cache key must be string, "%s" given', gettype($key)
 
-             ));
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-         if (!isset($key[0])) {
 
-             $e = new InvalidArgumentException('Cache key cannot be an empty string');
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-         if (preg_match('|[\{\}\(\)/\\\@\:]|', $key)) {
 
-             $e = new InvalidArgumentException(sprintf(
 
-                 'Invalid key: "%s". The key contains one or more characters reserved for future extension: {}()/\@:',
 
-                 $key
 
-             ));
 
-             $this->handleException($e, __FUNCTION__);
 
-         }
 
-     }
 
-     /**
 
-      * @param LoggerInterface $logger
 
-      */
 
-     public function setLogger(LoggerInterface $logger)
 
-     {
 
-         $this->logger = $logger;
 
-     }
 
-     /**
 
-      * Logs with an arbitrary level if the logger exists.
 
-      *
 
-      * @param mixed  $level
 
-      * @param string $message
 
-      * @param array  $context
 
-      */
 
-     protected function log($level, $message, array $context = [])
 
-     {
 
-         if ($this->logger !== null) {
 
-             $this->logger->log($level, $message, $context);
 
-         }
 
-     }
 
-     /**
 
-      * Log exception and rethrow it.
 
-      *
 
-      * @param \Exception $e
 
-      * @param string     $function
 
-      *
 
-      * @throws CachePoolException
 
-      */
 
-     private function handleException(\Exception $e, $function)
 
-     {
 
-         $level = 'alert';
 
-         if ($e instanceof InvalidArgumentException) {
 
-             $level = 'warning';
 
-         }
 
-         $this->log($level, $e->getMessage(), ['exception' => $e]);
 
-         if (!$e instanceof CacheException) {
 
-             $e = new CachePoolException(sprintf('Exception thrown when executing "%s". ', $function), 0, $e);
 
-         }
 
-         throw $e;
 
-     }
 
-     /**
 
-      * @param array $tags
 
-      *
 
-      * @return bool
 
-      */
 
-     public function invalidateTags(array $tags)
 
-     {
 
-         $itemIds = [];
 
-         foreach ($tags as $tag) {
 
-             $itemIds = array_merge($itemIds, $this->getList($this->getTagKey($tag)));
 
-         }
 
-         // Remove all items with the tag
 
-         $success = $this->deleteItems($itemIds);
 
-         if ($success) {
 
-             // Remove the tag list
 
-             foreach ($tags as $tag) {
 
-                 $this->removeList($this->getTagKey($tag));
 
-                 $l = $this->getList($this->getTagKey($tag));
 
-             }
 
-         }
 
-         return $success;
 
-     }
 
-     public function invalidateTag($tag)
 
-     {
 
-         return $this->invalidateTags([$tag]);
 
-     }
 
-     /**
 
-      * @param PhpCacheItem $item
 
-      */
 
-     protected function saveTags(PhpCacheItem $item)
 
-     {
 
-         $tags = $item->getTags();
 
-         foreach ($tags as $tag) {
 
-             $this->appendListItem($this->getTagKey($tag), $item->getKey());
 
-         }
 
-     }
 
-     /**
 
-      * Removes the key form all tag lists. When an item with tags is removed
 
-      * we MUST remove the tags. If we fail to remove the tags a new item with
 
-      * the same key will automatically get the previous tags.
 
-      *
 
-      * @param string $key
 
-      *
 
-      * @return $this
 
-      */
 
-     protected function preRemoveItem($key)
 
-     {
 
-         $item = $this->getItem($key);
 
-         $this->removeTagEntries($item);
 
-         return $this;
 
-     }
 
-     /**
 
-      * @param PhpCacheItem $item
 
-      */
 
-     private function removeTagEntries(PhpCacheItem $item)
 
-     {
 
-         $tags = $item->getPreviousTags();
 
-         foreach ($tags as $tag) {
 
-             $this->removeListItem($this->getTagKey($tag), $item->getKey());
 
-         }
 
-     }
 
-     /**
 
-      * @param string $tag
 
-      *
 
-      * @return string
 
-      */
 
-     protected function getTagKey($tag)
 
-     {
 
-         return 'tag'.self::SEPARATOR_TAG.$tag;
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function get($key, $default = null)
 
-     {
 
-         $item = $this->getItem($key);
 
-         if (!$item->isHit()) {
 
-             return $default;
 
-         }
 
-         return $item->get();
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function set($key, $value, $ttl = null)
 
-     {
 
-         $item = $this->getItem($key);
 
-         $item->set($value);
 
-         $item->expiresAfter($ttl);
 
-         return $this->save($item);
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function delete($key)
 
-     {
 
-         return $this->deleteItem($key);
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function getMultiple($keys, $default = null)
 
-     {
 
-         if (!is_array($keys)) {
 
-             if (!$keys instanceof \Traversable) {
 
-                 throw new InvalidArgumentException('$keys is neither an array nor Traversable');
 
-             }
 
-             // Since we need to throw an exception if *any* key is invalid, it doesn't
 
-             // make sense to wrap iterators or something like that.
 
-             $keys = iterator_to_array($keys, false);
 
-         }
 
-         $items = $this->getItems($keys);
 
-         return $this->generateValues($default, $items);
 
-     }
 
-     /**
 
-      * @param $default
 
-      * @param $items
 
-      *
 
-      * @return \Generator
 
-      */
 
-     private function generateValues($default, $items)
 
-     {
 
-         foreach ($items as $key => $item) {
 
-             /** @type $item CacheItemInterface */
 
-             if (!$item->isHit()) {
 
-                 yield $key => $default;
 
-             } else {
 
-                 yield $key => $item->get();
 
-             }
 
-         }
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function setMultiple($values, $ttl = null)
 
-     {
 
-         if (!is_array($values)) {
 
-             if (!$values instanceof \Traversable) {
 
-                 throw new InvalidArgumentException('$values is neither an array nor Traversable');
 
-             }
 
-         }
 
-         $keys        = [];
 
-         $arrayValues = [];
 
-         foreach ($values as $key => $value) {
 
-             if (is_int($key)) {
 
-                 $key = (string) $key;
 
-             }
 
-             $this->validateKey($key);
 
-             $keys[]            = $key;
 
-             $arrayValues[$key] = $value;
 
-         }
 
-         $items       = $this->getItems($keys);
 
-         $itemSuccess = true;
 
-         foreach ($items as $key => $item) {
 
-             $item->set($arrayValues[$key]);
 
-             try {
 
-                 $item->expiresAfter($ttl);
 
-             } catch (InvalidArgumentException $e) {
 
-                 throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
 
-             }
 
-             $itemSuccess = $itemSuccess && $this->saveDeferred($item);
 
-         }
 
-         return $itemSuccess && $this->commit();
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function deleteMultiple($keys)
 
-     {
 
-         if (!is_array($keys)) {
 
-             if (!$keys instanceof \Traversable) {
 
-                 throw new InvalidArgumentException('$keys is neither an array nor Traversable');
 
-             }
 
-             // Since we need to throw an exception if *any* key is invalid, it doesn't
 
-             // make sense to wrap iterators or something like that.
 
-             $keys = iterator_to_array($keys, false);
 
-         }
 
-         return $this->deleteItems($keys);
 
-     }
 
-     /**
 
-      * {@inheritdoc}
 
-      */
 
-     public function has($key)
 
-     {
 
-         return $this->hasItem($key);
 
-     }
 
- }
 
 
  |