mirror of
https://github.com/symfony/cache.git
synced 2026-03-24 07:32:11 +01:00
* 4.1: fixed tests fixed CS fixed CS fixed CS fixed short array CS in comments fixed CS in ExpressionLanguage fixtures fixed CS in generated files fixed CS on generated container files fixed CS on Form PHP templates fixed CS on YAML fixtures fixed fixtures switched array() to []
254 lines
6.3 KiB
PHP
254 lines
6.3 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the Symfony package.
|
|
*
|
|
* (c) Fabien Potencier <fabien@symfony.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Symfony\Component\Cache\Simple;
|
|
|
|
use Psr\SimpleCache\CacheInterface;
|
|
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
|
use Symfony\Component\Cache\PruneableInterface;
|
|
use Symfony\Component\Cache\ResettableInterface;
|
|
use Symfony\Contracts\Service\ResetInterface;
|
|
|
|
/**
|
|
* Chains several caches together.
|
|
*
|
|
* Cached items are fetched from the first cache having them in its data store.
|
|
* They are saved and deleted in all caches at once.
|
|
*
|
|
* @author Nicolas Grekas <p@tchwork.com>
|
|
*/
|
|
class ChainCache implements CacheInterface, PruneableInterface, ResettableInterface
|
|
{
|
|
private $miss;
|
|
private $caches = [];
|
|
private $defaultLifetime;
|
|
private $cacheCount;
|
|
|
|
/**
|
|
* @param CacheInterface[] $caches The ordered list of caches used to fetch cached items
|
|
* @param int $defaultLifetime The lifetime of items propagated from lower caches to upper ones
|
|
*/
|
|
public function __construct(array $caches, int $defaultLifetime = 0)
|
|
{
|
|
if (!$caches) {
|
|
throw new InvalidArgumentException('At least one cache must be specified.');
|
|
}
|
|
|
|
foreach ($caches as $cache) {
|
|
if (!$cache instanceof CacheInterface) {
|
|
throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), CacheInterface::class));
|
|
}
|
|
}
|
|
|
|
$this->miss = new \stdClass();
|
|
$this->caches = array_values($caches);
|
|
$this->cacheCount = \count($this->caches);
|
|
$this->defaultLifetime = 0 < $defaultLifetime ? $defaultLifetime : null;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function get($key, $default = null)
|
|
{
|
|
$miss = null !== $default && \is_object($default) ? $default : $this->miss;
|
|
|
|
foreach ($this->caches as $i => $cache) {
|
|
$value = $cache->get($key, $miss);
|
|
|
|
if ($miss !== $value) {
|
|
while (0 <= --$i) {
|
|
$this->caches[$i]->set($key, $value, $this->defaultLifetime);
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getMultiple($keys, $default = null)
|
|
{
|
|
$miss = null !== $default && \is_object($default) ? $default : $this->miss;
|
|
|
|
return $this->generateItems($this->caches[0]->getMultiple($keys, $miss), 0, $miss, $default);
|
|
}
|
|
|
|
private function generateItems($values, $cacheIndex, $miss, $default)
|
|
{
|
|
$missing = [];
|
|
$nextCacheIndex = $cacheIndex + 1;
|
|
$nextCache = isset($this->caches[$nextCacheIndex]) ? $this->caches[$nextCacheIndex] : null;
|
|
|
|
foreach ($values as $k => $value) {
|
|
if ($miss !== $value) {
|
|
yield $k => $value;
|
|
} elseif (!$nextCache) {
|
|
yield $k => $default;
|
|
} else {
|
|
$missing[] = $k;
|
|
}
|
|
}
|
|
|
|
if ($missing) {
|
|
$cache = $this->caches[$cacheIndex];
|
|
$values = $this->generateItems($nextCache->getMultiple($missing, $miss), $nextCacheIndex, $miss, $default);
|
|
|
|
foreach ($values as $k => $value) {
|
|
if ($miss !== $value) {
|
|
$cache->set($k, $value, $this->defaultLifetime);
|
|
yield $k => $value;
|
|
} else {
|
|
yield $k => $default;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function has($key)
|
|
{
|
|
foreach ($this->caches as $cache) {
|
|
if ($cache->has($key)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function clear()
|
|
{
|
|
$cleared = true;
|
|
$i = $this->cacheCount;
|
|
|
|
while ($i--) {
|
|
$cleared = $this->caches[$i]->clear() && $cleared;
|
|
}
|
|
|
|
return $cleared;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function delete($key)
|
|
{
|
|
$deleted = true;
|
|
$i = $this->cacheCount;
|
|
|
|
while ($i--) {
|
|
$deleted = $this->caches[$i]->delete($key) && $deleted;
|
|
}
|
|
|
|
return $deleted;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function deleteMultiple($keys)
|
|
{
|
|
if ($keys instanceof \Traversable) {
|
|
$keys = iterator_to_array($keys, false);
|
|
}
|
|
$deleted = true;
|
|
$i = $this->cacheCount;
|
|
|
|
while ($i--) {
|
|
$deleted = $this->caches[$i]->deleteMultiple($keys) && $deleted;
|
|
}
|
|
|
|
return $deleted;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function set($key, $value, $ttl = null)
|
|
{
|
|
$saved = true;
|
|
$i = $this->cacheCount;
|
|
|
|
while ($i--) {
|
|
$saved = $this->caches[$i]->set($key, $value, $ttl) && $saved;
|
|
}
|
|
|
|
return $saved;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function setMultiple($values, $ttl = null)
|
|
{
|
|
if ($values instanceof \Traversable) {
|
|
$valuesIterator = $values;
|
|
$values = function () use ($valuesIterator, &$values) {
|
|
$generatedValues = [];
|
|
|
|
foreach ($valuesIterator as $key => $value) {
|
|
yield $key => $value;
|
|
$generatedValues[$key] = $value;
|
|
}
|
|
|
|
$values = $generatedValues;
|
|
};
|
|
$values = $values();
|
|
}
|
|
$saved = true;
|
|
$i = $this->cacheCount;
|
|
|
|
while ($i--) {
|
|
$saved = $this->caches[$i]->setMultiple($values, $ttl) && $saved;
|
|
}
|
|
|
|
return $saved;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function prune()
|
|
{
|
|
$pruned = true;
|
|
|
|
foreach ($this->caches as $cache) {
|
|
if ($cache instanceof PruneableInterface) {
|
|
$pruned = $cache->prune() && $pruned;
|
|
}
|
|
}
|
|
|
|
return $pruned;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function reset()
|
|
{
|
|
foreach ($this->caches as $cache) {
|
|
if ($cache instanceof ResetInterface) {
|
|
$cache->reset();
|
|
}
|
|
}
|
|
}
|
|
}
|