Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 12d7fda

Browse filesBrowse files
committed
[FrameworkBundle] Allow clearing private cache pools
1 parent 4033b60 commit 12d7fda
Copy full SHA for 12d7fda

File tree

11 files changed

+265
-15
lines changed
Filter options

11 files changed

+265
-15
lines changed

‎src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php
+19-8Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Console\Output\OutputInterface;
1818
use Symfony\Component\Console\Style\SymfonyStyle;
1919
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
20+
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
2021

2122
/**
2223
* Clear cache pools.
@@ -55,16 +56,21 @@ protected function execute(InputInterface $input, OutputInterface $output)
5556
$clearers = array();
5657
$container = $this->getContainer();
5758
$cacheDir = $container->getParameter('kernel.cache_dir');
59+
$globalClearer = $container->get('cache.global_clearer');
5860

5961
foreach ($input->getArgument('pools') as $id) {
60-
$pool = $container->get($id);
62+
try {
63+
$pool = $container->get($id);
6164

62-
if ($pool instanceof CacheItemPoolInterface) {
63-
$pools[$id] = $pool;
64-
} elseif ($pool instanceof Psr6CacheClearer) {
65-
$clearers[$id] = $pool;
66-
} else {
67-
throw new \InvalidArgumentException(sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
65+
if ($pool instanceof CacheItemPoolInterface) {
66+
$pools[$id] = $pool;
67+
} elseif ($pool instanceof Psr6CacheClearer) {
68+
$clearers[$id] = $pool;
69+
} else {
70+
throw new \InvalidArgumentException(sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
71+
}
72+
} catch (ServiceNotFoundException $e) {
73+
$pools[$id] = $id;
6874
}
6975
}
7076

@@ -75,7 +81,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
7581

7682
foreach ($pools as $id => $pool) {
7783
$io->comment(sprintf('Clearing cache pool: <info>%s</info>', $id));
78-
$pool->clear();
84+
85+
if ($pool instanceof CacheItemPoolInterface) {
86+
$pool->clear();
87+
} else {
88+
$globalClearer->clearPool($id);
89+
}
7990
}
8091

8192
$io->success('Cache was successfully cleared.');

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php
+15-3Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,31 @@ final class CachePoolClearerPass implements CompilerPassInterface
2727
public function process(ContainerBuilder $container)
2828
{
2929
$container->getParameterBag()->remove('cache.prefix.seed');
30+
$poolsByClearer = array();
31+
$pools = array();
3032

3133
foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) {
34+
$pools[$id] = new Reference($id);
3235
foreach (array_reverse($attributes) as $attr) {
3336
if (isset($attr['clearer'])) {
34-
$clearer = $container->getDefinition($attr['clearer']);
35-
$clearer->addMethodCall('addPool', array(new Reference($id)));
37+
$poolsByClearer[$attr['clearer']][$id] = $pools[$id];
3638
}
37-
if (array_key_exists('clearer', $attr)) {
39+
if (!empty($attr['unlazy'])) {
40+
$container->getDefinition($id)->setLazy(false);
41+
}
42+
if (array_key_exists('clearer', $attr) || array_key_exists('unlazy', $attr)) {
3843
break;
3944
}
4045
}
4146
}
4247

48+
$container->getDefinition('cache.global_clearer')->addArgument($pools);
49+
50+
foreach ($poolsByClearer as $clearer => $pools) {
51+
$clearer = $container->getDefinition($clearer);
52+
$clearer->addArgument($pools);
53+
}
54+
4355
if (!$container->has('cache.annotations')) {
4456
return;
4557
}

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php
+11-1Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ public function process(ContainerBuilder $container)
4747
if ($pool->isAbstract()) {
4848
continue;
4949
}
50+
$isLazy = $pool->isLazy();
5051
while ($adapter instanceof DefinitionDecorator) {
5152
$adapter = $container->findDefinition($adapter->getParent());
53+
$isLazy = $isLazy || $adapter->isLazy();
5254
if ($t = $adapter->getTag('cache.pool')) {
5355
$tags[0] += $t[0];
5456
}
@@ -80,8 +82,16 @@ public function process(ContainerBuilder $container)
8082
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]))));
8183
}
8284

85+
$attr = array();
8386
if (null !== $clearer) {
84-
$pool->addTag('cache.pool', array('clearer' => $clearer));
87+
$attr['clearer'] = $clearer;
88+
}
89+
if (!$isLazy) {
90+
$pool->setLazy(true);
91+
$attr['unlazy'] = true;
92+
}
93+
if ($attr) {
94+
$pool->addTag('cache.pool', $attr);
8595
}
8696
}
8797
}

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
<tag name="kernel.cache_clearer" />
9898
</service>
9999

100+
<service id="cache.global_clearer" parent="cache.default_clearer" />
100101
<service id="cache.app_clearer" alias="cache.default_clearer" />
101102

102103
</services>

‎src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
1919
use Symfony\Component\DependencyInjection\Definition;
2020
use Symfony\Component\DependencyInjection\Reference;
21+
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
2122

2223
class CachePoolClearerPassTest extends \PHPUnit_Framework_TestCase
2324
{
@@ -29,6 +30,9 @@ public function testPoolRefsAreWeak()
2930
$container->setParameter('kernel.environment', 'prod');
3031
$container->setParameter('kernel.root_dir', 'foo');
3132

33+
$globalClearer = new Definition(Psr6CacheClearer::class);
34+
$container->setDefinition('cache.global_clearer', $globalClearer);
35+
3236
$publicPool = new Definition();
3337
$publicPool->addArgument('namespace');
3438
$publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias'));
@@ -50,6 +54,7 @@ public function testPoolRefsAreWeak()
5054
$pass->process($container);
5155
}
5256

53-
$this->assertEquals(array(array('addPool', array(new Reference('public.pool')))), $clearer->getMethodCalls());
57+
$this->assertEquals(array(array('public.pool' => new Reference('public.pool'))), $clearer->getArguments());
58+
$this->assertEquals(array(array('public.pool' => new Reference('public.pool'))), $globalClearer->getArguments());
5459
}
5560
}
+86Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
13+
14+
use Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand;
15+
use Symfony\Component\Console\Tester\CommandTester;
16+
17+
/**
18+
* @group functional
19+
*/
20+
class CachePoolClearCommandTest extends WebTestCase
21+
{
22+
private $application;
23+
24+
protected function setUp()
25+
{
26+
static::bootKernel(array('test_case' => 'CachePoolClear', 'root_config' => 'config.yml'));
27+
}
28+
29+
public function testClearPrivatePool()
30+
{
31+
$tester = $this->createCommandTester();
32+
$tester->execute(array('pools' => array('cache.private_pool')), array('decorated' => false));
33+
34+
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
35+
$this->assertContains('Clearing cache pool: cache.private_pool', $tester->getDisplay());
36+
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
37+
}
38+
39+
public function testClearPublicPool()
40+
{
41+
$tester = $this->createCommandTester();
42+
$tester->execute(array('pools' => array('cache.public_pool')), array('decorated' => false));
43+
44+
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
45+
$this->assertContains('Clearing cache pool: cache.public_pool', $tester->getDisplay());
46+
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
47+
}
48+
49+
public function testClearPoolWithCustomClearer()
50+
{
51+
$tester = $this->createCommandTester();
52+
$tester->execute(array('pools' => array('cache.pool_with_clearer')), array('decorated' => false));
53+
54+
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
55+
$this->assertContains('Clearing cache pool: cache.pool_with_clearer', $tester->getDisplay());
56+
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
57+
}
58+
59+
public function testCallClearer()
60+
{
61+
$tester = $this->createCommandTester();
62+
$tester->execute(array('pools' => array('cache.default_clearer')), array('decorated' => false));
63+
64+
$this->assertSame(0, $tester->getStatusCode(), 'cache:pool:clear exits with 0 in case of success');
65+
$this->assertContains('Calling cache clearer: cache.default_clearer', $tester->getDisplay());
66+
$this->assertContains('[OK] Cache was successfully cleared.', $tester->getDisplay());
67+
}
68+
69+
/**
70+
* @expectedException \InvalidArgumentException
71+
* @expectedExceptionMessage Cache pool not found: unknown_pool
72+
*/
73+
public function testClearUnexistingPool()
74+
{
75+
$this->createCommandTester()
76+
->execute(array('pools' => array('unknown_pool')), array('decorated' => false));
77+
}
78+
79+
private function createCommandTester()
80+
{
81+
$command = new CachePoolClearCommand();
82+
$command->setContainer(static::$kernel->getContainer());
83+
84+
return new CommandTester($command);
85+
}
86+
}
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
13+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
14+
15+
return array(
16+
new FrameworkBundle(),
17+
new TestBundle(),
18+
);
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
imports:
2+
- { resource: ../config/default.yml }
3+
4+
services:
5+
dummy:
6+
class: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\DeclaredClass
7+
arguments: ['@cache.private_pool']
8+
custom_clearer:
9+
parent: cache.default_clearer
10+
tags:
11+
- name: kernel.cache_clearer
12+
13+
framework:
14+
cache:
15+
pools:
16+
cache.private_pool: ~
17+
cache.public_pool:
18+
public: true
19+
cache.pool_with_clearer:
20+
public: true
21+
clearer: custom_clearer

