From e9f5e71f8f4f6af212c07fdbe21bde365dea4756 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 21 Feb 2016 00:25:19 +0100 Subject: [PATCH 1/6] [FrameworkBundle] integrate the Cache component --- .../Compiler/CacheAdapterPass.php | 88 ++++++++++++++ .../DependencyInjection/Configuration.php | 50 ++++++++ .../FrameworkExtension.php | 47 ++++++++ .../FrameworkBundle/FrameworkBundle.php | 2 + .../Resources/config/schema/symfony-1.0.xsd | 15 +++ .../Compiler/CacheAdapterPassTest.php | 109 ++++++++++++++++++ .../Fixtures/php/cache.php | 28 +++++ .../Fixtures/xml/cache.xml | 15 +++ .../Fixtures/yml/cache.yml | 17 +++ .../FrameworkExtensionTest.php | 47 ++++++++ 10 files changed, 418 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CacheAdapterPassTest.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php new file mode 100644 index 0000000000000..d8453caa89fd4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php @@ -0,0 +1,88 @@ + + * + * 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 Christian Flothmann + */ +class CacheAdapterPass implements CompilerPassInterface +{ + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $adapters = array(); + + foreach ($container->findTaggedServiceIds('cache.adapter') as $id => $tags) { + foreach ($tags as $attributes) { + $adapters[$attributes['id']] = array( + 'definition_id' => $id, + 'namespace_argument_index' => isset($attributes['namespace-arg-index']) ? $attributes['namespace-arg-index'] : null, + ); + } + } + + foreach ($container->getDefinitions() as $id => $definition) { + $definition->setArguments($this->resolveArguments($adapters, $id, $definition->getArguments())); + + $calls = $definition->getMethodCalls(); + + foreach ($calls as $index => $call) { + $calls[$index] = array($call[0], $this->resolveArguments($adapters, $id, $call[1])); + } + + $definition->setMethodCalls($calls); + + $definition->setProperties($this->resolveArguments($adapters, $id, $definition->getProperties())); + } + } + + private function resolveArguments(array $adapters, $id, array $arguments) + { + foreach ($arguments as $index => $argument) { + if ($argument instanceof Reference) { + $arguments[$index] = $this->createCacheAdapter($adapters, $id, $argument); + } + } + + return $arguments; + } + + private function createCacheAdapter(array $adapters, $serviceId, Reference $argument) + { + $adapterId = (string) $argument; + + if (0 !== strpos($adapterId, 'cache.adapter.')) { + return $argument; + } + + $name = substr($adapterId, 14); + + if (!isset($adapters[$name])) { + throw new \InvalidArgumentException(sprintf('The cache adapter "%s" is not configured.', $name)); + } + + $adapter = new DefinitionDecorator($adapters[$name]['definition_id']); + + if (null !== $adapters[$name]['namespace_argument_index']) { + $adapter->replaceArgument($adapters[$name]['namespace_argument_index'], sha1($serviceId)); + } + + return $adapter; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index ab55275b20b2c..6b2c4c21164bc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -114,6 +114,7 @@ public function getConfigTreeBuilder() $this->addSerializerSection($rootNode); $this->addPropertyAccessSection($rootNode); $this->addPropertyInfoSection($rootNode); + $this->addCacheSection($rootNode); return $treeBuilder; } @@ -547,4 +548,53 @@ private function addPropertyInfoSection(ArrayNodeDefinition $rootNode) ->end() ; } + + private function addCacheSection(ArrayNodeDefinition $rootNode) + { + $rootNode + ->children() + ->arrayNode('cache') + ->info('Cache configuration') + ->fixXmlConfig('adapter') + ->children() + ->arrayNode('adapters') + ->useAttributeAsKey('name') + ->prototype('array') + ->beforeNormalization() + ->always(function ($v) { + if (!isset($v['options'])) { + $v['options'] = array(); + } + + foreach ($v as $key => $value) { + if (!in_array($key, array('type', 'name', 'options'))) { + $v['options'][$key] = $value; + unset($v[$key]); + } + } + + return $v; + }) + ->end() + ->children() + ->enumNode('type') + ->info('The cache adapter type (one of "apcu", "doctrine", "filesystem")') + ->isRequired() + ->values(array('apcu', 'doctrine', 'filesystem')) + ->end() + ->arrayNode('options') + ->children() + ->integerNode('default_lifetime')->end() + ->scalarNode('cache_provider_service')->end() + ->scalarNode('directory')->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 324915ecb211d..8ae830b08f0a1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -12,6 +12,9 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection; use Doctrine\Common\Annotations\Reader; +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\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; @@ -138,6 +141,10 @@ public function load(array $configs, ContainerBuilder $container) $this->registerPropertyInfoConfiguration($config['property_info'], $container, $loader); } + if (isset($config['cache'])) { + $this->registerCacheConfiguration($config['cache'], $container); + } + $loader->load('debug_prod.xml'); $definition = $container->findDefinition('debug.debug_handlers_listener'); @@ -1017,6 +1024,46 @@ private function registerPropertyInfoConfiguration(array $config, ContainerBuild } } + private function registerCacheConfiguration(array $config, ContainerBuilder $container) + { + foreach ($config['adapters'] as $name => $adapter) { + $class = null; + $arguments = array(); + $namespaceArgumentIndex = null; + + switch ($adapter['type']) { + case 'apcu': + $class = ApcuAdapter::class; + $arguments[] = null; + $arguments[] = isset($adapter['options']['default_lifetime']) ? $adapter['options']['default_lifetime'] : 0; + $namespaceArgumentIndex = 0; + break; + case 'doctrine': + $class = DoctrineAdapter::class; + $arguments[] = isset($adapter['options']['cache_provider_service']) ? new Reference($adapter['options']['cache_provider_service']) : null; + $arguments[] = isset($adapter['options']['default_lifetime']) ? $adapter['options']['default_lifetime'] : null; + break; + case 'filesystem': + $class = FilesystemAdapter::class; + $arguments[] = isset($adapter['options']['directory']) ? $adapter['options']['directory'] : null; + $arguments[] = isset($adapter['options']['default_lifetime']) ? $adapter['options']['default_lifetime'] : null; + break; + } + + $tagAttributes = array('id' => $name); + + if (null !== $namespaceArgumentIndex) { + $tagAttributes['namespace-arg-index'] = $namespaceArgumentIndex; + } + + $adapterDefinition = new Definition($class); + $adapterDefinition->setArguments($arguments); + $adapterDefinition->setAbstract(true); + $adapterDefinition->addTag('cache.adapter', $tagAttributes); + $container->setDefinition('cache.adapter.'.$name, $adapterDefinition); + } + } + /** * Gets a hash of the kernel root directory. * diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 94062da0039f5..40dfcf0acf76a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -14,6 +14,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CacheAdapterPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\PropertyInfoPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass; @@ -87,6 +88,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new SerializerPass()); $container->addCompilerPass(new PropertyInfoPass()); + $container->addCompilerPass(new CacheAdapterPass()); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index cead2295ed1ac..79f295205f5ad 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -25,6 +25,7 @@ + @@ -202,4 +203,18 @@ + + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CacheAdapterPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CacheAdapterPassTest.php new file mode 100644 index 0000000000000..923189221f9e9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CacheAdapterPassTest.php @@ -0,0 +1,109 @@ + + * + * 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\CacheAdapterPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +class CacheAdapterPassTest extends \PHPUnit_Framework_TestCase +{ + private $cacheAdapterPass; + + protected function setUp() + { + $this->cacheAdapterPass = new CacheAdapterPass(); + } + + public function testAdapterIsInjectedIntoConstructorArguments() + { + $container = $this->initializeContainer(); + $this->cacheAdapterPass->process($container); + $adapter = $container->getDefinition('foo')->getArgument(0); + + $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $adapter); + $this->assertFalse($adapter->isAbstract()); + $this->assertSame('cache.adapter.apcu_adapter', $adapter->getParent()); + $this->assertSame('0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', $adapter->getArgument(0)); + } + + public function testAdapterIsInjectedIntoMethodArguments() + { + $container = $this->initializeContainer(); + $this->cacheAdapterPass->process($container); + $methodCalls = $container->getDefinition('bar')->getMethodCalls(); + $arguments = $methodCalls[0][1]; + $adapter = $arguments[0]; + + $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $adapter); + $this->assertFalse($adapter->isAbstract()); + $this->assertSame('cache.adapter.doctrine_adapter', $adapter->getParent()); + } + + public function testAdapterIsInjectIntoProperties() + { + $container = $this->initializeContainer(); + $this->cacheAdapterPass->process($container); + $properties = $container->getDefinition('baz')->getProperties(); + $adapter = $properties['cache']; + + $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $adapter); + $this->assertFalse($adapter->isAbstract()); + $this->assertSame('cache.adapter.fs_adapter', $adapter->getParent()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The cache adapter "bar" is not configured + */ + public function testThrowsExceptionWhenReferencedAdapterIsNotConfigured() + { + $container = new ContainerBuilder(); + $container->setDefinition('foo', new Definition('Foo', array(new Reference('cache.adapter.bar')))); + $this->cacheAdapterPass->process($container); + } + + private function initializeContainer() + { + $container = new ContainerBuilder(); + + $apcuAdapter = new Definition('Symfony\Component\Cache\Adapter\ApcuAdapter'); + $apcuAdapter->setAbstract(true); + $apcuAdapter->addTag('cache.adapter', array('id' => 'adapter1', 'namespace-arg-index' => 0)); + $container->setDefinition('cache.adapter.apcu_adapter', $apcuAdapter); + + $doctrineAdapter = new Definition('Symfony\Component\Cache\Adapter\DoctrineAdapter'); + $doctrineAdapter->setAbstract(true); + $doctrineAdapter->addTag('cache.adapter', array('id' => 'adapter2')); + $container->setDefinition('cache.adapter.doctrine_adapter', $doctrineAdapter); + + $filesystemAdapter = new Definition('Symfony\Component\Cache\Adapter\FilesystemAdapter'); + $filesystemAdapter->setAbstract(true); + $filesystemAdapter->addTag('cache.adapter', array('id' => 'adapter3')); + $container->setDefinition('cache.adapter.fs_adapter', $filesystemAdapter); + + $foo = new Definition(); + $foo->setArguments(array(new Reference('cache.adapter.adapter1'))); + $container->setDefinition('foo', $foo); + + $bar = new Definition(); + $bar->addMethodCall('setCache', array(new Reference('cache.adapter.adapter2'))); + $container->setDefinition('bar', $bar); + + $baz = new Definition(); + $baz->setProperty('cache', new Reference('cache.adapter.adapter3')); + $container->setDefinition('baz', $baz); + + return $container; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php new file mode 100644 index 0000000000000..a5c375ab3b740 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php @@ -0,0 +1,28 @@ +loadFromExtension('framework', array( + 'cache' => array( + 'adapters' => array( + 'foo' => array( + 'type' => 'apcu', + 'options' => array( + 'default_lifetime' => 30, + ), + ), + 'bar' => array( + 'type' => 'doctrine', + 'options' => array( + 'default_lifetime' => 5, + 'cache_provider_service' => 'app.doctrine_cache_provider', + ), + ), + 'baz' => array( + 'type' => 'filesystem', + 'options' => array( + 'default_lifetime' => 7, + 'directory' => 'app/cache/psr', + ), + ), + ), + ), +)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml new file mode 100644 index 0000000000000..086ea63a017af --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml new file mode 100644 index 0000000000000..9d0de6ad89ff1 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml @@ -0,0 +1,17 @@ +framework: + cache: + adapters: + foo: + type: apcu + options: + default_lifetime: 30 + bar: + type: doctrine + options: + default_lifetime: 5 + cache_provider_service: app.doctrine_cache_provider + baz: + type: filesystem + options: + default_lifetime: 7 + directory: app/cache/psr diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 55d9a16e77e5c..6643e7f1f73c8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -13,6 +13,9 @@ use Symfony\Bundle\FrameworkBundle\Tests\TestCase; 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\DefinitionDecorator; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; @@ -568,6 +571,15 @@ public function testPropertyInfoEnabled() $this->assertTrue($container->has('property_info')); } + public function testCacheAdaptersAbstractServices() + { + $container = $this->createContainerFromFile('cache'); + + $this->assertCacheAdapterIsRegistered($container, 'foo', 'apcu', array(null, 30), 0); + $this->assertCacheAdapterIsRegistered($container, 'bar', 'doctrine', array(new Reference('app.doctrine_cache_provider'), 5)); + $this->assertCacheAdapterIsRegistered($container, 'baz', 'filesystem', array('app/cache/psr', 7)); + } + protected function createContainer(array $data = array()) { return new ContainerBuilder(new ParameterBag(array_merge(array( @@ -636,4 +648,39 @@ private function assertVersionStrategy(ContainerBuilder $container, Reference $r $this->assertEquals($format, $versionStrategy->getArgument(1)); } } + + private function assertCacheAdapterIsRegistered(ContainerBuilder $container, $name, $type, array $arguments, $namespaceArgumentIndex = null) + { + $id = 'cache.adapter.'.$name; + + $this->assertTrue($container->has($id), sprintf('Service definition "%s" for cache adapter of type "%s" is registered', $id, $type)); + + $adapterDefinition = $container->getDefinition($id); + + switch ($type) { + case 'apcu': + $this->assertSame(ApcuAdapter::class, $adapterDefinition->getClass()); + break; + case 'doctrine': + $this->assertSame(DoctrineAdapter::class, $adapterDefinition->getClass()); + break; + case 'filesystem': + $this->assertSame(FilesystemAdapter::class, $adapterDefinition->getClass()); + break; + } + + $this->assertTrue($adapterDefinition->isAbstract(), sprintf('Service definition "%s" for cache adapter "%s" is abstract', $id, $name)); + $this->assertEquals($arguments, $adapterDefinition->getArguments()); + $this->assertTrue($adapterDefinition->hasTag('cache.adapter'), sprintf('Service definition "%s" is tagged with the "cache.adapter" tag.', $id)); + + $tag = $adapterDefinition->getTag('cache.adapter'); + + $this->assertTrue(isset($tag[0]['id']), 'The adapter name is the "id" attribute of the "cache.adapter" tag.'); + $this->assertSame($name, $tag[0]['id'], 'The adapter name is the "id" attribute of the "cache.adapter" tag.'); + + if (null !== $namespaceArgumentIndex) { + $this->assertTrue(isset($tag[0]['namespace-arg-index']), 'The namespace argument index is given by the "namespace-arg-index" attribute of the "cache.adapter" tag.'); + $this->assertSame($namespaceArgumentIndex, $tag[0]['namespace-arg-index'], 'The namespace argument index is given by the "namespace-arg-index" attribute of the "cache.adapter" tag.'); + } + } } From 0bfd3f591740eb0f7d18efb26be13f3c44b85f99 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 4 Mar 2016 18:43:16 +0100 Subject: [PATCH 2/6] [FrameworkBundle] Add wiring for cache-pool and cache-adapter service tags --- .../Compiler/CacheAdapterPass.php | 88 ------------------- .../Compiler/CachePoolPass.php | 64 ++++++++++++++ .../DependencyInjection/Configuration.php | 30 ++----- .../FrameworkExtension.php | 48 +++------- .../FrameworkBundle/FrameworkBundle.php | 4 +- .../Resources/config/cache_adapters.xml | 30 +++++++ .../Resources/config/schema/symfony-1.0.xsd | 4 +- ...pterPassTest.php => CachePoolPassTest.php} | 16 ++-- 8 files changed, 125 insertions(+), 159 deletions(-) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/{Compiler/CacheAdapterPassTest.php => CachePoolPassTest.php} (91%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php deleted file mode 100644 index d8453caa89fd4..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CacheAdapterPass.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * 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 Christian Flothmann - */ -class CacheAdapterPass implements CompilerPassInterface -{ - /** - * {@inheritdoc} - */ - public function process(ContainerBuilder $container) - { - $adapters = array(); - - foreach ($container->findTaggedServiceIds('cache.adapter') as $id => $tags) { - foreach ($tags as $attributes) { - $adapters[$attributes['id']] = array( - 'definition_id' => $id, - 'namespace_argument_index' => isset($attributes['namespace-arg-index']) ? $attributes['namespace-arg-index'] : null, - ); - } - } - - foreach ($container->getDefinitions() as $id => $definition) { - $definition->setArguments($this->resolveArguments($adapters, $id, $definition->getArguments())); - - $calls = $definition->getMethodCalls(); - - foreach ($calls as $index => $call) { - $calls[$index] = array($call[0], $this->resolveArguments($adapters, $id, $call[1])); - } - - $definition->setMethodCalls($calls); - - $definition->setProperties($this->resolveArguments($adapters, $id, $definition->getProperties())); - } - } - - private function resolveArguments(array $adapters, $id, array $arguments) - { - foreach ($arguments as $index => $argument) { - if ($argument instanceof Reference) { - $arguments[$index] = $this->createCacheAdapter($adapters, $id, $argument); - } - } - - return $arguments; - } - - private function createCacheAdapter(array $adapters, $serviceId, Reference $argument) - { - $adapterId = (string) $argument; - - if (0 !== strpos($adapterId, 'cache.adapter.')) { - return $argument; - } - - $name = substr($adapterId, 14); - - if (!isset($adapters[$name])) { - throw new \InvalidArgumentException(sprintf('The cache adapter "%s" is not configured.', $name)); - } - - $adapter = new DefinitionDecorator($adapters[$name]['definition_id']); - - if (null !== $adapters[$name]['namespace_argument_index']) { - $adapter->replaceArgument($adapters[$name]['namespace_argument_index'], sha1($serviceId)); - } - - return $adapter; - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php new file mode 100644 index 0000000000000..e4e6487209fe1 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php @@ -0,0 +1,64 @@ + + * + * 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 + */ +class CachePoolPass implements CompilerPassInterface +{ + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) { + $pool = $container->getDefinition($id); + $namespaceArgIndex = isset($tags[0]['namespace_arg_index']) ? $tags[0]['namespace_arg_index'] : -1; + + if (!$pool instanceof DefinitionDecorator) { + throw new \InvalidArgumentException(sprintf('Services tagged with "cache.pool" must have a parent service but "%s" has none.', $id)); + } + + $adapter = $pool; + + do { + $adapterId = $adapter->getParent(); + $adapter = $container->getDefinition($adapterId); + } while ($adapter instanceof DefinitionDecorator && !$adapter->getTag('cache.adapter')); + + $tags = $adapter->getTag('cache.adapter'); + + if (!isset($tags[0]['namespace_arg_index'])) { + throw new \InvalidArgumentException(sprintf('Invalid "cache.adapter" tag for service "%s": attribute "namespace_arg_index" is missing.', $adapterId)); + } + + if (!$adapter->isAbstract()) { + throw new \InvalidArgumentException(sprintf('Services tagged as "cache.adapter" must be abstract: "%s" is not.', $adapterId)); + } + + if (0 <= $namespaceArgIndex) { + $pool->replaceArgument($namespaceArgIndex, $this->getNamespace($id)); + } + } + } + + private function getNamespace($id) + { + return substr(str_replace('/', '-', base64_encode(md5('symfony.'.$id, true)), 0, 10)); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 6b2c4c21164bc..fed11eac7d8ea 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -555,40 +555,22 @@ private function addCacheSection(ArrayNodeDefinition $rootNode) ->children() ->arrayNode('cache') ->info('Cache configuration') - ->fixXmlConfig('adapter') + ->fixXmlConfig('pool') ->children() - ->arrayNode('adapters') + ->arrayNode('pool') ->useAttributeAsKey('name') ->prototype('array') ->beforeNormalization() - ->always(function ($v) { - if (!isset($v['options'])) { - $v['options'] = array(); - } - - foreach ($v as $key => $value) { - if (!in_array($key, array('type', 'name', 'options'))) { - $v['options'][$key] = $value; - unset($v[$key]); - } - } - - return $v; - }) ->end() ->children() ->enumNode('type') - ->info('The cache adapter type (one of "apcu", "doctrine", "filesystem")') + ->info('The cache pool type (one of "apcu", "doctrine" or "filesystem")') ->isRequired() ->values(array('apcu', 'doctrine', 'filesystem')) ->end() - ->arrayNode('options') - ->children() - ->integerNode('default_lifetime')->end() - ->scalarNode('cache_provider_service')->end() - ->scalarNode('directory')->end() - ->end() - ->end() + ->integerNode('default_lifetime')->default(0)->end() + ->scalarNode('cache_provider_service')->defaultNull()->end() + ->scalarNode('directory')->defaultNull()->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 8ae830b08f0a1..28be434f40ffd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -12,9 +12,6 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection; use Doctrine\Common\Annotations\Reader; -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\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; @@ -1024,43 +1021,24 @@ private function registerPropertyInfoConfiguration(array $config, ContainerBuild } } - private function registerCacheConfiguration(array $config, ContainerBuilder $container) + private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) { - foreach ($config['adapters'] as $name => $adapter) { - $class = null; - $arguments = array(); - $namespaceArgumentIndex = null; - - switch ($adapter['type']) { - case 'apcu': - $class = ApcuAdapter::class; - $arguments[] = null; - $arguments[] = isset($adapter['options']['default_lifetime']) ? $adapter['options']['default_lifetime'] : 0; - $namespaceArgumentIndex = 0; - break; - case 'doctrine': - $class = DoctrineAdapter::class; - $arguments[] = isset($adapter['options']['cache_provider_service']) ? new Reference($adapter['options']['cache_provider_service']) : null; - $arguments[] = isset($adapter['options']['default_lifetime']) ? $adapter['options']['default_lifetime'] : null; - break; - case 'filesystem': - $class = FilesystemAdapter::class; - $arguments[] = isset($adapter['options']['directory']) ? $adapter['options']['directory'] : null; - $arguments[] = isset($adapter['options']['default_lifetime']) ? $adapter['options']['default_lifetime'] : null; - break; - } + if (!empty($config['pool'])) { + $loader->load('cache_adapters.xml'); + } - $tagAttributes = array('id' => $name); + foreach ($config['pool'] as $name => $poolConfig) { + $poolDefinition = new DefinitionDecorator('cache.adapter.'.$poolConfig['type']); + $poolDefinition->replaceArgument(1, $poolConfig['default_lifetime']); - if (null !== $namespaceArgumentIndex) { - $tagAttributes['namespace-arg-index'] = $namespaceArgumentIndex; + if ('doctrine' === $poolConfig['type']) { + $poolDefinition->replaceArgument(0, new Reference($poolConfig['cache_provider_service'])); + } elseif ('filesystem' === $poolConfig['type'] && isset($poolConfig['directory'][0])) { + $poolDefinition->replaceArgument(0, $poolConfig['directory']); } - $adapterDefinition = new Definition($class); - $adapterDefinition->setArguments($arguments); - $adapterDefinition->setAbstract(true); - $adapterDefinition->addTag('cache.adapter', $tagAttributes); - $container->setDefinition('cache.adapter.'.$name, $adapterDefinition); + $poolDefinition->addTag('cache.pool'); + $container->setDefinition('cache.pool.'.$name, $poolDefinition); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 40dfcf0acf76a..9c0c91eda6b1f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -14,7 +14,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; -use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CacheAdapterPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\PropertyInfoPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass; @@ -88,7 +88,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new SerializerPass()); $container->addCompilerPass(new PropertyInfoPass()); - $container->addCompilerPass(new CacheAdapterPass()); + $container->addCompilerPass(new CachePoolPass()); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml new file mode 100644 index 0000000000000..02a9e6dfb5ccb --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + %kernel.cache_dir% + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 79f295205f5ad..cee9299e44e58 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -206,11 +206,11 @@ - + - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CacheAdapterPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/CachePoolPassTest.php similarity index 91% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CacheAdapterPassTest.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/CachePoolPassTest.php index 923189221f9e9..033809fcda76d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CacheAdapterPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/CachePoolPassTest.php @@ -11,24 +11,24 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; -use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CacheAdapterPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; -class CacheAdapterPassTest extends \PHPUnit_Framework_TestCase +class CachePoolPassTest extends \PHPUnit_Framework_TestCase { - private $cacheAdapterPass; + private $cachePoolPass; protected function setUp() { - $this->cacheAdapterPass = new CacheAdapterPass(); + $this->cachePoolPass = new CachePoolPass(); } public function testAdapterIsInjectedIntoConstructorArguments() { $container = $this->initializeContainer(); - $this->cacheAdapterPass->process($container); + $this->cachePoolPass->process($container); $adapter = $container->getDefinition('foo')->getArgument(0); $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $adapter); @@ -40,7 +40,7 @@ public function testAdapterIsInjectedIntoConstructorArguments() public function testAdapterIsInjectedIntoMethodArguments() { $container = $this->initializeContainer(); - $this->cacheAdapterPass->process($container); + $this->cachePoolPass->process($container); $methodCalls = $container->getDefinition('bar')->getMethodCalls(); $arguments = $methodCalls[0][1]; $adapter = $arguments[0]; @@ -53,7 +53,7 @@ public function testAdapterIsInjectedIntoMethodArguments() public function testAdapterIsInjectIntoProperties() { $container = $this->initializeContainer(); - $this->cacheAdapterPass->process($container); + $this->cachePoolPass->process($container); $properties = $container->getDefinition('baz')->getProperties(); $adapter = $properties['cache']; @@ -70,7 +70,7 @@ public function testThrowsExceptionWhenReferencedAdapterIsNotConfigured() { $container = new ContainerBuilder(); $container->setDefinition('foo', new Definition('Foo', array(new Reference('cache.adapter.bar')))); - $this->cacheAdapterPass->process($container); + $this->cachePoolPass->process($container); } private function initializeContainer() From 6bf21a485eda2500887b973f0710ab775522d37a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 10 Mar 2016 18:21:29 +0100 Subject: [PATCH 3/6] [FrameworkBundle] Add PSR-6 cache pool proxying --- .../DependencyInjection/Configuration.php | 4 ++-- .../DependencyInjection/FrameworkExtension.php | 2 +- .../FrameworkBundle/Resources/config/cache_adapters.xml | 9 ++++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index fed11eac7d8ea..d5ee6e65ac266 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -564,9 +564,9 @@ private function addCacheSection(ArrayNodeDefinition $rootNode) ->end() ->children() ->enumNode('type') - ->info('The cache pool type (one of "apcu", "doctrine" or "filesystem")') + ->info('The cache pool type (one of "apcu", "doctrine", "psr6" or "filesystem")') ->isRequired() - ->values(array('apcu', 'doctrine', 'filesystem')) + ->values(array('apcu', 'doctrine', 'psr6', 'filesystem')) ->end() ->integerNode('default_lifetime')->default(0)->end() ->scalarNode('cache_provider_service')->defaultNull()->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 28be434f40ffd..d0d8d1a29e499 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1031,7 +1031,7 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con $poolDefinition = new DefinitionDecorator('cache.adapter.'.$poolConfig['type']); $poolDefinition->replaceArgument(1, $poolConfig['default_lifetime']); - if ('doctrine' === $poolConfig['type']) { + if ('doctrine' === $poolConfig['type'] || 'psr6' === $poolConfig['type']) { $poolDefinition->replaceArgument(0, new Reference($poolConfig['cache_provider_service'])); } elseif ('filesystem' === $poolConfig['type'] && isset($poolConfig['directory'][0])) { $poolDefinition->replaceArgument(0, $poolConfig['directory']); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml index 02a9e6dfb5ccb..13612a1d28612 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml @@ -14,7 +14,14 @@ - + + + + + + + + From fba8f64a0cc07609f4591c2d66e790cf0c0c6a6b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 11 Mar 2016 09:48:42 +0100 Subject: [PATCH 4/6] fix cache pool wiring --- .../DependencyInjection/Compiler/CachePoolPass.php | 2 +- .../FrameworkBundle/DependencyInjection/Configuration.php | 4 +--- .../DependencyInjection/{ => Compiler}/CachePoolPassTest.php | 0 3 files changed, 2 insertions(+), 4 deletions(-) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/{ => Compiler}/CachePoolPassTest.php (100%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php index e4e6487209fe1..de32ab761ddcf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php @@ -59,6 +59,6 @@ public function process(ContainerBuilder $container) private function getNamespace($id) { - return substr(str_replace('/', '-', base64_encode(md5('symfony.'.$id, true)), 0, 10)); + return substr(str_replace('/', '-', base64_encode(md5('symfony.'.$id, true))), 0, 10); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index d5ee6e65ac266..59ecd8c7c1c51 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -560,15 +560,13 @@ private function addCacheSection(ArrayNodeDefinition $rootNode) ->arrayNode('pool') ->useAttributeAsKey('name') ->prototype('array') - ->beforeNormalization() - ->end() ->children() ->enumNode('type') ->info('The cache pool type (one of "apcu", "doctrine", "psr6" or "filesystem")') ->isRequired() ->values(array('apcu', 'doctrine', 'psr6', 'filesystem')) ->end() - ->integerNode('default_lifetime')->default(0)->end() + ->integerNode('default_lifetime')->defaultValue(0)->end() ->scalarNode('cache_provider_service')->defaultNull()->end() ->scalarNode('directory')->defaultNull()->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/CachePoolPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/CachePoolPassTest.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php From aecb0078de7c7b73a6920be51a716a321bf702cd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 11 Mar 2016 10:22:28 +0100 Subject: [PATCH 5/6] fix FrameworkExtension tests --- .../Compiler/CachePoolPass.php | 10 +- .../DependencyInjection/Configuration.php | 2 +- .../FrameworkExtension.php | 6 +- .../Resources/config/cache_adapters.xml | 8 +- .../Compiler/CachePoolPassTest.php | 113 +++++++++--------- .../Fixtures/php/cache.php | 18 +-- .../Fixtures/xml/cache.xml | 6 +- .../Fixtures/yml/cache.yml | 15 +-- .../FrameworkExtensionTest.php | 26 ++-- 9 files changed, 98 insertions(+), 106 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php index de32ab761ddcf..395169caaca47 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php @@ -14,7 +14,6 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\DefinitionDecorator; -use Symfony\Component\DependencyInjection\Reference; /** * @author Nicolas Grekas @@ -28,7 +27,6 @@ public function process(ContainerBuilder $container) { foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) { $pool = $container->getDefinition($id); - $namespaceArgIndex = isset($tags[0]['namespace_arg_index']) ? $tags[0]['namespace_arg_index'] : -1; if (!$pool instanceof DefinitionDecorator) { throw new \InvalidArgumentException(sprintf('Services tagged with "cache.pool" must have a parent service but "%s" has none.', $id)); @@ -39,7 +37,11 @@ public function process(ContainerBuilder $container) do { $adapterId = $adapter->getParent(); $adapter = $container->getDefinition($adapterId); - } while ($adapter instanceof DefinitionDecorator && !$adapter->getTag('cache.adapter')); + } while ($adapter instanceof DefinitionDecorator && !$adapter->hasTag('cache.adapter')); + + if (!$adapter->hasTag('cache.adapter')) { + throw new \InvalidArgumentException(sprintf('Services tagged with "cache.pool" must have a parent service tagged with "cache.adapter" but "%s" has none.', $id)); + } $tags = $adapter->getTag('cache.adapter'); @@ -51,7 +53,7 @@ public function process(ContainerBuilder $container) throw new \InvalidArgumentException(sprintf('Services tagged as "cache.adapter" must be abstract: "%s" is not.', $adapterId)); } - if (0 <= $namespaceArgIndex) { + if (0 <= $namespaceArgIndex = $tags[0]['namespace_arg_index']) { $pool->replaceArgument($namespaceArgIndex, $this->getNamespace($id)); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 59ecd8c7c1c51..83981d8c76603 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -557,7 +557,7 @@ private function addCacheSection(ArrayNodeDefinition $rootNode) ->info('Cache configuration') ->fixXmlConfig('pool') ->children() - ->arrayNode('pool') + ->arrayNode('pools') ->useAttributeAsKey('name') ->prototype('array') ->children() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index d0d8d1a29e499..956610f410c85 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -139,7 +139,7 @@ public function load(array $configs, ContainerBuilder $container) } if (isset($config['cache'])) { - $this->registerCacheConfiguration($config['cache'], $container); + $this->registerCacheConfiguration($config['cache'], $container, $loader); } $loader->load('debug_prod.xml'); @@ -1023,11 +1023,11 @@ private function registerPropertyInfoConfiguration(array $config, ContainerBuild private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) { - if (!empty($config['pool'])) { + if (!empty($config['pools'])) { $loader->load('cache_adapters.xml'); } - foreach ($config['pool'] as $name => $poolConfig) { + foreach ($config['pools'] as $name => $poolConfig) { $poolDefinition = new DefinitionDecorator('cache.adapter.'.$poolConfig['type']); $poolDefinition->replaceArgument(1, $poolConfig['default_lifetime']); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml index 13612a1d28612..9c49c8672de8d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml @@ -7,27 +7,27 @@ - + - + - + - + %kernel.cache_dir% diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php index 033809fcda76d..f07c04c7e0767 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php @@ -14,7 +14,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\DefinitionDecorator; class CachePoolPassTest extends \PHPUnit_Framework_TestCase { @@ -25,85 +25,84 @@ protected function setUp() $this->cachePoolPass = new CachePoolPass(); } - public function testAdapterIsInjectedIntoConstructorArguments() + public function testNamespaceArgumentIsReplaced() { - $container = $this->initializeContainer(); + $container = new ContainerBuilder(); + $adapter = new Definition(); + $adapter->setAbstract(true); + $adapter->addTag('cache.adapter', array('namespace_arg_index' => 0)); + $container->setDefinition('app.cache_adapter', $adapter); + $cachePool = new DefinitionDecorator('app.cache_adapter'); + $cachePool->addArgument(null); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); + $this->cachePoolPass->process($container); - $adapter = $container->getDefinition('foo')->getArgument(0); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $adapter); - $this->assertFalse($adapter->isAbstract()); - $this->assertSame('cache.adapter.apcu_adapter', $adapter->getParent()); - $this->assertSame('0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', $adapter->getArgument(0)); + $this->assertSame('yRnzIIVLvL', $cachePool->getArgument(0)); } - public function testAdapterIsInjectedIntoMethodArguments() + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Services tagged with "cache.pool" must have a parent service but "app.cache_pool" has none. + */ + public function testThrowsExceptionWhenCachePoolHasNoParentDefinition() { - $container = $this->initializeContainer(); - $this->cachePoolPass->process($container); - $methodCalls = $container->getDefinition('bar')->getMethodCalls(); - $arguments = $methodCalls[0][1]; - $adapter = $arguments[0]; + $container = new ContainerBuilder(); + $cachePool = new Definition(); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $adapter); - $this->assertFalse($adapter->isAbstract()); - $this->assertSame('cache.adapter.doctrine_adapter', $adapter->getParent()); + $this->cachePoolPass->process($container); } - public function testAdapterIsInjectIntoProperties() + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Services tagged with "cache.pool" must have a parent service tagged with "cache.adapter" but "app.cache_pool" has none. + */ + public function testThrowsExceptionWhenCachePoolIsNotBasedOnAdapter() { - $container = $this->initializeContainer(); - $this->cachePoolPass->process($container); - $properties = $container->getDefinition('baz')->getProperties(); - $adapter = $properties['cache']; + $container = new ContainerBuilder(); + $container->register('app.cache_adapter'); + $cachePool = new DefinitionDecorator('app.cache_adapter'); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $adapter); - $this->assertFalse($adapter->isAbstract()); - $this->assertSame('cache.adapter.fs_adapter', $adapter->getParent()); + $this->cachePoolPass->process($container); } /** * @expectedException \InvalidArgumentException - * @expectedExceptionMessage The cache adapter "bar" is not configured + * @expectedExceptionMessage Invalid "cache.adapter" tag for service "app.cache_adapter": attribute "namespace_arg_index" is missing. */ - public function testThrowsExceptionWhenReferencedAdapterIsNotConfigured() + public function testThrowsExceptionWhenCacheAdapterDefinesNoNamespaceArgument() { $container = new ContainerBuilder(); - $container->setDefinition('foo', new Definition('Foo', array(new Reference('cache.adapter.bar')))); + $adapter = new Definition(); + $adapter->setAbstract(true); + $adapter->addTag('cache.adapter'); + $container->setDefinition('app.cache_adapter', $adapter); + $cachePool = new DefinitionDecorator('app.cache_adapter'); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); + $this->cachePoolPass->process($container); } - private function initializeContainer() + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Services tagged as "cache.adapter" must be abstract: "app.cache_adapter" is not. + */ + public function testThrowsExceptionWhenCacheAdapterIsNotAbstract() { $container = new ContainerBuilder(); + $adapter = new Definition(); + $adapter->addTag('cache.adapter', array('namespace_arg_index' => 0)); + $container->setDefinition('app.cache_adapter', $adapter); + $cachePool = new DefinitionDecorator('app.cache_adapter'); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); - $apcuAdapter = new Definition('Symfony\Component\Cache\Adapter\ApcuAdapter'); - $apcuAdapter->setAbstract(true); - $apcuAdapter->addTag('cache.adapter', array('id' => 'adapter1', 'namespace-arg-index' => 0)); - $container->setDefinition('cache.adapter.apcu_adapter', $apcuAdapter); - - $doctrineAdapter = new Definition('Symfony\Component\Cache\Adapter\DoctrineAdapter'); - $doctrineAdapter->setAbstract(true); - $doctrineAdapter->addTag('cache.adapter', array('id' => 'adapter2')); - $container->setDefinition('cache.adapter.doctrine_adapter', $doctrineAdapter); - - $filesystemAdapter = new Definition('Symfony\Component\Cache\Adapter\FilesystemAdapter'); - $filesystemAdapter->setAbstract(true); - $filesystemAdapter->addTag('cache.adapter', array('id' => 'adapter3')); - $container->setDefinition('cache.adapter.fs_adapter', $filesystemAdapter); - - $foo = new Definition(); - $foo->setArguments(array(new Reference('cache.adapter.adapter1'))); - $container->setDefinition('foo', $foo); - - $bar = new Definition(); - $bar->addMethodCall('setCache', array(new Reference('cache.adapter.adapter2'))); - $container->setDefinition('bar', $bar); - - $baz = new Definition(); - $baz->setProperty('cache', new Reference('cache.adapter.adapter3')); - $container->setDefinition('baz', $baz); - - return $container; + $this->cachePoolPass->process($container); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php index a5c375ab3b740..c35d3106998be 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php @@ -2,26 +2,20 @@ $container->loadFromExtension('framework', array( 'cache' => array( - 'adapters' => array( + 'pools' => array( 'foo' => array( 'type' => 'apcu', - 'options' => array( - 'default_lifetime' => 30, - ), + 'default_lifetime' => 30, ), 'bar' => array( 'type' => 'doctrine', - 'options' => array( - 'default_lifetime' => 5, - 'cache_provider_service' => 'app.doctrine_cache_provider', - ), + 'default_lifetime' => 5, + 'cache_provider_service' => 'app.doctrine_cache_provider', ), 'baz' => array( 'type' => 'filesystem', - 'options' => array( - 'default_lifetime' => 7, - 'directory' => 'app/cache/psr', - ), + 'default_lifetime' => 7, + 'directory' => 'app/cache/psr', ), ), ), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml index 086ea63a017af..1bdc9f2375cdb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml index 9d0de6ad89ff1..c146b6741d182 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml @@ -1,17 +1,14 @@ framework: cache: - adapters: + pools: foo: type: apcu - options: - default_lifetime: 30 + default_lifetime: 30 bar: type: doctrine - options: - default_lifetime: 5 - cache_provider_service: app.doctrine_cache_provider + default_lifetime: 5 + cache_provider_service: app.doctrine_cache_provider baz: type: filesystem - options: - default_lifetime: 7 - directory: app/cache/psr + default_lifetime: 7 + directory: app/cache/psr diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 6643e7f1f73c8..c303c8797b153 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -571,13 +571,13 @@ public function testPropertyInfoEnabled() $this->assertTrue($container->has('property_info')); } - public function testCacheAdaptersAbstractServices() + public function testCachePoolServices() { $container = $this->createContainerFromFile('cache'); - $this->assertCacheAdapterIsRegistered($container, 'foo', 'apcu', array(null, 30), 0); - $this->assertCacheAdapterIsRegistered($container, 'bar', 'doctrine', array(new Reference('app.doctrine_cache_provider'), 5)); - $this->assertCacheAdapterIsRegistered($container, 'baz', 'filesystem', array('app/cache/psr', 7)); + $this->assertCachePoolServiceDefinitionIsCreated($container, 'foo', 'apcu', array('index_1' => 30), 0); + $this->assertCachePoolServiceDefinitionIsCreated($container, 'bar', 'doctrine', array('index_0' => new Reference('app.doctrine_cache_provider'), 'index_1' => 5)); + $this->assertCachePoolServiceDefinitionIsCreated($container, 'baz', 'filesystem', array('index_0' => 'app/cache/psr', 'index_1' => 7)); } protected function createContainer(array $data = array()) @@ -649,13 +649,18 @@ private function assertVersionStrategy(ContainerBuilder $container, Reference $r } } - private function assertCacheAdapterIsRegistered(ContainerBuilder $container, $name, $type, array $arguments, $namespaceArgumentIndex = null) + private function assertCachePoolServiceDefinitionIsCreated(ContainerBuilder $container, $name, $type, array $arguments, $namespaceArgumentIndex = null) { - $id = 'cache.adapter.'.$name; + $id = 'cache.pool.'.$name; - $this->assertTrue($container->has($id), sprintf('Service definition "%s" for cache adapter of type "%s" is registered', $id, $type)); + $this->assertTrue($container->has($id), sprintf('Service definition "%s" for cache pool of type "%s" is registered', $id, $type)); - $adapterDefinition = $container->getDefinition($id); + $poolDefinition = $container->getDefinition($id); + + $this->assertInstanceOf(DefinitionDecorator::class, $poolDefinition, sprintf('Cache pool "%s" is based on an abstract cache adapter.', $name)); + $this->assertEquals($arguments, $poolDefinition->getArguments()); + + $adapterDefinition = $container->getDefinition($poolDefinition->getParent()); switch ($type) { case 'apcu': @@ -669,15 +674,10 @@ private function assertCacheAdapterIsRegistered(ContainerBuilder $container, $na break; } - $this->assertTrue($adapterDefinition->isAbstract(), sprintf('Service definition "%s" for cache adapter "%s" is abstract', $id, $name)); - $this->assertEquals($arguments, $adapterDefinition->getArguments()); $this->assertTrue($adapterDefinition->hasTag('cache.adapter'), sprintf('Service definition "%s" is tagged with the "cache.adapter" tag.', $id)); $tag = $adapterDefinition->getTag('cache.adapter'); - $this->assertTrue(isset($tag[0]['id']), 'The adapter name is the "id" attribute of the "cache.adapter" tag.'); - $this->assertSame($name, $tag[0]['id'], 'The adapter name is the "id" attribute of the "cache.adapter" tag.'); - if (null !== $namespaceArgumentIndex) { $this->assertTrue(isset($tag[0]['namespace-arg-index']), 'The namespace argument index is given by the "namespace-arg-index" attribute of the "cache.adapter" tag.'); $this->assertSame($namespaceArgumentIndex, $tag[0]['namespace-arg-index'], 'The namespace argument index is given by the "namespace-arg-index" attribute of the "cache.adapter" tag.'); From 5e927b4c3539e72c367a8cdc52459bac95d42037 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 11 Mar 2016 18:32:55 +0100 Subject: [PATCH 6/6] add PSR-6 type tests --- .../Tests/DependencyInjection/Fixtures/php/cache.php | 5 +++++ .../Tests/DependencyInjection/Fixtures/xml/cache.xml | 1 + .../Tests/DependencyInjection/Fixtures/yml/cache.yml | 4 ++++ .../Tests/DependencyInjection/FrameworkExtensionTest.php | 1 + 4 files changed, 11 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php index c35d3106998be..63e5441293f60 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php @@ -17,6 +17,11 @@ 'default_lifetime' => 7, 'directory' => 'app/cache/psr', ), + 'foobar' => array( + 'type' => 'psr6', + 'default_lifetime' => 10, + 'cache_provider_service' => 'app.cache_pool', + ), ), ), )); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml index 1bdc9f2375cdb..f3d26f7380290 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml @@ -10,6 +10,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml index c146b6741d182..0d45b13527161 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml @@ -12,3 +12,7 @@ framework: type: filesystem default_lifetime: 7 directory: app/cache/psr + foobar: + type: psr6 + default_lifetime: 10 + cache_provider_service: app.cache_pool diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index c303c8797b153..93478df449b99 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -578,6 +578,7 @@ public function testCachePoolServices() $this->assertCachePoolServiceDefinitionIsCreated($container, 'foo', 'apcu', array('index_1' => 30), 0); $this->assertCachePoolServiceDefinitionIsCreated($container, 'bar', 'doctrine', array('index_0' => new Reference('app.doctrine_cache_provider'), 'index_1' => 5)); $this->assertCachePoolServiceDefinitionIsCreated($container, 'baz', 'filesystem', array('index_0' => 'app/cache/psr', 'index_1' => 7)); + $this->assertCachePoolServiceDefinitionIsCreated($container, 'foobar', 'psr6', array('index_0' => new Reference('app.cache_pool'), 'index_1' => 10)); } protected function createContainer(array $data = array()) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy