vendor/symfony/symfony/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php line 161

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\Adapter;
  11. use Psr\Cache\CacheItemInterface;
  12. use Psr\Log\LoggerAwareInterface;
  13. use Psr\Log\LoggerInterface;
  14. use Symfony\Component\Cache\CacheItem;
  15. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  16. use Symfony\Component\Cache\ResettableInterface;
  17. use Symfony\Component\Cache\Traits\AbstractTrait;
  18. /**
  19.  * @author Nicolas Grekas <p@tchwork.com>
  20.  */
  21. abstract class AbstractAdapter implements AdapterInterfaceLoggerAwareInterfaceResettableInterface
  22. {
  23.     /**
  24.      * @internal
  25.      */
  26.     const NS_SEPARATOR ':';
  27.     use AbstractTrait;
  28.     private static $apcuSupported;
  29.     private static $phpFilesSupported;
  30.     private $createCacheItem;
  31.     private $mergeByLifetime;
  32.     /**
  33.      * @param string $namespace
  34.      * @param int    $defaultLifetime
  35.      */
  36.     protected function __construct($namespace ''$defaultLifetime 0)
  37.     {
  38.         $this->namespace '' === $namespace '' CacheItem::validateKey($namespace).static::NS_SEPARATOR;
  39.         if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength 24) {
  40.             throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").'$this->maxIdLength 24, \strlen($namespace), $namespace));
  41.         }
  42.         $this->createCacheItem = \Closure::bind(
  43.             static function ($key$value$isHit) {
  44.                 $item = new CacheItem();
  45.                 $item->key $key;
  46.                 $item->value $value;
  47.                 $item->isHit $isHit;
  48.                 return $item;
  49.             },
  50.             null,
  51.             CacheItem::class
  52.         );
  53.         $getId = function ($key) { return $this->getId((string) $key); };
  54.         $this->mergeByLifetime = \Closure::bind(
  55.             static function ($deferred$namespace, &$expiredIds) use ($getId$defaultLifetime) {
  56.                 $byLifetime = [];
  57.                 $now time();
  58.                 $expiredIds = [];
  59.                 foreach ($deferred as $key => $item) {
  60.                     if (null === $item->expiry) {
  61.                         $byLifetime[$defaultLifetime $defaultLifetime 0][$getId($key)] = $item->value;
  62.                     } elseif (=== $item->expiry) {
  63.                         $byLifetime[0][$getId($key)] = $item->value;
  64.                     } elseif ($item->expiry $now) {
  65.                         $byLifetime[$item->expiry $now][$getId($key)] = $item->value;
  66.                     } else {
  67.                         $expiredIds[] = $getId($key);
  68.                     }
  69.                 }
  70.                 return $byLifetime;
  71.             },
  72.             null,
  73.             CacheItem::class
  74.         );
  75.     }
  76.     /**
  77.      * @param string $namespace
  78.      * @param int    $defaultLifetime
  79.      * @param string $version
  80.      * @param string $directory
  81.      *
  82.      * @return AdapterInterface
  83.      */
  84.     public static function createSystemCache($namespace$defaultLifetime$version$directoryLoggerInterface $logger null)
  85.     {
  86.         if (null === self::$apcuSupported) {
  87.             self::$apcuSupported ApcuAdapter::isSupported();
  88.         }
  89.         if (!self::$apcuSupported && null === self::$phpFilesSupported) {
  90.             self::$phpFilesSupported PhpFilesAdapter::isSupported();
  91.         }
  92.         if (self::$phpFilesSupported) {
  93.             $opcache = new PhpFilesAdapter($namespace$defaultLifetime$directory);
  94.             if (null !== $logger) {
  95.                 $opcache->setLogger($logger);
  96.             }
  97.             return $opcache;
  98.         }
  99.         $fs = new FilesystemAdapter($namespace$defaultLifetime$directory);
  100.         if (null !== $logger) {
  101.             $fs->setLogger($logger);
  102.         }
  103.         if (!self::$apcuSupported || (\in_array(\PHP_SAPI, ['cli''phpdbg'], true) && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) {
  104.             return $fs;
  105.         }
  106.         $apcu = new ApcuAdapter($namespace, (int) $defaultLifetime 5$version);
  107.         if (null !== $logger) {
  108.             $apcu->setLogger($logger);
  109.         }
  110.         return new ChainAdapter([$apcu$fs]);
  111.     }
  112.     public static function createConnection($dsn, array $options = [])
  113.     {
  114.         if (!\is_string($dsn)) {
  115.             throw new InvalidArgumentException(sprintf('The "%s()" method expect argument #1 to be string, "%s" given.'__METHOD__, \gettype($dsn)));
  116.         }
  117.         if (=== strpos($dsn'redis://')) {
  118.             return RedisAdapter::createConnection($dsn$options);
  119.         }
  120.         if (=== strpos($dsn'memcached://')) {
  121.             return MemcachedAdapter::createConnection($dsn$options);
  122.         }
  123.         throw new InvalidArgumentException(sprintf('Unsupported DSN: "%s".'$dsn));
  124.     }
  125.     /**
  126.      * {@inheritdoc}
  127.      */
  128.     public function getItem($key)
  129.     {
  130.         if ($this->deferred) {
  131.             $this->commit();
  132.         }
  133.         $id $this->getId($key);
  134.         $f $this->createCacheItem;
  135.         $isHit false;
  136.         $value null;
  137.         try {
  138.             foreach ($this->doFetch([$id]) as $value) {
  139.                 $isHit true;
  140.             }
  141.         } catch (\Exception $e) {
  142.             CacheItem::log($this->logger'Failed to fetch key "{key}"', ['key' => $key'exception' => $e]);
  143.         }
  144.         return $f($key$value$isHit);
  145.     }
  146.     /**
  147.      * {@inheritdoc}
  148.      */
  149.     public function getItems(array $keys = [])
  150.     {
  151.         if ($this->deferred) {
  152.             $this->commit();
  153.         }
  154.         $ids = [];
  155.         foreach ($keys as $key) {
  156.             $ids[] = $this->getId($key);
  157.         }
  158.         try {
  159.             $items $this->doFetch($ids);
  160.         } catch (\Exception $e) {
  161.             CacheItem::log($this->logger'Failed to fetch requested items', ['keys' => $keys'exception' => $e]);
  162.             $items = [];
  163.         }
  164.         $ids array_combine($ids$keys);
  165.         return $this->generateItems($items$ids);
  166.     }
  167.     /**
  168.      * {@inheritdoc}
  169.      */
  170.     public function save(CacheItemInterface $item)
  171.     {
  172.         if (!$item instanceof CacheItem) {
  173.             return false;
  174.         }
  175.         $this->deferred[$item->getKey()] = $item;
  176.         return $this->commit();
  177.     }
  178.     /**
  179.      * {@inheritdoc}
  180.      */
  181.     public function saveDeferred(CacheItemInterface $item)
  182.     {
  183.         if (!$item instanceof CacheItem) {
  184.             return false;
  185.         }
  186.         $this->deferred[$item->getKey()] = $item;
  187.         return true;
  188.     }
  189.     /**
  190.      * {@inheritdoc}
  191.      */
  192.     public function commit()
  193.     {
  194.         $ok true;
  195.         $byLifetime $this->mergeByLifetime;
  196.         $byLifetime $byLifetime($this->deferred$this->namespace$expiredIds);
  197.         $retry $this->deferred = [];
  198.         if ($expiredIds) {
  199.             $this->doDelete($expiredIds);
  200.         }
  201.         foreach ($byLifetime as $lifetime => $values) {
  202.             try {
  203.                 $e $this->doSave($values$lifetime);
  204.             } catch (\Exception $e) {
  205.             }
  206.             if (true === $e || [] === $e) {
  207.                 continue;
  208.             }
  209.             if (\is_array($e) || === \count($values)) {
  210.                 foreach (\is_array($e) ? $e array_keys($values) as $id) {
  211.                     $ok false;
  212.                     $v $values[$id];
  213.                     $type = \is_object($v) ? \get_class($v) : \gettype($v);
  214.                     CacheItem::log($this->logger'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type'exception' => $e instanceof \Exception $e null]);
  215.                 }
  216.             } else {
  217.                 foreach ($values as $id => $v) {
  218.                     $retry[$lifetime][] = $id;
  219.                 }
  220.             }
  221.         }
  222.         // When bulk-save failed, retry each item individually
  223.         foreach ($retry as $lifetime => $ids) {
  224.             foreach ($ids as $id) {
  225.                 try {
  226.                     $v $byLifetime[$lifetime][$id];
  227.                     $e $this->doSave([$id => $v], $lifetime);
  228.                 } catch (\Exception $e) {
  229.                 }
  230.                 if (true === $e || [] === $e) {
  231.                     continue;
  232.                 }
  233.                 $ok false;
  234.                 $type = \is_object($v) ? \get_class($v) : \gettype($v);
  235.                 CacheItem::log($this->logger'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type'exception' => $e instanceof \Exception $e null]);
  236.             }
  237.         }
  238.         return $ok;
  239.     }
  240.     public function __sleep()
  241.     {
  242.         throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  243.     }
  244.     public function __wakeup()
  245.     {
  246.         throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  247.     }
  248.     public function __destruct()
  249.     {
  250.         if ($this->deferred) {
  251.             $this->commit();
  252.         }
  253.     }
  254.     private function generateItems($items, &$keys)
  255.     {
  256.         $f $this->createCacheItem;
  257.         try {
  258.             foreach ($items as $id => $value) {
  259.                 if (!isset($keys[$id])) {
  260.                     $id key($keys);
  261.                 }
  262.                 $key $keys[$id];
  263.                 unset($keys[$id]);
  264.                 yield $key => $f($key$valuetrue);
  265.             }
  266.         } catch (\Exception $e) {
  267.             CacheItem::log($this->logger'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]);
  268.         }
  269.         foreach ($keys as $key) {
  270.             yield $key => $f($keynullfalse);
  271.         }
  272.     }
  273. }