‎src/Symfony/Bundle/FrameworkBundle/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/composer.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"symfony/config": "~2.8|~3.0",
2424
"symfony/event-dispatcher": "~2.8|~3.0",
2525
"symfony/http-foundation": "~3.1",
26-
"symfony/http-kernel": "~3.2",
26+
"symfony/http-kernel": "~3.3",
2727
"symfony/polyfill-mbstring": "~1.0",
2828
"symfony/filesystem": "~2.8|~3.0",
2929
"symfony/finder": "~2.8|~3.0",

‎src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php
+19-1Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,27 @@ class Psr6CacheClearer implements CacheClearerInterface
2020
{
2121
private $pools = array();
2222

23+
public function __construct(array $pools = array())
24+
{
25+
$this->pools = $pools;
26+
}
27+
2328
public function addPool(CacheItemPoolInterface $pool)
2429
{
25-
$this->pools[] = $pool;
30+
@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__));
31+
32+
if (!in_array($pool, $this->pools, true)) {
33+
$this->pools[] = $pool;
34+
}
35+
}
36+
37+
public function clearPool($name)
38+
{
39+
if (!isset($this->pools[$name])) {
40+
throw new \InvalidArgumentException(sprintf('Cache pool not found: %s.', $name));
41+
}
42+
43+
$this->pools[$name]->clear();
2644
}
2745

