Browse Source

slight compiler refactoring (RFC)

Johannes Schmitt 14 years ago
parent
commit
a2105d44aa

+ 30 - 0
src/Symfony/Component/DependencyInjection/Compiler/CompilerPassInterface.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace Symfony\Component\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * 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 <schmittjoh@gmail.com>
+ */
+interface CompilerPassInterface
+{
+    /**
+     * You can modify the container here before it is dumped to PHP code.
+     *
+     * @param ContainerBuilder $container
+     * @return void
+     */
+    function process(ContainerBuilder $container);
+}

+ 51 - 0
src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace Symfony\Component\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * 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 <fabien.potencier@symfony-project.com>
+ */
+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);
+    }
+}

+ 41 - 0
src/Symfony/Component/DependencyInjection/Compiler/ResolveInterfaceInjectorsPass.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace Symfony\Component\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * 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 <mallluhuct@gmail.com>
+ */
+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);
+                }
+            }
+        }
+    }
+}

+ 66 - 36
src/Symfony/Component/DependencyInjection/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 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
         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 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
         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 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
      */
     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();

+ 1 - 1
src/Symfony/Component/DependencyInjection/InterfaceInjector.php

@@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
 /**
  * InterfaceInjector is used for Interface Injection.
  *
- * @author     Bulat Shakirzyanov <mallluhuct@gmail.com>
+ * @author Bulat Shakirzyanov <mallluhuct@gmail.com>
  */
 class InterfaceInjector
 {