[Cache] Add [Taggable]CacheInterface, the easiest way to use a cache
This commit is contained in:
parent
2ae7ad9fe1
commit
589ff697f4
@ -15,6 +15,10 @@
|
||||
<argument type="service" id="cache.app" />
|
||||
</service>
|
||||
|
||||
<service id="cache.app.taggable" class="Symfony\Component\Cache\Adapter\TagAwareAdapter">
|
||||
<argument type="service" id="cache.app" />
|
||||
</service>
|
||||
|
||||
<service id="cache.system" parent="cache.adapter.system" public="true">
|
||||
<tag name="cache.pool" />
|
||||
</service>
|
||||
@ -122,7 +126,9 @@
|
||||
<service id="cache.global_clearer" parent="cache.default_clearer" public="true" />
|
||||
<service id="cache.app_clearer" alias="cache.default_clearer" public="true" />
|
||||
<service id="Psr\Cache\CacheItemPoolInterface" alias="cache.app" />
|
||||
<service id="Symfony\Component\Cache\TaggableCacheInterface" alias="cache.app.taggable" />
|
||||
<service id="Psr\SimpleCache\CacheInterface" alias="cache.app.simple" />
|
||||
<service id="Symfony\Component\Cache\Adapter\AdapterInterface" alias="cache.app" />
|
||||
<service id="Symfony\Component\Cache\CacheInterface" alias="cache.app" />
|
||||
</services>
|
||||
</container>
|
||||
|
@ -15,17 +15,20 @@ use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Component\Cache\CacheInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\AbstractTrait;
|
||||
use Symfony\Component\Cache\Traits\GetTrait;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
|
||||
abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
|
||||
{
|
||||
use AbstractTrait;
|
||||
use GetTrait;
|
||||
|
||||
private static $apcuSupported;
|
||||
private static $phpFilesSupported;
|
||||
|
@ -13,16 +13,19 @@ namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Symfony\Component\Cache\CacheInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\ArrayTrait;
|
||||
use Symfony\Component\Cache\Traits\GetTrait;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
|
||||
class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
|
||||
{
|
||||
use ArrayTrait;
|
||||
use GetTrait;
|
||||
|
||||
private $createCacheItem;
|
||||
|
||||
|
@ -13,10 +13,12 @@ namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\GetTrait;
|
||||
|
||||
/**
|
||||
* Chains several adapters together.
|
||||
@ -26,8 +28,10 @@ use Symfony\Component\Cache\ResettableInterface;
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
|
||||
class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
use GetTrait;
|
||||
|
||||
private $adapters = array();
|
||||
private $adapterCount;
|
||||
private $syncItem;
|
||||
@ -61,6 +65,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
|
||||
$item->expiry = $sourceItem->expiry;
|
||||
$item->isHit = $sourceItem->isHit;
|
||||
|
||||
$sourceItem->isTaggable = false;
|
||||
|
||||
if (0 < $sourceItem->defaultLifetime && $sourceItem->defaultLifetime < $defaultLifetime) {
|
||||
$defaultLifetime = $sourceItem->defaultLifetime;
|
||||
}
|
||||
@ -75,6 +81,33 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback)
|
||||
{
|
||||
$lastItem = null;
|
||||
$i = 0;
|
||||
$wrap = function (CacheItem $item = null) use ($key, $callback, &$wrap, &$i, &$lastItem) {
|
||||
$adapter = $this->adapters[$i];
|
||||
if (isset($this->adapters[++$i])) {
|
||||
$callback = $wrap;
|
||||
}
|
||||
if ($adapter instanceof CacheInterface) {
|
||||
$value = $adapter->get($key, $callback);
|
||||
} else {
|
||||
$value = $this->doGet($adapter, $key, $callback);
|
||||
}
|
||||
if (null !== $item) {
|
||||
($this->syncItem)($lastItem = $lastItem ?? $item, $item);
|
||||
}
|
||||
|
||||
return $value;
|
||||
};
|
||||
|
||||
return $wrap();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -12,13 +12,17 @@
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Symfony\Component\Cache\CacheInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Traits\GetTrait;
|
||||
|
||||
/**
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
class NullAdapter implements AdapterInterface
|
||||
class NullAdapter implements AdapterInterface, CacheInterface
|
||||
{
|
||||
use GetTrait;
|
||||
|
||||
private $createCacheItem;
|
||||
|
||||
public function __construct()
|
||||
|
@ -13,10 +13,12 @@ namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\GetTrait;
|
||||
use Symfony\Component\Cache\Traits\PhpArrayTrait;
|
||||
|
||||
/**
|
||||
@ -26,9 +28,10 @@ use Symfony\Component\Cache\Traits\PhpArrayTrait;
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
|
||||
class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
use PhpArrayTrait;
|
||||
use GetTrait;
|
||||
|
||||
private $createCacheItem;
|
||||
|
||||
@ -77,6 +80,31 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
|
||||
return $fallbackPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback)
|
||||
{
|
||||
if (null === $this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
if (null === $value = $this->values[$key] ?? null) {
|
||||
if ($this->pool instanceof CacheInterface) {
|
||||
return $this->pool->get($key, $callback);
|
||||
}
|
||||
|
||||
return $this->doGet($this->pool, $key, $callback);
|
||||
}
|
||||
if ('N;' === $value) {
|
||||
return null;
|
||||
}
|
||||
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
|
||||
return unserialize($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -13,17 +13,20 @@ namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\Traits\GetTrait;
|
||||
use Symfony\Component\Cache\Traits\ProxyTrait;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
|
||||
class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
use ProxyTrait;
|
||||
use GetTrait;
|
||||
|
||||
private $namespace;
|
||||
private $namespaceLen;
|
||||
@ -54,6 +57,20 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback)
|
||||
{
|
||||
if (!$this->pool instanceof CacheInterface) {
|
||||
return $this->doGet($this->pool, $key, $callback);
|
||||
}
|
||||
|
||||
return $this->pool->get($this->getId($key), function ($innerItem) use ($key, $callback) {
|
||||
return $callback(($this->createCacheItem)($key, $innerItem));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -16,16 +16,19 @@ use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
use Symfony\Component\Cache\TaggableCacheInterface;
|
||||
use Symfony\Component\Cache\Traits\GetTrait;
|
||||
use Symfony\Component\Cache\Traits\ProxyTrait;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, ResettableInterface
|
||||
class TagAwareAdapter implements TagAwareAdapterInterface, TaggableCacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
const TAGS_PREFIX = "\0tags\0";
|
||||
|
||||
use ProxyTrait;
|
||||
use GetTrait;
|
||||
|
||||
private $deferred = array();
|
||||
private $createCacheItem;
|
||||
@ -58,6 +61,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
|
||||
);
|
||||
$this->setCacheItemTags = \Closure::bind(
|
||||
function (CacheItem $item, $key, array &$itemTags) {
|
||||
$item->isTaggable = true;
|
||||
if (!$item->isHit) {
|
||||
return $item;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Symfony\Component\Cache\CacheInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Cache\ResettableInterface;
|
||||
|
||||
@ -22,7 +24,7 @@ use Symfony\Component\Cache\ResettableInterface;
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class TraceableAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
|
||||
class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
|
||||
{
|
||||
protected $pool;
|
||||
private $calls = array();
|
||||
@ -32,6 +34,38 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
|
||||
$this->pool = $pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback)
|
||||
{
|
||||
if (!$this->pool instanceof CacheInterface) {
|
||||
throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_class($this->pool), CacheInterface::class));
|
||||
}
|
||||
|
||||
$isHit = true;
|
||||
$callback = function (CacheItem $item) use ($callback, &$isHit) {
|
||||
$isHit = $item->isHit();
|
||||
|
||||
return $callback($item);
|
||||
};
|
||||
|
||||
$event = $this->start(__FUNCTION__);
|
||||
try {
|
||||
$value = $this->pool->get($key, $callback);
|
||||
$event->result[$key] = \is_object($value) ? \get_class($value) : gettype($value);
|
||||
} finally {
|
||||
$event->end = microtime(true);
|
||||
}
|
||||
if ($isHit) {
|
||||
++$event->hits;
|
||||
} else {
|
||||
++$event->misses;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -11,10 +11,12 @@
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Symfony\Component\Cache\TaggableCacheInterface;
|
||||
|
||||
/**
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface
|
||||
class TraceableTagAwareAdapter extends TraceableAdapter implements TaggableCacheInterface, TagAwareAdapterInterface
|
||||
{
|
||||
public function __construct(TagAwareAdapterInterface $pool)
|
||||
{
|
||||
|
@ -1,6 +1,12 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* added `CacheInterface` and `TaggableCacheInterface`
|
||||
* throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
|
37
src/Symfony/Component/Cache/CacheInterface.php
Normal file
37
src/Symfony/Component/Cache/CacheInterface.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?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;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
|
||||
/**
|
||||
* Gets and stores items from a cache.
|
||||
*
|
||||
* On cache misses, a callback is called that should return the missing value.
|
||||
* It is given two arguments:
|
||||
* - the missing cache key
|
||||
* - the corresponding PSR-6 CacheItemInterface object,
|
||||
* allowing time-based expiration control.
|
||||
*
|
||||
* If you need tag-based invalidation, use TaggableCacheInterface instead.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface CacheInterface
|
||||
{
|
||||
/**
|
||||
* @param callable(CacheItemInterface):mixed $callback Should return the computed value for the given key/item
|
||||
*
|
||||
* @return mixed The value corresponding to the provided key
|
||||
*/
|
||||
public function get(string $key, callable $callback);
|
||||
}
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Cache;
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
@ -29,6 +30,7 @@ final class CacheItem implements CacheItemInterface
|
||||
protected $prevTags = array();
|
||||
protected $innerItem;
|
||||
protected $poolHash;
|
||||
protected $isTaggable = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@ -109,7 +111,10 @@ final class CacheItem implements CacheItemInterface
|
||||
*/
|
||||
public function tag($tags)
|
||||
{
|
||||
if (!\is_array($tags)) {
|
||||
if (!$this->isTaggable) {
|
||||
throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key));
|
||||
}
|
||||
if (!\is_iterable($tags)) {
|
||||
$tags = array($tags);
|
||||
}
|
||||
foreach ($tags as $tag) {
|
||||
|
@ -121,7 +121,15 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
|
||||
foreach ($calls as $call) {
|
||||
++$statistics[$name]['calls'];
|
||||
$statistics[$name]['time'] += $call->end - $call->start;
|
||||
if ('getItem' === $call->name) {
|
||||
if ('get' === $call->name) {
|
||||
++$statistics[$name]['reads'];
|
||||
if ($call->hits) {
|
||||
++$statistics[$name]['hits'];
|
||||
} else {
|
||||
++$statistics[$name]['misses'];
|
||||
++$statistics[$name]['writes'];
|
||||
}
|
||||
} elseif ('getItem' === $call->name) {
|
||||
++$statistics[$name]['reads'];
|
||||
if ($call->hits) {
|
||||
++$statistics[$name]['hits'];
|
||||
|
19
src/Symfony/Component/Cache/Exception/LogicException.php
Normal file
19
src/Symfony/Component/Cache/Exception/LogicException.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?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\Exception;
|
||||
|
||||
use Psr\Cache\InvalidArgumentException as Psr6CacheInterface;
|
||||
use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface;
|
||||
|
||||
class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface
|
||||
{
|
||||
}
|
35
src/Symfony/Component/Cache/TaggableCacheInterface.php
Normal file
35
src/Symfony/Component/Cache/TaggableCacheInterface.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Gets and stores items from a tag-aware cache.
|
||||
*
|
||||
* On cache misses, a callback is called that should return the missing value.
|
||||
* It is given two arguments:
|
||||
* - the missing cache key
|
||||
* - the corresponding Symfony CacheItem object,
|
||||
* allowing time-based *and* tags-based expiration control
|
||||
*
|
||||
* If you don't need tags-based invalidation, use CacheInterface instead.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface TaggableCacheInterface extends CacheInterface
|
||||
{
|
||||
/**
|
||||
* @param callable(CacheItem):mixed $callback Should return the computed value for the given key/item
|
||||
*
|
||||
* @return mixed The value corresponding to the provided key
|
||||
*/
|
||||
public function get(string $key, callable $callback);
|
||||
}
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Tests\Adapter;
|
||||
|
||||
use Cache\IntegrationTests\CachePoolTest;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
|
||||
abstract class AdapterTestCase extends CachePoolTest
|
||||
@ -26,6 +27,26 @@ abstract class AdapterTestCase extends CachePoolTest
|
||||
}
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
||||
}
|
||||
|
||||
$cache = $this->createCachePool();
|
||||
|
||||
$value = mt_rand();
|
||||
|
||||
$this->assertSame($value, $cache->get('foo', function (CacheItem $item) use ($value) {
|
||||
$this->assertSame('foo', $item->getKey());
|
||||
|
||||
return $value;
|
||||
}));
|
||||
|
||||
$item = $cache->getItem('foo');
|
||||
$this->assertSame($value, $item->get());
|
||||
}
|
||||
|
||||
public function testDefaultLifeTime()
|
||||
{
|
||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
||||
|
@ -21,6 +21,7 @@ use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
class PhpArrayAdapterTest extends AdapterTestCase
|
||||
{
|
||||
protected $skippedTests = array(
|
||||
'testGet' => 'PhpArrayAdapter is read-only.',
|
||||
'testBasicUsage' => 'PhpArrayAdapter is read-only.',
|
||||
'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.',
|
||||
'testClear' => 'PhpArrayAdapter is read-only.',
|
||||
|
@ -55,6 +55,9 @@ class CacheItemTest extends TestCase
|
||||
public function testTag()
|
||||
{
|
||||
$item = new CacheItem();
|
||||
$r = new \ReflectionProperty($item, 'isTaggable');
|
||||
$r->setAccessible(true);
|
||||
$r->setValue($item, true);
|
||||
|
||||
$this->assertSame($item, $item->tag('foo'));
|
||||
$this->assertSame($item, $item->tag(array('bar', 'baz')));
|
||||
@ -72,6 +75,24 @@ class CacheItemTest extends TestCase
|
||||
public function testInvalidTag($tag)
|
||||
{
|
||||
$item = new CacheItem();
|
||||
$r = new \ReflectionProperty($item, 'isTaggable');
|
||||
$r->setAccessible(true);
|
||||
$r->setValue($item, true);
|
||||
|
||||
$item->tag($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Cache\Exception\LogicException
|
||||
* @expectedExceptionMessage Cache item "foo" comes from a non tag-aware pool: you cannot tag it.
|
||||
*/
|
||||
public function testNonTaggableItem()
|
||||
{
|
||||
$item = new CacheItem();
|
||||
$r = new \ReflectionProperty($item, 'key');
|
||||
$r->setAccessible(true);
|
||||
$r->setValue($item, 'foo');
|
||||
|
||||
$item->tag(array());
|
||||
}
|
||||
}
|
||||
|
43
src/Symfony/Component/Cache/Traits/GetTrait.php
Normal file
43
src/Symfony/Component/Cache/Traits/GetTrait.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?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\Traits;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait GetTrait
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key, callable $callback)
|
||||
{
|
||||
return $this->doGet($this, $key, $callback);
|
||||
}
|
||||
|
||||
private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback)
|
||||
{
|
||||
$item = $pool->getItem($key);
|
||||
|
||||
if ($item->isHit()) {
|
||||
return $item->get();
|
||||
}
|
||||
|
||||
$pool->save($item->set($value = $callback($item)));
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user