2846
/**
+68Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpKernel\Tests\CacheClearer;
13+
14+
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
15+
use Psr\Cache\CacheItemPoolInterface;
16+
17+
class Psr6CacheClearerTest extends \PHPUnit_Framework_TestCase
18+
{
19+
public function testClearPoolsInjectedInConstructor()
20+
{
21+
$pool = $this->getMock(CacheItemPoolInterface::class);
22+
$pool
23+
->expects($this->once())
24+
->method('clear');
25+
26+
(new Psr6CacheClearer(array('pool' => $pool)))->clear('');
27+
}
28+
29+
public function testClearPool()
30+
{
31+
$pool = $this->getMock(CacheItemPoolInterface::class);
32+
$pool
33+
->expects($this->once())
34+
->method('clear');
35+
36+
(new Psr6CacheClearer(array('pool' => $pool)))->clearPool('pool');
37+
}
38+
39+
/**
40+
* @expectedException \InvalidArgumentException
41+
* @expectedExceptionMessage Cache pool not found: unknown
42+
*/
43+
public function testClearPoolThrowsExceptionOnUnreferencedPool()
44+
{
45+
(new Psr6CacheClearer())->clearPool('unknown');
46+
}
47+
48+
/**
49+
* @group legacy
50+
* @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.
51+
*/
52+
public function testClearPoolsInjectedByAdder()
53+
{
54+
$pool1 = $this->getMock(CacheItemPoolInterface::class);
55+
$pool1
56+
->expects($this->once())
57+
->method('clear');
58+
59+
$pool2 = $this->getMock(CacheItemPoolInterface::class);
60+
$pool2
61+
->expects($this->once())
62+
->method('clear');
63+
64+
$clearer = new Psr6CacheClearer(array('pool1' => $pool1));
65+
$clearer->addPool($pool2);
66+
$clearer->clear('');
67+
}
68+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.