vendor/symfony/symfony/src/Symfony/Component/Cache/Traits/AbstractTrait.php line 222

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Cache\Traits;
  11. use Psr\Log\LoggerAwareTrait;
  12. use Symfony\Component\Cache\CacheItem;
  13. /**
  14.  * @author Nicolas Grekas <p@tchwork.com>
  15.  *
  16.  * @internal
  17.  */
  18. trait AbstractTrait
  19. {
  20.     use LoggerAwareTrait;
  21.     private $namespace;
  22.     private $namespaceVersion '';
  23.     private $versioningIsEnabled false;
  24.     private $deferred = [];
  25.     /**
  26.      * @var int|null The maximum length to enforce for identifiers or null when no limit applies
  27.      */
  28.     protected $maxIdLength;
  29.     /**
  30.      * Fetches several cache items.
  31.      *
  32.      * @param array $ids The cache identifiers to fetch
  33.      *
  34.      * @return array|\Traversable The corresponding values found in the cache
  35.      */
  36.     abstract protected function doFetch(array $ids);
  37.     /**
  38.      * Confirms if the cache contains specified cache item.
  39.      *
  40.      * @param string $id The identifier for which to check existence
  41.      *
  42.      * @return bool True if item exists in the cache, false otherwise
  43.      */
  44.     abstract protected function doHave($id);
  45.     /**
  46.      * Deletes all items in the pool.
  47.      *
  48.      * @param string $namespace The prefix used for all identifiers managed by this pool
  49.      *
  50.      * @return bool True if the pool was successfully cleared, false otherwise
  51.      */
  52.     abstract protected function doClear($namespace);
  53.     /**
  54.      * Removes multiple items from the pool.
  55.      *
  56.      * @param array $ids An array of identifiers that should be removed from the pool
  57.      *
  58.      * @return bool True if the items were successfully removed, false otherwise
  59.      */
  60.     abstract protected function doDelete(array $ids);
  61.     /**
  62.      * Persists several cache items immediately.
  63.      *
  64.      * @param array $values   The values to cache, indexed by their cache identifier
  65.      * @param int   $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
  66.      *
  67.      * @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not
  68.      */
  69.     abstract protected function doSave(array $values$lifetime);
  70.     /**
  71.      * {@inheritdoc}
  72.      */
  73.     public function hasItem($key)
  74.     {
  75.         $id $this->getId($key);
  76.         if (isset($this->deferred[$key])) {
  77.             $this->commit();
  78.         }
  79.         try {
  80.             return $this->doHave($id);
  81.         } catch (\Exception $e) {
  82.             CacheItem::log($this->logger'Failed to check if key "{key}" is cached', ['key' => $key'exception' => $e]);
  83.             return false;
  84.         }
  85.     }
  86.     /**
  87.      * {@inheritdoc}
  88.      */
  89.     public function clear()
  90.     {
  91.         $this->deferred = [];
  92.         if ($cleared $this->versioningIsEnabled) {
  93.             $namespaceVersion substr_replace(base64_encode(pack('V'mt_rand())), static::NS_SEPARATOR5);
  94.             try {
  95.                 $cleared $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0);
  96.             } catch (\Exception $e) {
  97.                 $cleared false;
  98.             }
  99.             if ($cleared true === $cleared || [] === $cleared) {
  100.                 $this->namespaceVersion $namespaceVersion;
  101.             }
  102.         }
  103.         try {
  104.             return $this->doClear($this->namespace) || $cleared;
  105.         } catch (\Exception $e) {
  106.             CacheItem::log($this->logger'Failed to clear the cache', ['exception' => $e]);
  107.             return false;
  108.         }
  109.     }
  110.     /**
  111.      * {@inheritdoc}
  112.      */
  113.     public function deleteItem($key)
  114.     {
  115.         return $this->deleteItems([$key]);
  116.     }
  117.     /**
  118.      * {@inheritdoc}
  119.      */
  120.     public function deleteItems(array $keys)
  121.     {
  122.         $ids = [];
  123.         foreach ($keys as $key) {
  124.             $ids[$key] = $this->getId($key);
  125.             unset($this->deferred[$key]);
  126.         }
  127.         try {
  128.             if ($this->doDelete($ids)) {
  129.                 return true;
  130.             }
  131.         } catch (\Exception $e) {
  132.         }
  133.         $ok true;
  134.         // When bulk-delete failed, retry each item individually
  135.         foreach ($ids as $key => $id) {
  136.             try {
  137.                 $e null;
  138.                 if ($this->doDelete([$id])) {
  139.                     continue;
  140.                 }
  141.             } catch (\Exception $e) {
  142.             }
  143.             CacheItem::log($this->logger'Failed to delete key "{key}"', ['key' => $key'exception' => $e]);
  144.             $ok false;
  145.         }
  146.         return $ok;
  147.     }
  148.     /**
  149.      * Enables/disables versioning of items.
  150.      *
  151.      * When versioning is enabled, clearing the cache is atomic and doesn't require listing existing keys to proceed,
  152.      * but old keys may need garbage collection and extra round-trips to the back-end are required.
  153.      *
  154.      * Calling this method also clears the memoized namespace version and thus forces a resynchonization of it.
  155.      *
  156.      * @param bool $enable
  157.      *
  158.      * @return bool the previous state of versioning
  159.      */
  160.     public function enableVersioning($enable true)
  161.     {
  162.         $wasEnabled $this->versioningIsEnabled;
  163.         $this->versioningIsEnabled = (bool) $enable;
  164.         $this->namespaceVersion '';
  165.         return $wasEnabled;
  166.     }
  167.     /**
  168.      * {@inheritdoc}
  169.      */
  170.     public function reset()
  171.     {
  172.         if ($this->deferred) {
  173.             $this->commit();
  174.         }
  175.         $this->namespaceVersion '';
  176.     }
  177.     /**
  178.      * Like the native unserialize() function but throws an exception if anything goes wrong.
  179.      *
  180.      * @param string $value
  181.      *
  182.      * @return mixed
  183.      *
  184.      * @throws \Exception
  185.      */
  186.     protected static function unserialize($value)
  187.     {
  188.         if ('b:0;' === $value) {
  189.             return false;
  190.         }
  191.         $unserializeCallbackHandler ini_set('unserialize_callback_func'__CLASS__.'::handleUnserializeCallback');
  192.         try {
  193.             if (false !== $value unserialize($value)) {
  194.                 return $value;
  195.             }
  196.             throw new \DomainException('Failed to unserialize cached value.');
  197.         } catch (\Error $e) {
  198.             throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR$e->getFile(), $e->getLine());
  199.         } finally {
  200.             ini_set('unserialize_callback_func'$unserializeCallbackHandler);
  201.         }
  202.     }
  203.     private function getId($key)
  204.     {
  205.         CacheItem::validateKey($key);
  206.         if ($this->versioningIsEnabled && '' === $this->namespaceVersion) {
  207.             $this->namespaceVersion '1'.static::NS_SEPARATOR;
  208.             try {
  209.                 foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) {
  210.                     $this->namespaceVersion $v;
  211.                 }
  212.                 if ('1'.static::NS_SEPARATOR === $this->namespaceVersion) {
  213.                     $this->namespaceVersion substr_replace(base64_encode(pack('V'time())), static::NS_SEPARATOR5);
  214.                     $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0);
  215.                 }
  216.             } catch (\Exception $e) {
  217.             }
  218.         }
  219.         if (null === $this->maxIdLength) {
  220.             return $this->namespace.$this->namespaceVersion.$key;
  221.         }
  222.         if (\strlen($id $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) {
  223.             $id $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256'$keytrue)), static::NS_SEPARATOR, -(\strlen($this->namespaceVersion) + 22));
  224.         }
  225.         return $id;
  226.     }
  227.     /**
  228.      * @internal
  229.      */
  230.     public static function handleUnserializeCallback($class)
  231.     {
  232.         throw new \DomainException('Class not found: '.$class);
  233.     }
  234. }