vendor/symfony/cache/Adapter/AbstractAdapter.php line 160

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\Log\LoggerAwareInterface;
  12. use Psr\Log\LoggerInterface;
  13. use Symfony\Component\Cache\CacheItem;
  14. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  15. use Symfony\Component\Cache\ResettableInterface;
  16. use Symfony\Component\Cache\Traits\AbstractAdapterTrait;
  17. use Symfony\Component\Cache\Traits\ContractsTrait;
  18. use Symfony\Contracts\Cache\CacheInterface;
  19. /**
  20.  * @author Nicolas Grekas <p@tchwork.com>
  21.  */
  22. abstract class AbstractAdapter implements AdapterInterfaceCacheInterfaceLoggerAwareInterfaceResettableInterface
  23. {
  24.     use AbstractAdapterTrait;
  25.     use ContractsTrait;
  26.     /**
  27.      * @internal
  28.      */
  29.     protected const NS_SEPARATOR ':';
  30.     private static $apcuSupported;
  31.     private static $phpFilesSupported;
  32.     protected function __construct(string $namespace ''int $defaultLifetime 0)
  33.     {
  34.         $this->namespace '' === $namespace '' CacheItem::validateKey($namespace).static::NS_SEPARATOR;
  35.         $this->defaultLifetime $defaultLifetime;
  36.         if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength 24) {
  37.             throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").'$this->maxIdLength 24\strlen($namespace), $namespace));
  38.         }
  39.         self::$createCacheItem ??= \Closure::bind(
  40.             static function ($key$value$isHit) {
  41.                 $item = new CacheItem();
  42.                 $item->key $key;
  43.                 $item->value $v $value;
  44.                 $item->isHit $isHit;
  45.                 $item->unpack();
  46.                 return $item;
  47.             },
  48.             null,
  49.             CacheItem::class
  50.         );
  51.         self::$mergeByLifetime ??= \Closure::bind(
  52.             static function ($deferred$namespace, &$expiredIds$getId$defaultLifetime) {
  53.                 $byLifetime = [];
  54.                 $now microtime(true);
  55.                 $expiredIds = [];
  56.                 foreach ($deferred as $key => $item) {
  57.                     $key = (string) $key;
  58.                     if (null === $item->expiry) {
  59.                         $ttl $defaultLifetime $defaultLifetime 0;
  60.                     } elseif (!$item->expiry) {
  61.                         $ttl 0;
  62.                     } elseif (>= $ttl = (int) (0.1 $item->expiry $now)) {
  63.                         $expiredIds[] = $getId($key);
  64.                         continue;
  65.                     }
  66.                     $byLifetime[$ttl][$getId($key)] = $item->pack();
  67.                 }
  68.                 return $byLifetime;
  69.             },
  70.             null,
  71.             CacheItem::class
  72.         );
  73.     }
  74.     /**
  75.      * Returns the best possible adapter that your runtime supports.
  76.      *
  77.      * Using ApcuAdapter makes system caches compatible with read-only filesystems.
  78.      */
  79.     public static function createSystemCache(string $namespaceint $defaultLifetimestring $versionstring $directoryLoggerInterface $logger null): AdapterInterface
  80.     {
  81.         $opcache = new PhpFilesAdapter($namespace$defaultLifetime$directorytrue);
  82.         if (null !== $logger) {
  83.             $opcache->setLogger($logger);
  84.         }
  85.         if (!self::$apcuSupported ??= ApcuAdapter::isSupported()) {
  86.             return $opcache;
  87.         }
  88.         if (\in_array(\PHP_SAPI, ['cli''phpdbg'], true) && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOL)) {
  89.             return $opcache;
  90.         }
  91.         $apcu = new ApcuAdapter($namespaceintdiv($defaultLifetime5), $version);
  92.         if (null !== $logger) {
  93.             $apcu->setLogger($logger);
  94.         }
  95.         return new ChainAdapter([$apcu$opcache]);
  96.     }
  97.     public static function createConnection(string $dsn, array $options = [])
  98.     {
  99.         if (str_starts_with($dsn'redis:') || str_starts_with($dsn'rediss:')) {
  100.             return RedisAdapter::createConnection($dsn$options);
  101.         }
  102.         if (str_starts_with($dsn'memcached:')) {
  103.             return MemcachedAdapter::createConnection($dsn$options);
  104.         }
  105.         if (str_starts_with($dsn'couchbase:')) {
  106.             if (CouchbaseBucketAdapter::isSupported()) {
  107.                 return CouchbaseBucketAdapter::createConnection($dsn$options);
  108.             }
  109.             return CouchbaseCollectionAdapter::createConnection($dsn$options);
  110.         }
  111.         throw new InvalidArgumentException(sprintf('Unsupported DSN: "%s".'$dsn));
  112.     }
  113.     public function commit(): bool
  114.     {
  115.         $ok true;
  116.         $byLifetime = (self::$mergeByLifetime)($this->deferred$this->namespace$expiredIds$this->getId(...), $this->defaultLifetime);
  117.         $retry $this->deferred = [];
  118.         if ($expiredIds) {
  119.             try {
  120.                 $this->doDelete($expiredIds);
  121.             } catch (\Exception $e) {
  122.                 $ok false;
  123.                 CacheItem::log($this->logger'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e'cache-adapter' => get_debug_type($this)]);
  124.             }
  125.         }
  126.         foreach ($byLifetime as $lifetime => $values) {
  127.             try {
  128.                 $e $this->doSave($values$lifetime);
  129.             } catch (\Exception $e) {
  130.             }
  131.             if (true === $e || [] === $e) {
  132.                 continue;
  133.             }
  134.             if (\is_array($e) || === \count($values)) {
  135.                 foreach (\is_array($e) ? $e array_keys($values) as $id) {
  136.                     $ok false;
  137.                     $v $values[$id];
  138.                     $type get_debug_type($v);
  139.                     $message sprintf('Failed to save key "{key}" of type %s%s'$type$e instanceof \Exception ': '.$e->getMessage() : '.');
  140.                     CacheItem::log($this->logger$message, ['key' => substr($id\strlen($this->namespace)), 'exception' => $e instanceof \Exception $e null'cache-adapter' => get_debug_type($this)]);
  141.                 }
  142.             } else {
  143.                 foreach ($values as $id => $v) {
  144.                     $retry[$lifetime][] = $id;
  145.                 }
  146.             }
  147.         }
  148.         // When bulk-save failed, retry each item individually
  149.         foreach ($retry as $lifetime => $ids) {
  150.             foreach ($ids as $id) {
  151.                 try {
  152.                     $v $byLifetime[$lifetime][$id];
  153.                     $e $this->doSave([$id => $v], $lifetime);
  154.                 } catch (\Exception $e) {
  155.                 }
  156.                 if (true === $e || [] === $e) {
  157.                     continue;
  158.                 }
  159.                 $ok false;
  160.                 $type get_debug_type($v);
  161.                 $message sprintf('Failed to save key "{key}" of type %s%s'$type$e instanceof \Exception ': '.$e->getMessage() : '.');
  162.                 CacheItem::log($this->logger$message, ['key' => substr($id\strlen($this->namespace)), 'exception' => $e instanceof \Exception $e null'cache-adapter' => get_debug_type($this)]);
  163.             }
  164.         }
  165.         return $ok;
  166.     }
  167. }