[FrameworkBundle] Allow clearing private cache pools

This commit is contained in:
Robin Chalas 2016-12-07 20:11:50 +01:00
parent 635d77b32a
commit b71df3f295
No known key found for this signature in database
GPG Key ID: 89672113756EE03B
13 changed files with 275 additions and 14 deletions

View File

@ -18,3 +18,9 @@ SecurityBundle
* The `FirewallContext::getContext()` method has been deprecated and will be removed in 4.0.
Use the `getListeners()` method instead.
HttpKernel
-----------
* The `Psr6CacheClearer::addPool()` method has been deprecated. Pass an array of pools indexed
by name to the constructor instead.

View File

@ -175,6 +175,9 @@ HttpKernel
* The `DataCollector::varToString()` method has been removed in favor of `cloneVar()`.
* The `Psr6CacheClearer::addPool()` method has been removed. Pass an array of pools indexed
by name to the constructor instead.
Security
--------

View File

@ -55,16 +55,21 @@ EOF
$clearers = array();
$container = $this->getContainer();
$cacheDir = $container->getParameter('kernel.cache_dir');
$globalClearer = $container->get('cache.global_clearer');
foreach ($input->getArgument('pools') as $id) {
$pool = $container->get($id);
if ($pool instanceof CacheItemPoolInterface) {
$pools[$id] = $pool;
} elseif ($pool instanceof Psr6CacheClearer) {
$clearers[$id] = $pool;
if ($globalClearer->hasPool($id)) {
$pools[$id] = $id;
} else {
throw new \InvalidArgumentException(sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
$pool = $container->get($id);
if ($pool instanceof CacheItemPoolInterface) {
$pools[$id] = $pool;
} elseif ($pool instanceof Psr6CacheClearer) {
$clearers[$id] = $pool;
} else {
throw new \InvalidArgumentException(sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
}
}
}
@ -75,7 +80,12 @@ EOF
foreach ($pools as $id => $pool) {
$io->comment(sprintf('Clearing cache pool: <info>%s</info>', $id));
$pool->clear();
if ($pool instanceof CacheItemPoolInterface) {
$pool->clear();
} else {
$globalClearer->clearPool($id);
}
}
$io->success('Cache was successfully cleared.');

View File

@ -27,19 +27,31 @@ final class CachePoolClearerPass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
$container->getParameterBag()->remove('cache.prefix.seed');
$poolsByClearer = array();
$pools = array();
foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) {
$pools[$id] = new Reference($id);
foreach (array_reverse($attributes) as $attr) {
if (isset($attr['clearer'])) {
$clearer = $container->getDefinition($attr['clearer']);
$clearer->addMethodCall('addPool', array(new Reference($id)));
$poolsByClearer[$attr['clearer']][$id] = $pools[$id];
}
if (array_key_exists('clearer', $attr)) {
if (!empty($attr['unlazy'])) {
$container->getDefinition($id)->setLazy(false);
}
if (array_key_exists('clearer', $attr) || array_key_exists('unlazy', $attr)) {
break;
}
}
}
$container->getDefinition('cache.global_clearer')->addArgument($pools);
foreach ($poolsByClearer as $clearer => $pools) {
$clearer = $container->getDefinition($clearer);
$clearer->addArgument($pools);
}
if (!$container->has('cache.annotations')) {
return;
}

View File

@ -47,8 +47,10 @@ class CachePoolPass implements CompilerPassInterface
if ($pool->isAbstract()) {
continue;
}
$isLazy = $pool->isLazy();
while ($adapter instanceof DefinitionDecorator) {
$adapter = $container->findDefinition($adapter->getParent());
$isLazy = $isLazy || $adapter->isLazy();
if ($t = $adapter->getTag('cache.pool')) {
$tags[0] += $t[0];
}
@ -80,8 +82,16 @@ class CachePoolPass implements CompilerPassInterface
throw new InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "clearer", "provider", "namespace" and "default_lifetime", found "%s".', $id, implode('", "', array_keys($tags[0]))));
}
$attr = array();
if (null !== $clearer) {
$pool->addTag('cache.pool', array('clearer' => $clearer));
$attr['clearer'] = $clearer;
}
if (!$isLazy) {
$pool->setLazy(true);
$attr['unlazy'] = true;
}
if ($attr) {
$pool->addTag('cache.pool', $attr);
}
}
}

View File

@ -97,6 +97,7 @@
<tag name="kernel.cache_clearer" />
</service>
<service id="cache.global_clearer" parent="cache.default_clearer" />
<service id="cache.app_clearer" alias="cache.default_clearer" />
</services>

View File

@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
{
@ -29,6 +30,9 @@ class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
$container->setParameter('kernel.environment', 'prod');
$container->setParameter('kernel.root_dir', 'foo');
$globalClearer = new Definition(Psr6CacheClearer::class);
$container->setDefinition('cache.global_clearer', $globalClearer);
$publicPool = new Definition();
$publicPool->addArgument('namespace');
$publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias'));
@ -50,6 +54,7 @@ class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
$pass->process($container);
}
$this->assertEquals(array(array('addPool', array(new Reference('public.pool')))), $clearer->getMethodCalls());
$this->assertEquals(array(array('public.pool' => new Reference('public.pool'))), $clearer->getArguments());
$this->assertEquals(array(array('public.pool' => new Reference('public.pool'))), $globalClearer->getArguments());
}
}

