diff --git a/Compiler/CompilerPassInterface.php b/Compiler/CompilerPassInterface.php new file mode 100644 index 000000000..bec3d3708 --- /dev/null +++ b/Compiler/CompilerPassInterface.php @@ -0,0 +1,30 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Interface that must be implemented by compilation passes + * + * @author Johannes M. Schmitt + */ +interface CompilerPassInterface +{ + /** + * You can modify the container here before it is dumped to PHP code. + * + * @param ContainerBuilder $container + * @return void + */ + function process(ContainerBuilder $container); +} diff --git a/Compiler/MergeExtensionConfigurationPass.php b/Compiler/MergeExtensionConfigurationPass.php new file mode 100644 index 000000000..3c0dbc46c --- /dev/null +++ b/Compiler/MergeExtensionConfigurationPass.php @@ -0,0 +1,51 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Merges extension configs into the container builder + * + * @author Fabien Potencier + */ +class MergeExtensionConfigurationPass implements CompilerPassInterface +{ + /** + * {@inheritDoc} + */ + public function process(ContainerBuilder $container) + { + $parameters = $container->getParameterBag()->all(); + $definitions = $container->getDefinitions(); + $aliases = $container->getAliases(); + + foreach ($container->getExtensionConfigs() as $name => $configs) { + list($namespace, $tag) = explode(':', $name); + + $extension = $container->getExtension($namespace); + + $tmpContainer = new ContainerBuilder($container->getParameterBag()); + $tmpContainer->addObjectResource($extension); + foreach ($configs as $config) { + $extension->load($tag, $config, $tmpContainer); + } + + $container->merge($tmpContainer); + } + + $container->setExtensionConfigs(array()); + $container->addDefinitions($definitions); + $container->addAliases($aliases); + $container->getParameterBag()->add($parameters); + } +} diff --git a/Compiler/ResolveInterfaceInjectorsPass.php b/Compiler/ResolveInterfaceInjectorsPass.php new file mode 100644 index 000000000..90cc1b15a --- /dev/null +++ b/Compiler/ResolveInterfaceInjectorsPass.php @@ -0,0 +1,41 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Resolves interface injectors and inlines them as method calls + * + * @author Bulat Shakirzyanov + */ +class ResolveInterfaceInjectorsPass implements CompilerPassInterface +{ + /** + * {@inheritDoc} + */ + public function process(ContainerBuilder $container) + { + foreach ($container->getDefinitions() as $definition) { + foreach ($container->getInterfaceInjectors() as $injector) { + if (null !== $definition->getFactoryService()) { + continue; + } + $defClass = $container->getParameterBag()->resolveValue($definition->getClass()); + $definition->setClass($defClass); + if ($injector->supports($defClass)) { + $injector->processDefinition($definition); + } + } + } + } +} diff --git a/ContainerBuilder.php b/ContainerBuilder.php index a7d901356..76c305fbb 100644 --- a/ContainerBuilder.php +++ b/ContainerBuilder.php @@ -2,10 +2,14 @@ namespace Symfony\Component\DependencyInjection; +use Symfony\Component\DependencyInjection\Compiler\ResolveInterfaceInjectorsPass; +use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; -use Symfony\Component\DependencyInjection\Resource\ResourceInterface; -use Symfony\Component\DependencyInjection\Resource\FileResource; use Symfony\Component\DependencyInjection\InterfaceInjector; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +use Symfony\Component\DependencyInjection\Resource\FileResource; +use Symfony\Component\DependencyInjection\Resource\ResourceInterface; /* * This file is part of the Symfony framework. @@ -31,6 +35,21 @@ class ContainerBuilder extends Container implements TaggedContainerInterface protected $resources = array(); protected $extensionConfigs = array(); protected $injectors = array(); + protected $compilerPasses; + + /** + * Constructor + * @param ParameterBagInterface $parameterBag + */ + public function __construct(ParameterBagInterface $parameterBag = null) + { + parent::__construct($parameterBag); + + $passes = array(); + $passes[] = new MergeExtensionConfigurationPass(); + $passes[] = new ResolveInterfaceInjectorsPass(); + $this->compilerPasses = $passes; + } /** * Registers an extension. @@ -127,6 +146,38 @@ public function loadFromExtension($extension, $tag, array $values = array()) return $this; } + /** + * Adds a compiler pass at the end of the current passes + * + * @param CompilerPassInterface $pass + * @return void + */ + public function addCompilerPass(CompilerPassInterface $pass) + { + $this->compilerPasses[] = $pass; + } + + /** + * Returns the currently registered compiler passes + * + * @return array + */ + public function getCompilerPasses() + { + return $this->compilerPasses; + } + + /** + * Overwrites all existing passes + * + * @param array $passes + * @return void + */ + public function setCompilerPasses(array $passes) + { + $this->compilerPasses = $passes; + } + /** * Sets a service. * @@ -267,6 +318,17 @@ public function getExtensionConfigs() return $this->extensionConfigs; } + /** + * Sets the extension configs array + * + * @param array $config + * @return void + */ + public function setExtensionConfigs(array $config) + { + $this->extensionConfigs = $config; + } + /** * Freezes the container. * @@ -279,40 +341,8 @@ public function getExtensionConfigs() */ public function freeze() { - $parameters = $this->parameterBag->all(); - $definitions = $this->definitions; - $aliases = $this->aliases; - - foreach ($this->extensionConfigs as $name => $configs) { - list($namespace, $tag) = explode(':', $name); - - $extension = $this->getExtension($namespace); - - $container = new self($this->parameterBag); - $container->addObjectResource($extension); - foreach ($configs as $config) { - $extension->load($tag, $config, $container); - } - - $this->merge($container); - } - - $this->extensionConfigs = array(); - $this->addDefinitions($definitions); - $this->addAliases($aliases); - $this->parameterBag->add($parameters); - - foreach ($this->definitions as $definition) { - foreach ($this->injectors as $injector) { - if (null !== $definition->getFactoryService()) { - continue; - } - $defClass = $this->parameterBag->resolveValue($definition->getClass()); - $definition->setClass($defClass); - if ($injector->supports($defClass)) { - $injector->processDefinition($definition); - } - } + foreach ($this->compilerPasses as $pass) { + $pass->process($this); } parent::freeze(); diff --git a/InterfaceInjector.php b/InterfaceInjector.php index b4b5c57e9..9e37b6263 100755 --- a/InterfaceInjector.php +++ b/InterfaceInjector.php @@ -16,7 +16,7 @@ /** * InterfaceInjector is used for Interface Injection. * - * @author Bulat Shakirzyanov + * @author Bulat Shakirzyanov */ class InterfaceInjector {