feature #18371 [FrameworkBundle] integrate the Cache component (xabbuh, nicolas-grekas)
This PR was merged into the 3.1-dev branch. Discussion ---------- [FrameworkBundle] integrate the Cache component | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #17537 | License | MIT | Doc PR | - Last commit is the diff with #17868. Commits -------4152634
[FrameworkBundle] Add default pool & system adapter714b916
[FrameworkBundle] Add & use Psr6CacheClearer4740c5c
[FrameworkBundle] use abstract cache.pool decoration and aliases92b1a20
[FrameworkBundle] Fix and add tests for cache pool wiringe44bfdc
[FrameworkBundle] Add cache-pool tag and wiring281eafa
[FrameworkBundle] Integrate the Cache componentbc51fde
[Cache] Normalize constructor arguments order
This commit is contained in:
commit
0b67fa3dd1
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -114,6 +114,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
$this->addSerializerSection($rootNode);
|
$this->addSerializerSection($rootNode);
|
||||||
$this->addPropertyAccessSection($rootNode);
|
$this->addPropertyAccessSection($rootNode);
|
||||||
$this->addPropertyInfoSection($rootNode);
|
$this->addPropertyInfoSection($rootNode);
|
||||||
|
$this->addCacheSection($rootNode);
|
||||||
|
|
||||||
return $treeBuilder;
|
return $treeBuilder;
|
||||||
}
|
}
|
||||||
@ -547,4 +548,39 @@ class Configuration implements ConfigurationInterface
|
|||||||
->end()
|
->end()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function addCacheSection(ArrayNodeDefinition $rootNode)
|
||||||
|
{
|
||||||
|
$rootNode
|
||||||
|
->children()
|
||||||
|
->arrayNode('cache')
|
||||||
|
->info('Cache configuration')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->fixXmlConfig('pool')
|
||||||
|
->children()
|
||||||
|
->arrayNode('pools')
|
||||||
|
->useAttributeAsKey('name')
|
||||||
|
->prototype('array')
|
||||||
|
->children()
|
||||||
|
->scalarNode('adapter')
|
||||||
|
->info('The cache pool adapter service to use as template definition.')
|
||||||
|
->defaultValue('cache.adapter.shared')
|
||||||
|
->end()
|
||||||
|
->booleanNode('public')->defaultFalse()->end()
|
||||||
|
->integerNode('default_lifetime')->end()
|
||||||
|
->scalarNode('provider')
|
||||||
|
->info('The service name to use as provider when the specified adapter needs one.')
|
||||||
|
->end()
|
||||||
|
->scalarNode('namespace')
|
||||||
|
->info('The namespace where cached items are stored. Auto-generated by default. Set to false to disable namespacing.')
|
||||||
|
->end()
|
||||||
|
->scalarNode('clearer')->defaultValue('cache.default_pools_clearer')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,6 +122,7 @@ class FrameworkExtension extends Extension
|
|||||||
$this->registerFragmentsConfiguration($config['fragments'], $container, $loader);
|
$this->registerFragmentsConfiguration($config['fragments'], $container, $loader);
|
||||||
$this->registerTranslatorConfiguration($config['translator'], $container);
|
$this->registerTranslatorConfiguration($config['translator'], $container);
|
||||||
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
|
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
|
||||||
|
$this->registerCacheConfiguration($config['cache'], $container, $loader);
|
||||||
|
|
||||||
if ($this->isConfigEnabled($container, $config['router'])) {
|
if ($this->isConfigEnabled($container, $config['router'])) {
|
||||||
$this->registerRouterConfiguration($config['router'], $container, $loader);
|
$this->registerRouterConfiguration($config['router'], $container, $loader);
|
||||||
@ -1016,6 +1017,28 @@ class FrameworkExtension extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||||
|
{
|
||||||
|
$loader->load('cache_pools.xml');
|
||||||
|
|
||||||
|
foreach ($config['pools'] as $name => $poolConfig) {
|
||||||
|
$poolDefinition = new DefinitionDecorator($poolConfig['adapter']);
|
||||||
|
$poolDefinition->setPublic($poolConfig['public']);
|
||||||
|
unset($poolConfig['adapter'], $poolConfig['public']);
|
||||||
|
|
||||||
|
$poolDefinition->addTag('cache.pool', $poolConfig);
|
||||||
|
$container->setDefinition('cache.pool.'.$name, $poolDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addClassesToCompile(array(
|
||||||
|
'Psr\Cache\CacheItemInterface',
|
||||||
|
'Psr\Cache\CacheItemPoolInterface',
|
||||||
|
'Symfony\Component\Cache\Adapter\AdapterInterface',
|
||||||
|
'Symfony\Component\Cache\Adapter\AbstractAdapter',
|
||||||
|
'Symfony\Component\Cache\CacheItem',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a hash of the kernel root directory.
|
* Gets a hash of the kernel root directory.
|
||||||
*
|
*
|
||||||
|
@ -14,6 +14,7 @@ namespace Symfony\Bundle\FrameworkBundle;
|
|||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ControllerArgumentValueResolverPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ControllerArgumentValueResolverPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\PropertyInfoPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\PropertyInfoPass;
|
||||||
@ -89,6 +90,7 @@ class FrameworkBundle extends Bundle
|
|||||||
$container->addCompilerPass(new SerializerPass());
|
$container->addCompilerPass(new SerializerPass());
|
||||||
$container->addCompilerPass(new PropertyInfoPass());
|
$container->addCompilerPass(new PropertyInfoPass());
|
||||||
$container->addCompilerPass(new ControllerArgumentValueResolverPass());
|
$container->addCompilerPass(new ControllerArgumentValueResolverPass());
|
||||||
|
$container->addCompilerPass(new CachePoolPass());
|
||||||
|
|
||||||
if ($container->getParameter('kernel.debug')) {
|
if ($container->getParameter('kernel.debug')) {
|
||||||
$container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);
|
$container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);
|
||||||
|
@ -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 -->
|
||||||
|
</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>
|
@ -25,6 +25,7 @@
|
|||||||
<xsd:element name="property-access" type="property_access" minOccurs="0" maxOccurs="1" />
|
<xsd:element name="property-access" type="property_access" minOccurs="0" maxOccurs="1" />
|
||||||
<xsd:element name="serializer" type="serializer" minOccurs="0" maxOccurs="1" />
|
<xsd:element name="serializer" type="serializer" minOccurs="0" maxOccurs="1" />
|
||||||
<xsd:element name="property-info" type="property_info" minOccurs="0" maxOccurs="1" />
|
<xsd:element name="property-info" type="property_info" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xsd:element name="cache" type="cache" minOccurs="0" maxOccurs="1" />
|
||||||
</xsd:all>
|
</xsd:all>
|
||||||
|
|
||||||
<xsd:attribute name="http-method-override" type="xsd:boolean" />
|
<xsd:attribute name="http-method-override" type="xsd:boolean" />
|
||||||
@ -202,4 +203,19 @@
|
|||||||
<xsd:complexType name="property_info">
|
<xsd:complexType name="property_info">
|
||||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
|
|
||||||
|
<xsd:complexType name="cache">
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="pool" type="cache_pool" />
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
|
||||||
|
<xsd:complexType name="cache_pool">
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
<xsd:attribute name="adapter" type="xsd:string" />
|
||||||
|
<xsd:attribute name="public" type="xsd:boolean" />
|
||||||
|
<xsd:attribute name="default-lifetime" type="xsd:integer" />
|
||||||
|
<xsd:attribute name="provider" type="xsd:string" />
|
||||||
|
<xsd:attribute name="clearer" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
</xsd:schema>
|
</xsd:schema>
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -265,6 +265,9 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
|||||||
'base_urls' => array(),
|
'base_urls' => array(),
|
||||||
'packages' => array(),
|
'packages' => array(),
|
||||||
),
|
),
|
||||||
|
'cache' => array(
|
||||||
|
'pools' => array(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<container xmlns="http://symfony.com/schema/dic/services"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:framework="http://symfony.com/schema/dic/symfony"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
|
||||||
|
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
|
||||||
|
|
||||||
|
<framework:config>
|
||||||
|
<framework:cache>
|
||||||
|
<framework:pool name="foo" adapter="cache.adapter.apcu" default-lifetime="30" />
|
||||||
|
<framework:pool name="bar" adapter="cache.adapter.doctrine" default-lifetime="5" provider="app.doctrine_cache_provider" />
|
||||||
|
<framework:pool name="baz" adapter="cache.adapter.filesystem" default-lifetime="7" />
|
||||||
|
<framework:pool name="foobar" adapter="cache.adapter.psr6" default-lifetime="10" provider="app.cache_pool" />
|
||||||
|
<framework:pool name="def" default-lifetime="11" />
|
||||||
|
</framework:cache>
|
||||||
|
</framework:config>
|
||||||
|
</container>
|
@ -0,0 +1,19 @@
|
|||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
pools:
|
||||||
|
foo:
|
||||||
|
adapter: cache.adapter.apcu
|
||||||
|
default_lifetime: 30
|
||||||
|
bar:
|
||||||
|
adapter: cache.adapter.doctrine
|
||||||
|
default_lifetime: 5
|
||||||
|
provider: app.doctrine_cache_provider
|
||||||
|
baz:
|
||||||
|
adapter: cache.adapter.filesystem
|
||||||
|
default_lifetime: 7
|
||||||
|
foobar:
|
||||||
|
adapter: cache.adapter.psr6
|
||||||
|
default_lifetime: 10
|
||||||
|
provider: app.cache_pool
|
||||||
|
def:
|
||||||
|
default_lifetime: 11
|
@ -13,6 +13,9 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
|
|||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
|
||||||
|
use Symfony\Component\Cache\Adapter\ApcuAdapter;
|
||||||
|
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
|
||||||
|
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||||
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
|
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
|
||||||
@ -568,6 +571,17 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||||||
$this->assertTrue($container->has('property_info'));
|
$this->assertTrue($container->has('property_info'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCachePoolServices()
|
||||||
|
{
|
||||||
|
$container = $this->createContainerFromFile('cache');
|
||||||
|
|
||||||
|
$this->assertCachePoolServiceDefinitionIsCreated($container, 'foo', 'cache.adapter.apcu', 30);
|
||||||
|
$this->assertCachePoolServiceDefinitionIsCreated($container, 'bar', 'cache.adapter.doctrine', 5);
|
||||||
|
$this->assertCachePoolServiceDefinitionIsCreated($container, 'baz', 'cache.adapter.filesystem', 7);
|
||||||
|
$this->assertCachePoolServiceDefinitionIsCreated($container, 'foobar', 'cache.adapter.psr6', 10);
|
||||||
|
$this->assertCachePoolServiceDefinitionIsCreated($container, 'def', 'cache.adapter.filesystem', 11);
|
||||||
|
}
|
||||||
|
|
||||||
protected function createContainer(array $data = array())
|
protected function createContainer(array $data = array())
|
||||||
{
|
{
|
||||||
return new ContainerBuilder(new ParameterBag(array_merge(array(
|
return new ContainerBuilder(new ParameterBag(array_merge(array(
|
||||||
@ -636,4 +650,39 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||||||
$this->assertEquals($format, $versionStrategy->getArgument(1));
|
$this->assertEquals($format, $versionStrategy->getArgument(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertCachePoolServiceDefinitionIsCreated(ContainerBuilder $container, $name, $adapter, $defaultLifetime)
|
||||||
|
{
|
||||||
|
$id = 'cache.pool.'.$name;
|
||||||
|
|
||||||
|
$this->assertTrue($container->has($id), sprintf('Service definition "%s" for cache pool of type "%s" is registered', $id, $adapter));
|
||||||
|
|
||||||
|
$poolDefinition = $container->getDefinition($id);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(DefinitionDecorator::class, $poolDefinition, sprintf('Cache pool "%s" is based on an abstract cache pool.', $name));
|
||||||
|
|
||||||
|
$this->assertTrue($poolDefinition->hasTag('cache.pool'), sprintf('Service definition "%s" is tagged with the "cache.pool" tag.', $id));
|
||||||
|
$this->assertFalse($poolDefinition->isAbstract(), sprintf('Service definition "%s" is not abstract.', $id));
|
||||||
|
|
||||||
|
$tag = $poolDefinition->getTag('cache.pool');
|
||||||
|
$this->assertTrue(isset($tag[0]['default_lifetime']), 'The default lifetime is stored as an attribute of the "cache.pool" tag.');
|
||||||
|
$this->assertSame($defaultLifetime, $tag[0]['default_lifetime'], 'The default lifetime is stored as an attribute of the "cache.pool" tag.');
|
||||||
|
|
||||||
|
$adapterId = $poolDefinition->getParent();
|
||||||
|
$adapterDefinition = $container->findDefinition($adapterId);
|
||||||
|
|
||||||
|
switch ($adapter) {
|
||||||
|
case 'cache.adapter.apcu':
|
||||||
|
$this->assertSame(ApcuAdapter::class, $adapterDefinition->getClass());
|
||||||
|
break;
|
||||||
|
case 'cache.adapter.doctrine':
|
||||||
|
$this->assertSame(DoctrineAdapter::class, $adapterDefinition->getClass());
|
||||||
|
break;
|
||||||
|
case 'cache.adapter.filesystem':
|
||||||
|
$this->assertSame(FilesystemAdapter::class, $adapterDefinition->getClass());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($adapterDefinition->isAbstract(), sprintf('Service definition "%s" is abstract.', $adapterId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
<?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\Component\Cache\Adapter\FilesystemAdapter;
|
||||||
|
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||||
|
|
||||||
|
class CachePoolsTest extends WebTestCase
|
||||||
|
{
|
||||||
|
public function testCachePools()
|
||||||
|
{
|
||||||
|
$this->doTestCachePools(array(), FilesystemAdapter::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires extension redis
|
||||||
|
*/
|
||||||
|
public function testRedisCachePools()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->doTestCachePools(array('root_config' => 'redis_config.yml', 'environment' => 'redis_cache'), RedisAdapter::class);
|
||||||
|
} catch (\PHPUnit_Framework_Error_Warning $e) {
|
||||||
|
if (0 !== strpos($e->getMessage(), 'unable to connect to 127.0.0.1')) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
$this->markTestSkipped($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doTestCachePools($options, $adapterClass)
|
||||||
|
{
|
||||||
|
static::bootKernel($options);
|
||||||
|
$container = static::$kernel->getContainer();
|
||||||
|
|
||||||
|
$pool = $container->get('cache.pool.test');
|
||||||
|
$this->assertInstanceOf($adapterClass, $pool);
|
||||||
|
|
||||||
|
$key = 'foobar';
|
||||||
|
$pool->deleteItem($key);
|
||||||
|
$item = $pool->getItem($key);
|
||||||
|
$this->assertFalse($item->isHit());
|
||||||
|
|
||||||
|
$item->set('baz');
|
||||||
|
$pool->save($item);
|
||||||
|
$item = $pool->getItem($key);
|
||||||
|
$this->assertTrue($item->isHit());
|
||||||
|
|
||||||
|
$container->get('cache_clearer')->clear($container->getParameter('kernel.cache_dir'));
|
||||||
|
$item = $pool->getItem($key);
|
||||||
|
$this->assertFalse($item->isHit());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function createKernel(array $options = array())
|
||||||
|
{
|
||||||
|
return parent::createKernel(array('test_case' => 'CachePools') + $options);
|
||||||
|
}
|
||||||
|
}
|
@ -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,8 @@
|
|||||||
|
imports:
|
||||||
|
- { resource: ../config/default.yml }
|
||||||
|
|
||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
pools:
|
||||||
|
test:
|
||||||
|
public: true
|
@ -0,0 +1,22 @@
|
|||||||
|
imports:
|
||||||
|
- { resource: ../config/default.yml }
|
||||||
|
|
||||||
|
services:
|
||||||
|
cache.adapter.redis.connection:
|
||||||
|
public: false
|
||||||
|
class: Redis
|
||||||
|
calls:
|
||||||
|
- [connect, [127.0.0.1]]
|
||||||
|
|
||||||
|
cache.adapter.shared:
|
||||||
|
abstract: true
|
||||||
|
parent: cache.adapter.redis
|
||||||
|
tags:
|
||||||
|
- name: cache.pool
|
||||||
|
provider: cache.adapter.redis.connection
|
||||||
|
|
||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
pools:
|
||||||
|
test:
|
||||||
|
public: true
|
@ -18,8 +18,9 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.5.9",
|
"php": ">=5.5.9",
|
||||||
"symfony/asset": "~2.8|~3.0",
|
"symfony/asset": "~2.8|~3.0",
|
||||||
|
"symfony/cache": "~3.1",
|
||||||
"symfony/class-loader": "~2.8|~3.0",
|
"symfony/class-loader": "~2.8|~3.0",
|
||||||
"symfony/dependency-injection": "~2.8|~3.0",
|
"symfony/dependency-injection": "~3.1",
|
||||||
"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",
|
||||||
|
@ -20,7 +20,7 @@ class DoctrineAdapter extends AbstractAdapter
|
|||||||
{
|
{
|
||||||
private $provider;
|
private $provider;
|
||||||
|
|
||||||
public function __construct(CacheProvider $provider, $defaultLifetime = 0, $namespace = '')
|
public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0)
|
||||||
{
|
{
|
||||||
parent::__construct('', $defaultLifetime);
|
parent::__construct('', $defaultLifetime);
|
||||||
$this->provider = $provider;
|
$this->provider = $provider;
|
||||||
|
@ -20,7 +20,7 @@ class FilesystemAdapter extends AbstractAdapter
|
|||||||
{
|
{
|
||||||
private $directory;
|
private $directory;
|
||||||
|
|
||||||
public function __construct($directory, $defaultLifetime = 0, $namespace = '')
|
public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
|
||||||
{
|
{
|
||||||
parent::__construct('', $defaultLifetime);
|
parent::__construct('', $defaultLifetime);
|
||||||
|
|
||||||
@ -28,6 +28,9 @@ class FilesystemAdapter extends AbstractAdapter
|
|||||||
$directory = sys_get_temp_dir().'/symfony-cache';
|
$directory = sys_get_temp_dir().'/symfony-cache';
|
||||||
}
|
}
|
||||||
if (isset($namespace[0])) {
|
if (isset($namespace[0])) {
|
||||||
|
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
|
||||||
|
throw new InvalidArgumentException(sprintf('FilesystemAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
|
||||||
|
}
|
||||||
$directory .= '/'.$namespace;
|
$directory .= '/'.$namespace;
|
||||||
}
|
}
|
||||||
if (!file_exists($dir = $directory.'/.')) {
|
if (!file_exists($dir = $directory.'/.')) {
|
||||||
|
@ -28,7 +28,7 @@ class ProxyAdapter implements AdapterInterface
|
|||||||
private $hits = 0;
|
private $hits = 0;
|
||||||
private $misses = 0;
|
private $misses = 0;
|
||||||
|
|
||||||
public function __construct(CacheItemPoolInterface $pool, $defaultLifetime = 0, $namespace = '')
|
public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defaultLifetime = 0)
|
||||||
{
|
{
|
||||||
$this->pool = $pool;
|
$this->pool = $pool;
|
||||||
$this->namespace = $this->getId($namespace, true);
|
$this->namespace = $this->getId($namespace, true);
|
||||||
|
@ -28,7 +28,7 @@ class ChainAdapterTest extends CachePoolTest
|
|||||||
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
|
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ChainAdapter(array(new ArrayAdapter(), new ExternalAdapter(), new FilesystemAdapter(null)));
|
return new ChainAdapter(array(new ArrayAdapter(), new ExternalAdapter(), new FilesystemAdapter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +25,6 @@ class FilesystemAdapterTest extends CachePoolTest
|
|||||||
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
|
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FilesystemAdapter(sys_get_temp_dir().DIRECTORY_SEPARATOR.'sf-cache');
|
return new FilesystemAdapter('sf-cache');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,6 @@ class NamespacedProxyAdapterTest extends ProxyAdapterTest
|
|||||||
{
|
{
|
||||||
public function createCachePool()
|
public function createCachePool()
|
||||||
{
|
{
|
||||||
return new ProxyAdapter(new ArrayAdapter(), 0, 'foo');
|
return new ProxyAdapter(new ArrayAdapter(), 'foo');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ class RedisAdapterTest extends CachePoolTest
|
|||||||
$e = error_get_last();
|
$e = error_get_last();
|
||||||
self::markTestSkipped($e['message']);
|
self::markTestSkipped($e['message']);
|
||||||
}
|
}
|
||||||
self::$redis->select(1993);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
public static function tearDownAfterClass()
|
||||||
|
@ -58,8 +58,8 @@ class PassConfig
|
|||||||
|
|
||||||
$this->removingPasses = array(
|
$this->removingPasses = array(
|
||||||
new RemovePrivateAliasesPass(),
|
new RemovePrivateAliasesPass(),
|
||||||
new RemoveAbstractDefinitionsPass(),
|
|
||||||
new ReplaceAliasByActualDefinitionPass(),
|
new ReplaceAliasByActualDefinitionPass(),
|
||||||
|
new RemoveAbstractDefinitionsPass(),
|
||||||
new RepeatedPass(array(
|
new RepeatedPass(array(
|
||||||
new AnalyzeServiceReferencesPass(),
|
new AnalyzeServiceReferencesPass(),
|
||||||
new InlineServiceDefinitionsPass(),
|
new InlineServiceDefinitionsPass(),
|
||||||
@ -102,8 +102,7 @@ class PassConfig
|
|||||||
throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type));
|
throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type));
|
||||||
}
|
}
|
||||||
|
|
||||||
$passes = &$this->$property;
|
$this->{$property}[] = $pass;
|
||||||
$passes[] = $pass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,11 +96,11 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
|
|||||||
*/
|
*/
|
||||||
private function resolveDefinition(ContainerBuilder $container, DefinitionDecorator $definition)
|
private function resolveDefinition(ContainerBuilder $container, DefinitionDecorator $definition)
|
||||||
{
|
{
|
||||||
if (!$container->hasDefinition($parent = $definition->getParent())) {
|
if (!$container->has($parent = $definition->getParent())) {
|
||||||
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $this->currentId));
|
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $this->currentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
$parentDef = $container->getDefinition($parent);
|
$parentDef = $container->findDefinition($parent);
|
||||||
if ($parentDef instanceof DefinitionDecorator) {
|
if ($parentDef instanceof DefinitionDecorator) {
|
||||||
$id = $this->currentId;
|
$id = $this->currentId;
|
||||||
$this->currentId = $parent;
|
$this->currentId = $parent;
|
||||||
|
@ -309,6 +309,20 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals(array('Foo', 'Bar'), $def->getAutowiringTypes());
|
$this->assertEquals(array('Foo', 'Bar'), $def->getAutowiringTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testProcessResolvesAliases()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('parent', 'ParentClass');
|
||||||
|
$container->setAlias('parent_alias', 'parent');
|
||||||
|
$container->setDefinition('child', new DefinitionDecorator('parent_alias'));
|
||||||
|
|
||||||
|
$this->process($container);
|
||||||
|
|
||||||
|
$def = $container->getDefinition('child');
|
||||||
|
$this->assertSame('ParentClass', $def->getClass());
|
||||||
|
}
|
||||||
|
|
||||||
protected function process(ContainerBuilder $container)
|
protected function process(ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$pass = new ResolveDefinitionTemplatesPass();
|
$pass = new ResolveDefinitionTemplatesPass();
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
<?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\CacheClearer;
|
||||||
|
|
||||||
|
use Psr\Cache\CacheItemPoolInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
class Psr6CacheClearer implements CacheClearerInterface
|
||||||
|
{
|
||||||
|
private $pools = array();
|
||||||
|
|
||||||
|
public function addPool(CacheItemPoolInterface $pool)
|
||||||
|
{
|
||||||
|
$this->pools[] = $pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function clear($cacheDir)
|
||||||
|
{
|
||||||
|
foreach ($this->pools as $pool) {
|
||||||
|
$pool->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user