View File

@ -0,0 +1,86 @@
<?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\Bundle\FrameworkBundle\Tests\Functional;
use Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand;
use Symfony\Component\Console\Tester\CommandTester;
/**
* @group functional
*/
class CachePoolClearCommandTest extends WebTestCase
{
private $application;
protected function setUp()
{
static::bootKernel(array('test_case' => 'CachePoolClear', 'root_config' => 'config.yml'));
}
public function testClearPrivatePool()
{
$tester = $this->createCommandTester();
$tester->execute(array('pools' => array('cache.private_pool')), array('decorated' => false));
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
$this->assertContains('Clearing cache pool: cache.private_pool', $tester->getDisplay());
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
}
public function testClearPublicPool()
{
$tester = $this->createCommandTester();
$tester->execute(array('pools' => array('cache.public_pool')), array('decorated' => false));
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
$this->assertContains('Clearing cache pool: cache.public_pool', $tester->getDisplay());
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
}
public function testClearPoolWithCustomClearer()
{
$tester = $this->createCommandTester();
$tester->execute(array('pools' => array('cache.pool_with_clearer')), array('decorated' => false));
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
$this->assertContains('Clearing cache pool: cache.pool_with_clearer', $tester->getDisplay());
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
}
public function testCallClearer()
{
$tester = $this->createCommandTester();
$tester->execute(array('pools' => array('cache.default_clearer')), array('decorated' => false));
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
$this->assertContains('Calling cache clearer: cache.default_clearer', $tester->getDisplay());
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
* @expectedExceptionMessage You have requested a non-existent service "unknown_pool"
*/
public function testClearUnexistingPool()
{
$this->createCommandTester()
->execute(array('pools' => array('unknown_pool')), array('decorated' => false));
}
private function createCommandTester()
{
$command = new CachePoolClearCommand();
$command->setContainer(static::$kernel->getContainer());
return new CommandTester($command);
}
}

View File

@ -0,0 +1,18 @@
<?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.
*/
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
return array(
new FrameworkBundle(),
new TestBundle(),
);

View File

@ -0,0 +1,21 @@
imports:
- { resource: ../config/default.yml }
services:
dummy:
class: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\DeclaredClass
arguments: ['@cache.private_pool']
custom_clearer:
parent: cache.default_clearer
tags:
- name: kernel.cache_clearer
framework:
cache:
pools:
cache.private_pool: ~
cache.public_pool:
public: true
cache.pool_with_clearer:
public: true
clearer: custom_clearer

View File

@ -23,7 +23,7 @@
"symfony/config": "~2.8|~3.0",
"symfony/event-dispatcher": "~2.8|~3.0",
"symfony/http-foundation": "~3.1",
"symfony/http-kernel": "~3.2",
"symfony/http-kernel": "~3.3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/filesystem": "~2.8|~3.0",
"symfony/finder": "~2.8|~3.0",

View File

@ -20,11 +20,32 @@ class Psr6CacheClearer implements CacheClearerInterface
{
private $pools = array();
public function __construct(array $pools = array())
{
$this->pools = $pools;
}
public function addPool(CacheItemPoolInterface $pool)
{
@trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Pass an array of pools indexed by name to the constructor instead.', __METHOD__), E_USER_DEPRECATED);
$this->pools[] = $pool;
}
public function hasPool($name)
{
return isset($this->pools[$name]);
}
public function clearPool($name)
{
if (!isset($this->pools[$name])) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: %s.', $name));
}
return $this->pools[$name]->clear();
}
/**
* {@inheritdoc}
*/

View File

@ -0,0 +1,68 @@
<?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\HttpKernel\Tests\CacheClearer;
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
use Psr\Cache\CacheItemPoolInterface;
class Psr6CacheClearerTest extends \PHPUnit_Framework_TestCase
{
public function testClearPoolsInjectedInConstructor()
{
$pool = $this->getMock(CacheItemPoolInterface::class);
$pool
->expects($this->once())
->method('clear');
(new Psr6CacheClearer(array('pool' => $pool)))->clear('');
}
public function testClearPool()
{
$pool = $this->getMock(CacheItemPoolInterface::class);
$pool
->expects($this->once())
->method('clear');
(new Psr6CacheClearer(array('pool' => $pool)))->clearPool('pool');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Cache pool not found: unknown
*/
public function testClearPoolThrowsExceptionOnUnreferencedPool()
{
(new Psr6CacheClearer())->clearPool('unknown');
}
/**
* @group legacy
* @expectedDeprecation The Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer::addPool() method is deprecated since version 3.3 and will be removed in 4.0. Pass an array of pools indexed by name to the constructor instead.
*/
public function testClearPoolsInjectedByAdder()
{
$pool1 = $this->getMock(CacheItemPoolInterface::class);
$pool1
->expects($this->once())
->method('clear');
$pool2 = $this->getMock(CacheItemPoolInterface::class);
$pool2
->expects($this->once())
->method('clear');
$clearer = new Psr6CacheClearer(array('pool1' => $pool1));
$clearer->addPool($pool2);
$clearer->clear('');
}
}