diff --git a/UPGRADE-3.3.md b/UPGRADE-3.3.md
index 2989eaa550..2f0d91aade 100644
--- a/UPGRADE-3.3.md
+++ b/UPGRADE-3.3.md
@@ -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.
diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md
index b1c788de84..4a743b2da3 100644
--- a/UPGRADE-4.0.md
+++ b/UPGRADE-4.0.md
@@ -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
--------
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php
index 82934e1845..9c6ab53a82 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php
@@ -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: %s', $id));
- $pool->clear();
+
+ if ($pool instanceof CacheItemPoolInterface) {
+ $pool->clear();
+ } else {
+ $globalClearer->clearPool($id);
+ }
}
$io->success('Cache was successfully cleared.');
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php
index c859a6ba90..591d03c58a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php
@@ -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;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php
index 1e09b88214..e4e3bc3506 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php
@@ -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);
}
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml
index 80cb00ada9..c790ce5a6e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml
@@ -97,6 +97,7 @@
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php
index 38a2d38761..98caf89ba0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php
@@ -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());
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolClearCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolClearCommandTest.php
new file mode 100644
index 0000000000..59949dfdfd
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolClearCommandTest.php
@@ -0,0 +1,86 @@
+
+ *
+ * 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);
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePoolClear/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePoolClear/bundles.php
new file mode 100644
index 0000000000..a73987bcc9
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePoolClear/bundles.php
@@ -0,0 +1,18 @@
+
+ *
+ * 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(),
+);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePoolClear/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePoolClear/config.yml
new file mode 100644
index 0000000000..75107485ee
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePoolClear/config.yml
@@ -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
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index 6a45eb0177..0e43050e03 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -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",
diff --git a/src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php b/src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php
index 30261b3f7c..2336b18a29 100644
--- a/src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php
+++ b/src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php
@@ -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}
*/
diff --git a/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php b/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php
new file mode 100644
index 0000000000..dd47971120
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php
@@ -0,0 +1,68 @@
+
+ *
+ * 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('');
+ }
+}