[FrameworkBundle] Allow clearing private cache pools
This commit is contained in:
parent
635d77b32a
commit
b71df3f295
@ -18,3 +18,9 @@ SecurityBundle
|
|||||||
|
|
||||||
* The `FirewallContext::getContext()` method has been deprecated and will be removed in 4.0.
|
* The `FirewallContext::getContext()` method has been deprecated and will be removed in 4.0.
|
||||||
Use the `getListeners()` method instead.
|
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.
|
||||||
|
@ -175,6 +175,9 @@ HttpKernel
|
|||||||
|
|
||||||
* The `DataCollector::varToString()` method has been removed in favor of `cloneVar()`.
|
* 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
|
Security
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -55,16 +55,21 @@ EOF
|
|||||||
$clearers = array();
|
$clearers = array();
|
||||||
$container = $this->getContainer();
|
$container = $this->getContainer();
|
||||||
$cacheDir = $container->getParameter('kernel.cache_dir');
|
$cacheDir = $container->getParameter('kernel.cache_dir');
|
||||||
|
$globalClearer = $container->get('cache.global_clearer');
|
||||||
|
|
||||||
foreach ($input->getArgument('pools') as $id) {
|
foreach ($input->getArgument('pools') as $id) {
|
||||||
$pool = $container->get($id);
|
if ($globalClearer->hasPool($id)) {
|
||||||
|
$pools[$id] = $id;
|
||||||
if ($pool instanceof CacheItemPoolInterface) {
|
|
||||||
$pools[$id] = $pool;
|
|
||||||
} elseif ($pool instanceof Psr6CacheClearer) {
|
|
||||||
$clearers[$id] = $pool;
|
|
||||||
} else {
|
} 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) {
|
foreach ($pools as $id => $pool) {
|
||||||
$io->comment(sprintf('Clearing cache pool: <info>%s</info>', $id));
|
$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.');
|
$io->success('Cache was successfully cleared.');
|
||||||
|
@ -27,19 +27,31 @@ final class CachePoolClearerPass implements CompilerPassInterface
|
|||||||
public function process(ContainerBuilder $container)
|
public function process(ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$container->getParameterBag()->remove('cache.prefix.seed');
|
$container->getParameterBag()->remove('cache.prefix.seed');
|
||||||
|
$poolsByClearer = array();
|
||||||
|
$pools = array();
|
||||||
|
|
||||||
foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) {
|
foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) {
|
||||||
|
$pools[$id] = new Reference($id);
|
||||||
foreach (array_reverse($attributes) as $attr) {
|
foreach (array_reverse($attributes) as $attr) {
|
||||||
if (isset($attr['clearer'])) {
|
if (isset($attr['clearer'])) {
|
||||||
$clearer = $container->getDefinition($attr['clearer']);
|
$poolsByClearer[$attr['clearer']][$id] = $pools[$id];
|
||||||
$clearer->addMethodCall('addPool', array(new Reference($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;
|
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')) {
|
if (!$container->has('cache.annotations')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,10 @@ class CachePoolPass implements CompilerPassInterface
|
|||||||
if ($pool->isAbstract()) {
|
if ($pool->isAbstract()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
$isLazy = $pool->isLazy();
|
||||||
while ($adapter instanceof DefinitionDecorator) {
|
while ($adapter instanceof DefinitionDecorator) {
|
||||||
$adapter = $container->findDefinition($adapter->getParent());
|
$adapter = $container->findDefinition($adapter->getParent());
|
||||||
|
$isLazy = $isLazy || $adapter->isLazy();
|
||||||
if ($t = $adapter->getTag('cache.pool')) {
|
if ($t = $adapter->getTag('cache.pool')) {
|
||||||
$tags[0] += $t[0];
|
$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]))));
|
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) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,7 @@
|
|||||||
<tag name="kernel.cache_clearer" />
|
<tag name="kernel.cache_clearer" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="cache.global_clearer" parent="cache.default_clearer" />
|
||||||
<service id="cache.app_clearer" alias="cache.default_clearer" />
|
<service id="cache.app_clearer" alias="cache.default_clearer" />
|
||||||
|
|
||||||
</services>
|
</services>
|
||||||
|
@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
|
|||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\Definition;
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
|
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
|
||||||
|
|
||||||
class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
|
class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
@ -29,6 +30,9 @@ class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
|
|||||||
$container->setParameter('kernel.environment', 'prod');
|
$container->setParameter('kernel.environment', 'prod');
|
||||||
$container->setParameter('kernel.root_dir', 'foo');
|
$container->setParameter('kernel.root_dir', 'foo');
|
||||||
|
|
||||||
|
$globalClearer = new Definition(Psr6CacheClearer::class);
|
||||||
|
$container->setDefinition('cache.global_clearer', $globalClearer);
|
||||||
|
|
||||||
$publicPool = new Definition();
|
$publicPool = new Definition();
|
||||||
$publicPool->addArgument('namespace');
|
$publicPool->addArgument('namespace');
|
||||||
$publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias'));
|
$publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias'));
|
||||||
@ -50,6 +54,7 @@ class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
|
|||||||
$pass->process($container);
|
$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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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(),
|
||||||
|
);
|
@ -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
|
@ -23,7 +23,7 @@
|
|||||||
"symfony/config": "~2.8|~3.0",
|
"symfony/config": "~2.8|~3.0",
|
||||||
"symfony/event-dispatcher": "~2.8|~3.0",
|
"symfony/event-dispatcher": "~2.8|~3.0",
|
||||||
"symfony/http-foundation": "~3.1",
|
"symfony/http-foundation": "~3.1",
|
||||||
"symfony/http-kernel": "~3.2",
|
"symfony/http-kernel": "~3.3",
|
||||||
"symfony/polyfill-mbstring": "~1.0",
|
"symfony/polyfill-mbstring": "~1.0",
|
||||||
"symfony/filesystem": "~2.8|~3.0",
|
"symfony/filesystem": "~2.8|~3.0",
|
||||||
"symfony/finder": "~2.8|~3.0",
|
"symfony/finder": "~2.8|~3.0",
|
||||||
|
@ -20,11 +20,32 @@ class Psr6CacheClearer implements CacheClearerInterface
|
|||||||
{
|
{
|
||||||
private $pools = array();
|
private $pools = array();
|
||||||
|
|
||||||
|
public function __construct(array $pools = array())
|
||||||
|
{
|
||||||
|
$this->pools = $pools;
|
||||||
|
}
|
||||||
|
|
||||||
public function addPool(CacheItemPoolInterface $pool)
|
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;
|
$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}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -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('');
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user