[Cache] Add nonce based cache invalidation to ApcuAdapter

This commit is contained in:
Nicolas Grekas 2016-05-05 22:23:36 +02:00
parent b85ab60b70
commit a7899fe65c
4 changed files with 39 additions and 1 deletions

View File

@ -1037,6 +1037,8 @@ class FrameworkExtension extends Extension
private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$nonce = substr(str_replace('/', '-', base64_encode(md5(uniqid(mt_rand(), true), true))), 0, -2);
$container->getDefinition('cache.adapter.apcu')->replaceArgument(2, $nonce);
$container->getDefinition('cache.adapter.filesystem')->replaceArgument(2, $config['directory']);
foreach (array('doctrine', 'psr6', 'redis') as $name) {

View File

@ -27,6 +27,7 @@
<tag name="monolog.logger" channel="cache" />
<argument /> <!-- namespace -->
<argument /> <!-- default lifetime -->
<argument /> <!-- nonce -->
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore" />
</call>

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\CacheException;
/**
@ -18,7 +19,7 @@ use Symfony\Component\Cache\Exception\CacheException;
*/
class ApcuAdapter extends AbstractAdapter
{
public function __construct($namespace = '', $defaultLifetime = 0)
public function __construct($namespace = '', $defaultLifetime = 0, $nonce = 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');
@ -27,6 +28,15 @@ class ApcuAdapter extends AbstractAdapter
ini_set('apc.use_request_time', 0);
}
parent::__construct($namespace, $defaultLifetime);
if (null !== $nonce) {
CacheItem::validateKey($nonce);
if (!apcu_exists($nonce.':nonce'.$namespace)) {
$this->clear($namespace);
apcu_add($nonce.':nonce'.$namespace, null);
}
}
}
/**

View File

@ -43,4 +43,29 @@ class ApcuAdapterTest extends CachePoolTest
$item = $pool->getItem('foo');
$this->assertFalse($item->isHit());
}
public function testNonce()
{
$namespace = str_replace('\\', '.', __CLASS__);
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
$item = $pool1->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertTrue($pool1->save($item->set('bar')));
$item = $pool1->getItem('foo');
$this->assertTrue($item->isHit());
$this->assertSame('bar', $item->get());
$pool2 = new ApcuAdapter($namespace, 0, 'p2');
$item = $pool2->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertNull($item->get());
$item = $pool1->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertNull($item->get());
}
}