diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 25178d3b2dde1..831d219ab29c9 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -12,23 +12,43 @@ namespace Symfony\Component\Cache\Adapter; use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; /** * @author Nicolas Grekas */ -abstract class AbstractAdapter implements CacheItemPoolInterface +abstract class AbstractAdapter implements AdapterInterface { + /** + * @var string + */ private $namespace; + + /** + * @var AdapterInterface + */ + private $decorated; + + /** + * @var array + */ private $deferred = array(); + + /** + * @var \Closure + */ private $createCacheItem; + + /** + * @var \Closure + */ private $mergeByLifetime; - protected function __construct($namespace = '', $defaultLifetime = 0) + protected function __construct($namespace = '', $defaultLifetime = 0, AdapterInterface $decorated = null) { $this->namespace = $namespace; + $this->decorated = $decorated; $this->createCacheItem = \Closure::bind( function ($key, $value, $isHit) use ($defaultLifetime) { $item = new CacheItem(); @@ -109,7 +129,6 @@ abstract protected function doSave(array $values, $lifetime); public function getItem($key) { $id = $this->getId($key); - if ($this->deferred) { $this->commit(); } @@ -125,6 +144,10 @@ public function getItem($key) $isHit = true; } + if (!$isHit && $this->decorated) { + return $this->decorated->getItem($key); + } + return $f($key, $value, $isHit); } @@ -154,6 +177,13 @@ public function getItems(array $keys = array()) foreach ($ids as $key => $id) { $isHit = isset($values[$id]); + + if (!$isHit && $this->decorated) { + $items[$key] = $this->getItem($key); + + continue; + } + $items[$key] = $f($key, $isHit ? $values[$id] : null, $isHit); } @@ -169,7 +199,13 @@ public function hasItem($key) $this->commit(); } - return $this->doHave($this->getId($key)); + $got = $this->doHave($this->getId($key)); + + if ($got || !$this->decorated) { + return $got; + } + + return $this->decorated->hasItem($key); } /** @@ -178,8 +214,9 @@ public function hasItem($key) public function clear() { $this->deferred = array(); + $cleared = $this->decorated ? $this->decorated->clear() : true; - return $this->doClear(); + return $this->doClear() && $cleared; } /** @@ -187,7 +224,9 @@ public function clear() */ public function deleteItem($key) { - return $this->deleteItems(array($key)); + $deleted = $this->decorated ? $this->decorated->deleteItem($key) : true; + + return $this->deleteItems(array($key)) && $deleted; } /** @@ -202,7 +241,9 @@ public function deleteItems(array $keys) unset($this->deferred[$key]); } - return $this->doDelete($ids); + $deleted = $this->decorated ? $this->decorated->deleteItems($keys) : true; + + return $this->doDelete($ids) && $deleted; } /** @@ -217,7 +258,9 @@ public function save(CacheItemInterface $item) $this->deferred[$key] = $item; $this->commit(); - return !isset($this->deferred[$key]); + $saved = $this->decorated ? $this->decorated->save($item) : true; + + return !isset($this->deferred[$key]) && $saved; } /** @@ -240,7 +283,7 @@ public function saveDeferred(CacheItemInterface $item) } $this->deferred[$item->getKey()] = $item; - return true; + return $this->decorated ? $this->decorated->saveDeferred($item) : true; } /** @@ -265,7 +308,9 @@ public function commit() } } - return !$this->deferred = $ko; + $committed = $this->decorated ? $this->decorated->commit() : true; + + return !($this->deferred = $ko) && $committed; } public function __destruct() diff --git a/src/Symfony/Component/Cache/Adapter/AdapterInterface.php b/src/Symfony/Component/Cache/Adapter/AdapterInterface.php new file mode 100644 index 0000000000000..f6fb018200a79 --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/AdapterInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemPoolInterface; + +/** + * Marker interface for adapters managing \Symfony\Component\Cache\CacheItem instances. + * + * @author Kévin Dunglas + */ +interface AdapterInterface extends CacheItemPoolInterface +{ +} diff --git a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php index 30ff93109c2c8..688cad0762622 100644 --- a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php @@ -18,7 +18,7 @@ */ class ApcuAdapter extends AbstractAdapter { - public function __construct($namespace = '', $defaultLifetime = 0) + public function __construct($namespace = '', $defaultLifetime = 0, AdapterInterface $decorated = null) { if (!function_exists('apcu_fetch') || !ini_get('apc.enabled') || ('cli' === PHP_SAPI && !ini_get('apc.enable_cli'))) { throw new CacheException('APCu is not enabled'); @@ -26,7 +26,7 @@ public function __construct($namespace = '', $defaultLifetime = 0) if ('cli' === PHP_SAPI) { ini_set('apc.use_request_time', 0); } - parent::__construct($namespace, $defaultLifetime); + parent::__construct($namespace, $defaultLifetime, $decorated); } /** diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php index 6f3ba49ec7cfe..f6201b71234bf 100644 --- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php @@ -19,7 +19,7 @@ /** * @author Nicolas Grekas */ -class ArrayAdapter implements CacheItemPoolInterface +class ArrayAdapter implements AdapterInterface { private $values = array(); private $expiries = array(); diff --git a/src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php b/src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php index 9fcef8693b09a..0d4a85a141af1 100644 --- a/src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php @@ -20,9 +20,9 @@ class DoctrineAdapter extends AbstractAdapter { private $provider; - public function __construct(CacheProvider $provider, $defaultLifetime = null) + public function __construct(CacheProvider $provider, $defaultLifetime = null, AdapterInterface $decorated = null) { - parent::__construct('', $defaultLifetime); + parent::__construct('', $defaultLifetime, $decorated); $this->provider = $provider; } diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php index f8f1004015919..d98569a8dcc5f 100644 --- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php @@ -18,7 +18,7 @@ /** * @author Nicolas Grekas */ -class ProxyAdapter implements CacheItemPoolInterface +class ProxyAdapter implements AdapterInterface { private $pool; private $createCacheItem; diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterDecoratorTest.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterDecoratorTest.php new file mode 100644 index 0000000000000..a7144e1e7a987 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterDecoratorTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Cache\IntegrationTests\CachePoolTest; +use Symfony\Component\Cache\Adapter\ApcuAdapter; + +/** + * @author Kévin Dunglas + */ +class AdapterDecoratorTest extends CachePoolTest +{ + public function createCachePool() + { + return new ApcuAdapter(__CLASS__, 0, new ApcuAdapter()); + } +}