diff --git a/src/Symfony/Components/DependencyInjection/BuilderConfiguration.php b/src/Symfony/Components/DependencyInjection/BuilderConfiguration.php index 69001f80aa..94d21031e3 100644 --- a/src/Symfony/Components/DependencyInjection/BuilderConfiguration.php +++ b/src/Symfony/Components/DependencyInjection/BuilderConfiguration.php @@ -2,7 +2,7 @@ namespace Symfony\Components\DependencyInjection; -use Symfony\Components\DependencyInjection\Loader\Loader; +use Symfony\Components\DependencyInjection\Loader\LoaderExtensionInterface; /* * This file is part of the Symfony framework. @@ -22,13 +22,18 @@ use Symfony\Components\DependencyInjection\Loader\Loader; */ class BuilderConfiguration { - protected $definitions = array(); - protected $parameters = array(); - protected $aliases = array(); - protected $resources = array(); + protected $definitions; + protected $parameters; + protected $aliases; + protected $resources; + protected $extensions; public function __construct(array $definitions = array(), array $parameters = array()) { + $this->aliases = array(); + $this->resources = array(); + $this->extensions = array(); + $this->setDefinitions($definitions); $this->setParameters($parameters); } @@ -82,20 +87,42 @@ class BuilderConfiguration } /** - * Merges the configuration given by an extension. + * Loads the configuration for an extension. * - * @param $key string The extension tag to load (namespace.tag) - * @param $values array An array of values to customize the extension + * @param $extension LoaderExtensionInterface A LoaderExtensionInterface instance + * @param $tag string The extension tag to load (without the namespace - namespace.tag) + * @param $values array An array of values that customizes the extension * * @return BuilderConfiguration The current instance */ - public function mergeExtension($key, array $values = array()) + public function loadFromExtension(LoaderExtensionInterface $extension, $tag, array $values = array()) { - list($namespace, $tag) = explode('.', $key); + $namespace = $extension->getAlias(); - $config = Loader::getExtension($namespace)->load($tag, $values); + if (!isset($this->extensions[$namespace])) { + $this->extensions[$namespace] = new self(); - $this->merge($config); + $r = new \ReflectionObject($extension); + $this->extensions[$namespace]->addResource(new FileResource($r->getFileName())); + } + + $this->extensions[$namespace] = $extension->load($tag, $values, $this->extensions[$namespace]); + + return $this; + } + + /** + * Merges the extension configuration. + * + * @return BuilderConfiguration The current instance + */ + public function mergeExtensionsConfiguration() + { + foreach ($this->extensions as $name => $configuration) { + $this->merge($configuration); + } + + $this->extensions = array(); return $this; } diff --git a/src/Symfony/Components/DependencyInjection/Loader/IniFileLoader.php b/src/Symfony/Components/DependencyInjection/Loader/IniFileLoader.php index 0318227c9b..5338741bb8 100644 --- a/src/Symfony/Components/DependencyInjection/Loader/IniFileLoader.php +++ b/src/Symfony/Components/DependencyInjection/Loader/IniFileLoader.php @@ -26,17 +26,21 @@ class IniFileLoader extends FileLoader /** * Loads a resource. * - * @param string $file An INI file path + * @param mixed $resource The resource + * @param Boolean $main Whether this is the main load() call + * @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration * * @return BuilderConfiguration A BuilderConfiguration instance * * @throws \InvalidArgumentException When ini file is not valid */ - public function load($file) + public function load($file, $main = true, BuilderConfiguration $configuration = null) { $path = $this->findFile($file); - $configuration = new BuilderConfiguration(); + if (null === $configuration) { + $configuration = new BuilderConfiguration(); + } $configuration->addResource(new FileResource($path)); diff --git a/src/Symfony/Components/DependencyInjection/Loader/LoaderExtension.php b/src/Symfony/Components/DependencyInjection/Loader/LoaderExtension.php index 1da9ea6364..3ceade8394 100644 --- a/src/Symfony/Components/DependencyInjection/Loader/LoaderExtension.php +++ b/src/Symfony/Components/DependencyInjection/Loader/LoaderExtension.php @@ -2,6 +2,8 @@ namespace Symfony\Components\DependencyInjection\Loader; +use Symfony\Components\DependencyInjection\BuilderConfiguration; + /* * This file is part of the Symfony framework. * @@ -36,19 +38,20 @@ abstract class LoaderExtension implements LoaderExtensionInterface /** * Loads a specific configuration. * - * @param string The tag name - * @param array An array of configuration values + * @param string $tag The tag name + * @param array $config An array of configuration values + * @param BuilderConfiguration $configuration A BuilderConfiguration instance * * @return BuilderConfiguration A BuilderConfiguration instance * * @throws \InvalidArgumentException When provided tag is not defined in this extension */ - public function load($tag, array $config) + public function load($tag, array $config, BuilderConfiguration $configuration) { if (!method_exists($this, $method = $tag.'Load')) { throw new \InvalidArgumentException(sprintf('The tag "%s" is not defined in the "%s" extension.', $tag, $this->getNamespace())); } - return $this->$method($config); + return $this->$method($config, $configuration); } } diff --git a/src/Symfony/Components/DependencyInjection/Loader/LoaderExtensionInterface.php b/src/Symfony/Components/DependencyInjection/Loader/LoaderExtensionInterface.php index 88304b00e6..4294e45c17 100644 --- a/src/Symfony/Components/DependencyInjection/Loader/LoaderExtensionInterface.php +++ b/src/Symfony/Components/DependencyInjection/Loader/LoaderExtensionInterface.php @@ -2,6 +2,8 @@ namespace Symfony\Components\DependencyInjection\Loader; +use Symfony\Components\DependencyInjection\BuilderConfiguration; + /* * This file is part of the Symfony framework. * @@ -31,12 +33,15 @@ interface LoaderExtensionInterface /** * Loads a specific configuration. * - * @param string The tag name - * @param array An array of configuration values + * @param string $tag The tag name + * @param array $config An array of configuration values + * @param BuilderConfiguration $configuration A BuilderConfiguration instance * * @return BuilderConfiguration A BuilderConfiguration instance + * + * @throws \InvalidArgumentException When provided tag is not defined in this extension */ - public function load($tag, array $config); + public function load($tag, array $config, BuilderConfiguration $configuration); /** * Returns the namespace to be used for this extension (XML namespace). diff --git a/src/Symfony/Components/DependencyInjection/Loader/LoaderInterface.php b/src/Symfony/Components/DependencyInjection/Loader/LoaderInterface.php index b739ec923b..c7312ef098 100644 --- a/src/Symfony/Components/DependencyInjection/Loader/LoaderInterface.php +++ b/src/Symfony/Components/DependencyInjection/Loader/LoaderInterface.php @@ -2,6 +2,8 @@ namespace Symfony\Components\DependencyInjection\Loader; +use Symfony\Components\DependencyInjection\BuilderConfiguration; + /* * This file is part of the Symfony framework. * @@ -56,11 +58,13 @@ interface LoaderInterface * If you load file1.xml and file2.xml in this order, the value of complex * will be "foo". * - * @param mixed $resource The resource + * @param mixed $resource The resource + * @param Boolean $main Whether this is the main load() call + * @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration * * @return BuilderConfiguration A BuilderConfiguration instance */ - function load($resource); + function load($resource, $main = true, BuilderConfiguration $configuration = null); static function registerExtension(LoaderExtensionInterface $extension); } diff --git a/src/Symfony/Components/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Components/DependencyInjection/Loader/XmlFileLoader.php index ff808dd9b1..175e63ee10 100644 --- a/src/Symfony/Components/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Components/DependencyInjection/Loader/XmlFileLoader.php @@ -29,17 +29,21 @@ class XmlFileLoader extends FileLoader /** * Loads an array of XML files. * - * @param string $file An XML file path + * @param mixed $resource The resource + * @param Boolean $main Whether this is the main load() call + * @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration * * @return BuilderConfiguration A BuilderConfiguration instance */ - public function load($file) + public function load($file, $main = true, BuilderConfiguration $configuration = null) { $path = $this->findFile($file); $xml = $this->parseFile($path); - $configuration = new BuilderConfiguration(); + if (null === $configuration) { + $configuration = new BuilderConfiguration(); + } $configuration->addResource(new FileResource($path)); @@ -58,6 +62,10 @@ class XmlFileLoader extends FileLoader // extensions $this->loadFromExtensions($configuration, $xml); + if ($main) { + $configuration->mergeExtensionsConfiguration(); + } + return $configuration; } @@ -77,11 +85,11 @@ class XmlFileLoader extends FileLoader } foreach ($xml->imports->import as $import) { - $configuration->merge($this->parseImport($import, $file)); + $this->parseImport($configuration, $import, $file); } } - protected function parseImport($import, $file) + protected function parseImport(BuilderConfiguration $configuration, $import, $file) { $class = null; if (isset($import['class']) && $import['class'] !== get_class($this)) { @@ -102,7 +110,7 @@ class XmlFileLoader extends FileLoader $importedFile = $this->getAbsolutePath((string) $import['resource'], dirname($file)); - return $loader->load($importedFile); + return $loader->load($importedFile, false, $configuration); } protected function parseDefinitions(BuilderConfiguration $configuration, $xml, $file) @@ -325,12 +333,11 @@ EOF } $values = static::convertDomElementToArray($node); - $config = $this->getExtension($node->namespaceURI)->load($node->localName, is_array($values) ? $values : array($values)); + if (!is_array($values)) { + $values = array(); + } - $r = new \ReflectionObject($this->getExtension($node->namespaceURI)); - $config->addResource(new FileResource($r->getFileName())); - - $configuration->merge($config); + $configuration->loadFromExtension($this->getExtension($node->namespaceURI), $node->localName, $values); } } diff --git a/src/Symfony/Components/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Components/DependencyInjection/Loader/YamlFileLoader.php index f5c7e98b04..30ee5241dd 100644 --- a/src/Symfony/Components/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Components/DependencyInjection/Loader/YamlFileLoader.php @@ -32,17 +32,21 @@ class YamlFileLoader extends FileLoader /** * Loads an array of Yaml files. * - * @param string $file A YAML file path + * @param mixed $resource The resource + * @param Boolean $main Whether this is the main load() call + * @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration * * @return BuilderConfiguration A BuilderConfiguration instance */ - public function load($file) + public function load($file, $main = true, BuilderConfiguration $configuration = null) { $path = $this->findFile($file); $content = $this->loadFile($path); - $configuration = new BuilderConfiguration(); + if (null === $configuration) { + $configuration = new BuilderConfiguration(); + } $configuration->addResource(new FileResource($path)); @@ -66,6 +70,10 @@ class YamlFileLoader extends FileLoader // extensions $this->loadFromExtensions($configuration, $content); + if ($main) { + $configuration->mergeExtensionsConfiguration(); + } + return $configuration; } @@ -76,11 +84,11 @@ class YamlFileLoader extends FileLoader } foreach ($content['imports'] as $import) { - $configuration->merge($this->parseImport($import, $file)); + $this->parseImport($configuration, $import, $file); } } - protected function parseImport($import, $file) + protected function parseImport(BuilderConfiguration $configuration, $import, $file) { $class = null; if (isset($import['class']) && $import['class'] !== get_class($this)) { @@ -101,7 +109,7 @@ class YamlFileLoader extends FileLoader $importedFile = $this->getAbsolutePath($import['resource'], dirname($file)); - return $loader->load($importedFile); + return $loader->load($importedFile, false, $configuration); } protected function parseDefinitions(BuilderConfiguration $configuration, $content, $file) @@ -232,12 +240,7 @@ class YamlFileLoader extends FileLoader $values = array(); } - $config = static::getExtension($namespace)->load($tag, $values); - - $r = new \ReflectionObject($this->getExtension($namespace)); - $config->addResource(new FileResource($r->getFileName())); - - $configuration->merge($config); + $configuration->loadFromExtension($this->getExtension($namespace), $tag, $values); } } } diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Loader/FileLoaderTest.php b/tests/Symfony/Tests/Components/DependencyInjection/Loader/FileLoaderTest.php index 9e709e3745..922470dbca 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Loader/FileLoaderTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/Loader/FileLoaderTest.php @@ -11,6 +11,7 @@ namespace Symfony\Tests\Components\DependencyInjection\Loader; use Symfony\Components\DependencyInjection\Builder; +use Symfony\Components\DependencyInjection\BuilderConfiguration; use Symfony\Components\DependencyInjection\Loader\FileLoader; class XmlDumperTest extends \PHPUnit_Framework_TestCase @@ -44,7 +45,7 @@ class ProjectLoader extends FileLoader { public $paths; - public function load($resource) + public function load($resource, $main = true, BuilderConfiguration $configuration = null) { } diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderExtensionTest.php b/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderExtensionTest.php index d8046fd9c7..b23f3a135d 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderExtensionTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderExtensionTest.php @@ -12,6 +12,8 @@ namespace Symfony\Tests\Components\DependencyInjection\Loader; require_once __DIR__.'/../../../../../fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php'; +use Symfony\Components\DependencyInjection\BuilderConfiguration; + class LoaderExtensionTest extends \PHPUnit_Framework_TestCase { public function testLoad() @@ -19,14 +21,14 @@ class LoaderExtensionTest extends \PHPUnit_Framework_TestCase $extension = new \ProjectExtension(); try { - $extension->load('foo', array()); + $extension->load('foo', array(), new BuilderConfiguration()); $this->fail('->load() throws an InvalidArgumentException if the tag does not exist'); } catch (\Exception $e) { $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tag does not exist'); $this->assertEquals('The tag "foo" is not defined in the "http://www.example.com/schema/project" extension.', $e->getMessage(), '->load() throws an InvalidArgumentException if the tag does not exist'); } - $config = $extension->load('bar', array('foo' => 'bar')); + $config = $extension->load('bar', array('foo' => 'bar'), new BuilderConfiguration()); $this->assertEquals(array('project.parameter.bar' => 'bar'), $config->getParameters(), '->load() calls the method tied to the given tag'); } } diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderTest.php b/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderTest.php index 243b3af3dd..9747353400 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderTest.php @@ -13,10 +13,11 @@ namespace Symfony\Tests\Components\DependencyInjection\Loader; require_once __DIR__.'/../../../../../fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php'; use Symfony\Components\DependencyInjection\Loader\Loader; +use Symfony\Components\DependencyInjection\BuilderConfiguration; class ProjectLoader1 extends Loader { - public function load($resource) + public function load($resource, $main = true, BuilderConfiguration $configuration = null) { } } diff --git a/tests/fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php b/tests/fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php index 7de14f829b..13958ed6e4 100644 --- a/tests/fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php +++ b/tests/fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php @@ -6,10 +6,8 @@ use Symfony\Components\DependencyInjection\Loader\LoaderExtension; class ProjectExtension extends LoaderExtension { - public function barLoad(array $config) + public function barLoad(array $config, BuilderConfiguration $configuration) { - $configuration = new BuilderConfiguration(); - $configuration->setDefinition('project.service.bar', new Definition('FooClass')); $configuration->setParameter('project.parameter.bar', isset($config['foo']) ? $config['foo'] : 'foobar');