-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[FrameworkBundle] integrate the Cache component #18371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bc51fde
281eafa
e44bfdc
92b1a20
4740c5c
714b916
4152634
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<?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\DependencyInjection\Compiler; | ||
|
||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\DefinitionDecorator; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
|
||
/** | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
class CachePoolPass implements CompilerPassInterface | ||
{ | ||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function process(ContainerBuilder $container) | ||
{ | ||
$attributes = array( | ||
'provider', | ||
'namespace', | ||
'default_lifetime', | ||
); | ||
foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) { | ||
$adapter = $pool = $container->getDefinition($id); | ||
if ($pool->isAbstract()) { | ||
continue; | ||
} | ||
if (!isset($tags[0]['namespace'])) { | ||
$tags[0]['namespace'] = $this->getNamespace($id); | ||
} | ||
while ($adapter instanceof DefinitionDecorator) { | ||
$adapter = $container->findDefinition($adapter->getParent()); | ||
if ($t = $adapter->getTag('cache.pool')) { | ||
$tags[0] += $t[0]; | ||
} | ||
} | ||
if (isset($tags[0]['clearer'])) { | ||
$clearer = $container->getDefinition($tags[0]['clearer']); | ||
} else { | ||
$clearer = null; | ||
} | ||
unset($tags[0]['clearer']); | ||
|
||
if (isset($tags[0]['provider']) && is_string($tags[0]['provider'])) { | ||
$tags[0]['provider'] = new Reference($tags[0]['provider']); | ||
} | ||
$i = 0; | ||
foreach ($attributes as $attr) { | ||
if (isset($tags[0][$attr])) { | ||
$pool->replaceArgument($i++, $tags[0][$attr]); | ||
} | ||
unset($tags[0][$attr]); | ||
} | ||
if (!empty($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])))); | ||
} | ||
|
||
if (null !== $clearer) { | ||
$clearer->addMethodCall('addPool', array(new Reference($id))); | ||
} | ||
} | ||
} | ||
|
||
private function getNamespace($id) | ||
{ | ||
return substr(str_replace('/', '-', base64_encode(md5('symfony.'.$id, true))), 0, 10); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?xml version="1.0" ?> | ||
|
||
<container xmlns="http://symfony.com/schema/dic/services" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> | ||
|
||
<services> | ||
|
||
<service id="cache.default_pools_clearer" class="Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer" public="false"> | ||
<tag name="kernel.cache_clearer" /> | ||
</service> | ||
|
||
<service id="cache.adapter.shared" alias="cache.adapter.filesystem" /> | ||
<service id="cache.adapter.local" alias="cache.adapter.filesystem" /> | ||
|
||
<service id="cache.pool.shared" parent="cache.adapter.shared"> | ||
<tag name="cache.pool" clearer="cache.default_pools_clearer" /> | ||
</service> | ||
|
||
<service id="cache.pool.local" parent="cache.adapter.local"> | ||
<tag name="cache.pool" clearer="cache.default_pools_clearer" /> | ||
</service> | ||
|
||
<service id="cache.adapter.apcu" class="Symfony\Component\Cache\Adapter\ApcuAdapter" abstract="true"> | ||
<argument /> <!-- namespace --> | ||
<argument /> <!-- default lifetime --> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In other services There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But default lifetime is always second... |
||
</service> | ||
|
||
<service id="cache.adapter.doctrine" class="Symfony\Component\Cache\Adapter\DoctrineAdapter" abstract="true"> | ||
<argument /> <!-- Doctrine provider service --> | ||
<argument /> <!-- namespace --> | ||
<argument /> <!-- default lifetime --> | ||
</service> | ||
|
||
<service id="cache.adapter.filesystem" class="Symfony\Component\Cache\Adapter\FilesystemAdapter" abstract="true"> | ||
<argument /> <!-- namespace --> | ||
<argument /> <!-- default lifetime --> | ||
<argument>%kernel.cache_dir%/pools</argument> | ||
</service> | ||
|
||
<service id="cache.adapter.psr6" class="Symfony\Component\Cache\Adapter\ProxyAdapter" abstract="true"> | ||
<argument /> <!-- PSR-6 provider service --> | ||
<argument /> <!-- namespace --> | ||
<argument /> <!-- default lifetime --> | ||
</service> | ||
|
||
<service id="cache.adapter.redis" class="Symfony\Component\Cache\Adapter\RedisAdapter" abstract="true"> | ||
<argument /> <!-- Redis connection object --> | ||
<argument /> <!-- namespace --> | ||
<argument /> <!-- default lifetime --> | ||
</service> | ||
|
||
</services> | ||
</container> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?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\DependencyInjection\Compiler; | ||
|
||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\DefinitionDecorator; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
|
||
class CachePoolPassTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
private $cachePoolPass; | ||
|
||
protected function setUp() | ||
{ | ||
$this->cachePoolPass = new CachePoolPass(); | ||
} | ||
|
||
public function testNamespaceArgumentIsReplaced() | ||
{ | ||
$container = new ContainerBuilder(); | ||
$adapter = new Definition(); | ||
$adapter->setAbstract(true); | ||
$adapter->addTag('cache.pool'); | ||
$container->setDefinition('app.cache_adapter', $adapter); | ||
$container->setAlias('app.cache_adapter_alias', 'app.cache_adapter'); | ||
$cachePool = new DefinitionDecorator('app.cache_adapter_alias'); | ||
$cachePool->addArgument(null); | ||
$cachePool->addTag('cache.pool'); | ||
$container->setDefinition('app.cache_pool', $cachePool); | ||
|
||
$this->cachePoolPass->process($container); | ||
|
||
$this->assertSame('yRnzIIVLvL', $cachePool->getArgument(0)); | ||
} | ||
|
||
public function testArgsAreReplaced() | ||
{ | ||
$container = new ContainerBuilder(); | ||
$cachePool = new Definition(); | ||
$cachePool->addTag('cache.pool', array( | ||
'provider' => 'foobar', | ||
'default_lifetime' => 3, | ||
)); | ||
$cachePool->addArgument(null); | ||
$cachePool->addArgument(null); | ||
$cachePool->addArgument(null); | ||
$container->setDefinition('app.cache_pool', $cachePool); | ||
|
||
$this->cachePoolPass->process($container); | ||
|
||
$this->assertInstanceOf(Reference::class, $cachePool->getArgument(0)); | ||
$this->assertSame('foobar', (string) $cachePool->getArgument(0)); | ||
$this->assertSame('yRnzIIVLvL', $cachePool->getArgument(1)); | ||
$this->assertSame(3, $cachePool->getArgument(2)); | ||
} | ||
|
||
/** | ||
* @expectedException \InvalidArgumentException | ||
* @expectedExceptionMessage Invalid "cache.pool" tag for service "app.cache_pool": accepted attributes are | ||
*/ | ||
public function testThrowsExceptionWhenCachePoolTagHasUnknownAttributes() | ||
{ | ||
$container = new ContainerBuilder(); | ||
$adapter = new Definition(); | ||
$adapter->setAbstract(true); | ||
$adapter->addTag('cache.pool'); | ||
$container->setDefinition('app.cache_adapter', $adapter); | ||
$cachePool = new DefinitionDecorator('app.cache_adapter'); | ||
$cachePool->addTag('cache.pool', array('foobar' => 123)); | ||
$container->setDefinition('app.cache_pool', $cachePool); | ||
|
||
$this->cachePoolPass->process($container); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
$container->loadFromExtension('framework', array( | ||
'cache' => array( | ||
'pools' => array( | ||
'foo' => array( | ||
'adapter' => 'cache.adapter.apcu', | ||
'default_lifetime' => 30, | ||
), | ||
'bar' => array( | ||
'adapter' => 'cache.adapter.doctrine', | ||
'default_lifetime' => 5, | ||
'provider' => 'app.doctrine_cache_provider', | ||
), | ||
'baz' => array( | ||
'adapter' => 'cache.adapter.filesystem', | ||
'default_lifetime' => 7, | ||
), | ||
'foobar' => array( | ||
'adapter' => 'cache.adapter.psr6', | ||
'default_lifetime' => 10, | ||
'provider' => 'app.cache_pool', | ||
), | ||
'def' => array( | ||
'default_lifetime' => 11, | ||
), | ||
), | ||
), | ||
)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could it make sense to apply several
cache.pool
tags on the service ? If yes, we need to handle all tags, not only the first one.If not, we may want to warn the user that subsequent tags are ignored to ease debugging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doesn't make sense. We can add a warning, but unless I'm wrong no other compiler passes do that...