vendor/symfony/cache/Adapter/ChainAdapter.php line 90

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\Cache\CacheItemPoolInterface;
  13. use Symfony\Component\Cache\CacheItem;
  14. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  15. use Symfony\Component\Cache\PruneableInterface;
  16. use Symfony\Component\Cache\ResettableInterface;
  17. /**
  18.  * Chains several adapters together.
  19.  *
  20.  * Cached items are fetched from the first adapter having them in its data store.
  21.  * They are saved and deleted in all adapters at once.
  22.  *
  23.  * @author Kévin Dunglas <dunglas@gmail.com>
  24.  */
  25. class ChainAdapter implements AdapterInterfacePruneableInterfaceResettableInterface
  26. {
  27.     private $adapters = [];
  28.     private $adapterCount;
  29.     private $syncItem;
  30.     /**
  31.      * @param CacheItemPoolInterface[] $adapters        The ordered list of adapters used to fetch cached items
  32.      * @param int                      $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones
  33.      */
  34.     public function __construct(array $adapters$defaultLifetime 0)
  35.     {
  36.         if (!$adapters) {
  37.             throw new InvalidArgumentException('At least one adapter must be specified.');
  38.         }
  39.         foreach ($adapters as $adapter) {
  40.             if (!$adapter instanceof CacheItemPoolInterface) {
  41.                 throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($adapter), CacheItemPoolInterface::class));
  42.             }
  43.             if (\in_array(\PHP_SAPI, ['cli''phpdbg'], true) && $adapter instanceof ApcuAdapter && !filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN)) {
  44.                 continue; // skip putting APCu in the chain when the backend is disabled
  45.             }
  46.             if ($adapter instanceof AdapterInterface) {
  47.                 $this->adapters[] = $adapter;
  48.             } else {
  49.                 $this->adapters[] = new ProxyAdapter($adapter);
  50.             }
  51.         }
  52.         $this->adapterCount = \count($this->adapters);
  53.         $this->syncItem = \Closure::bind(
  54.             static function ($sourceItem$item) use ($defaultLifetime) {
  55.                 $item->value $sourceItem->value;
  56.                 $item->expiry $sourceItem->expiry;
  57.                 $item->isHit $sourceItem->isHit;
  58.                 if ($sourceItem->defaultLifetime && $sourceItem->defaultLifetime $defaultLifetime) {
  59.                     $defaultLifetime $sourceItem->defaultLifetime;
  60.                 }
  61.                 if ($defaultLifetime && ($item->defaultLifetime <= || $defaultLifetime $item->defaultLifetime)) {
  62.                     $item->defaultLifetime $defaultLifetime;
  63.                 }
  64.                 return $item;
  65.             },
  66.             null,
  67.             CacheItem::class
  68.         );
  69.     }
  70.     /**
  71.      * {@inheritdoc}
  72.      */
  73.     public function getItem($key)
  74.     {
  75.         $syncItem $this->syncItem;
  76.         $misses = [];
  77.         foreach ($this->adapters as $i => $adapter) {
  78.             $item $adapter->getItem($key);
  79.             if ($item->isHit()) {
  80.                 while (<= --$i) {
  81.                     $this->adapters[$i]->save($syncItem($item$misses[$i]));
  82.                 }
  83.                 return $item;
  84.             }
  85.             $misses[$i] = $item;
  86.         }
  87.         return $item;
  88.     }
  89.     /**
  90.      * {@inheritdoc}
  91.      */
  92.     public function getItems(array $keys = [])
  93.     {
  94.         return $this->generateItems($this->adapters[0]->getItems($keys), 0);
  95.     }
  96.     private function generateItems($items$adapterIndex)
  97.     {
  98.         $missing = [];
  99.         $misses = [];
  100.         $nextAdapterIndex $adapterIndex 1;
  101.         $nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null;
  102.         foreach ($items as $k => $item) {
  103.             if (!$nextAdapter || $item->isHit()) {
  104.                 yield $k => $item;
  105.             } else {
  106.                 $missing[] = $k;
  107.                 $misses[$k] = $item;
  108.             }
  109.         }
  110.         if ($missing) {
  111.             $syncItem $this->syncItem;
  112.             $adapter $this->adapters[$adapterIndex];
  113.             $items $this->generateItems($nextAdapter->getItems($missing), $nextAdapterIndex);
  114.             foreach ($items as $k => $item) {
  115.                 if ($item->isHit()) {
  116.                     $adapter->save($syncItem($item$misses[$k]));
  117.                 }
  118.                 yield $k => $item;
  119.             }
  120.         }
  121.     }
  122.     /**
  123.      * {@inheritdoc}
  124.      */
  125.     public function hasItem($key)
  126.     {
  127.         foreach ($this->adapters as $adapter) {
  128.             if ($adapter->hasItem($key)) {
  129.                 return true;
  130.             }
  131.         }
  132.         return false;
  133.     }
  134.     /**
  135.      * {@inheritdoc}
  136.      */
  137.     public function clear()
  138.     {
  139.         $cleared true;
  140.         $i $this->adapterCount;
  141.         while ($i--) {
  142.             $cleared $this->adapters[$i]->clear() && $cleared;
  143.         }
  144.         return $cleared;
  145.     }
  146.     /**
  147.      * {@inheritdoc}
  148.      */
  149.     public function deleteItem($key)
  150.     {
  151.         $deleted true;
  152.         $i $this->adapterCount;
  153.         while ($i--) {
  154.             $deleted $this->adapters[$i]->deleteItem($key) && $deleted;
  155.         }
  156.         return $deleted;
  157.     }
  158.     /**
  159.      * {@inheritdoc}
  160.      */
  161.     public function deleteItems(array $keys)
  162.     {
  163.         $deleted true;
  164.         $i $this->adapterCount;
  165.         while ($i--) {
  166.             $deleted $this->adapters[$i]->deleteItems($keys) && $deleted;
  167.         }
  168.         return $deleted;
  169.     }
  170.     /**
  171.      * {@inheritdoc}
  172.      */
  173.     public function save(CacheItemInterface $item)
  174.     {
  175.         $saved true;
  176.         $i $this->adapterCount;
  177.         while ($i--) {
  178.             $saved $this->adapters[$i]->save($item) && $saved;
  179.         }
  180.         return $saved;
  181.     }
  182.     /**
  183.      * {@inheritdoc}
  184.      */
  185.     public function saveDeferred(CacheItemInterface $item)
  186.     {
  187.         $saved true;
  188.         $i $this->adapterCount;
  189.         while ($i--) {
  190.             $saved $this->adapters[$i]->saveDeferred($item) && $saved;
  191.         }
  192.         return $saved;
  193.     }
  194.     /**
  195.      * {@inheritdoc}
  196.      */
  197.     public function commit()
  198.     {
  199.         $committed true;
  200.         $i $this->adapterCount;
  201.         while ($i--) {
  202.             $committed $this->adapters[$i]->commit() && $committed;
  203.         }
  204.         return $committed;
  205.     }
  206.     /**
  207.      * {@inheritdoc}
  208.      */
  209.     public function prune()
  210.     {
  211.         $pruned true;
  212.         foreach ($this->adapters as $adapter) {
  213.             if ($adapter instanceof PruneableInterface) {
  214.                 $pruned $adapter->prune() && $pruned;
  215.             }
  216.         }
  217.         return $pruned;
  218.     }
  219.     /**
  220.      * {@inheritdoc}
  221.      */
  222.     public function reset()
  223.     {
  224.         foreach ($this->adapters as $adapter) {
  225.             if ($adapter instanceof ResettableInterface) {
  226.                 $adapter->reset();
  227.             }
  228.         }
  229.     }
  230. }