From e44bfdcde90a592ff0aa7ff6ab1c340c32fa51d6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 4 Mar 2016 18:43:16 +0100 Subject: [PATCH] [FrameworkBundle] Add cache-pool tag and wiring --- .../Compiler/CacheAdapterPass.php | 88 ------------------- .../Compiler/CachePoolPass.php | 64 ++++++++++++++ .../DependencyInjection/Configuration.php | 32 ++----- .../FrameworkExtension.php | 50 +++-------- .../FrameworkBundle/FrameworkBundle.php | 4 +- .../Resources/config/cache_adapters.xml | 37 ++++++++ .../Resources/config/schema/symfony-1.0.xsd | 4 +- ...pterPassTest.php => CachePoolPassTest.php} | 16 ++-- 8 files changed, 134 insertions(+), 161 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 d8453caa89..0000000000 --- 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 0000000000..e4e6487209 --- /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 6dab7150c9..d64d9faad4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -555,40 +555,22 @@ class Configuration implements ConfigurationInterface ->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", "psr6" 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() + ->values(array('apcu', 'doctrine', 'psr6', 'filesystem')) ->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 7419622990..f7431a6600 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; @@ -1023,43 +1020,24 @@ class FrameworkExtension extends Extension } } - 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; + if (!empty($config['pool'])) { + $loader->load('cache_adapters.xml'); + } - 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; + foreach ($config['pool'] as $name => $poolConfig) { + $poolDefinition = new DefinitionDecorator('cache.adapter.'.$poolConfig['type']); + $poolDefinition->replaceArgument(1, $poolConfig['default_lifetime']); + + 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']); } - $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); + $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 8c0fddbdc7..7ed44c5bb8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -14,7 +14,7 @@ namespace Symfony\Bundle\FrameworkBundle; 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\ControllerArgumentValueResolverPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\PropertyInfoPass; @@ -90,7 +90,7 @@ class FrameworkBundle extends Bundle $container->addCompilerPass(new SerializerPass()); $container->addCompilerPass(new PropertyInfoPass()); $container->addCompilerPass(new ControllerArgumentValueResolverPass()); - $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 0000000000..13612a1d28 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_adapters.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %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 79f295205f..cee9299e44 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 923189221f..033809fcda 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 @@ class CacheAdapterPassTest extends \PHPUnit_Framework_TestCase 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 @@ class CacheAdapterPassTest extends \PHPUnit_Framework_TestCase 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 @@ class CacheAdapterPassTest extends \PHPUnit_Framework_TestCase { $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()