Skip to content

Commit b057ef6

Browse files
committed
[DependencyInjection] changed the extension mechanism to allow an extension to be inherit and merge from an existing configuration
1 parent a79ad89 commit b057ef6

File tree

11 files changed

+109
-54
lines changed

11 files changed

+109
-54
lines changed

src/Symfony/Components/DependencyInjection/BuilderConfiguration.php

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Symfony\Components\DependencyInjection;
44

5-
use Symfony\Components\DependencyInjection\Loader\Loader;
5+
use Symfony\Components\DependencyInjection\Loader\LoaderExtensionInterface;
66

77
/*
88
* This file is part of the Symfony framework.
@@ -22,13 +22,18 @@
2222
*/
2323
class BuilderConfiguration
2424
{
25-
protected $definitions = array();
26-
protected $parameters = array();
27-
protected $aliases = array();
28-
protected $resources = array();
25+
protected $definitions;
26+
protected $parameters;
27+
protected $aliases;
28+
protected $resources;
29+
protected $extensions;
2930

3031
public function __construct(array $definitions = array(), array $parameters = array())
3132
{
33+
$this->aliases = array();
34+
$this->resources = array();
35+
$this->extensions = array();
36+
3237
$this->setDefinitions($definitions);
3338
$this->setParameters($parameters);
3439
}
@@ -82,20 +87,42 @@ public function merge(BuilderConfiguration $configuration = null)
8287
}
8388

8489
/**
85-
* Merges the configuration given by an extension.
90+
* Loads the configuration for an extension.
8691
*
87-
* @param $key string The extension tag to load (namespace.tag)
88-
* @param $values array An array of values to customize the extension
92+
* @param $extension LoaderExtensionInterface A LoaderExtensionInterface instance
93+
* @param $tag string The extension tag to load (without the namespace - namespace.tag)
94+
* @param $values array An array of values that customizes the extension
8995
*
9096
* @return BuilderConfiguration The current instance
9197
*/
92-
public function mergeExtension($key, array $values = array())
98+
public function loadFromExtension(LoaderExtensionInterface $extension, $tag, array $values = array())
9399
{
94-
list($namespace, $tag) = explode('.', $key);
100+
$namespace = $extension->getAlias();
101+
102+
if (!isset($this->extensions[$namespace])) {
103+
$this->extensions[$namespace] = new self();
104+
105+
$r = new \ReflectionObject($extension);
106+
$this->extensions[$namespace]->addResource(new FileResource($r->getFileName()));
107+
}
108+
109+
$this->extensions[$namespace] = $extension->load($tag, $values, $this->extensions[$namespace]);
110+
111+
return $this;
112+
}
95113

96-
$config = Loader::getExtension($namespace)->load($tag, $values);
114+
/**
115+
* Merges the extension configuration.
116+
*
117+
* @return BuilderConfiguration The current instance
118+
*/
119+
public function mergeExtensionsConfiguration()
120+
{
121+
foreach ($this->extensions as $name => $configuration) {
122+
$this->merge($configuration);
123+
}
97124

98-
$this->merge($config);
125+
$this->extensions = array();
99126

100127
return $this;
101128
}

src/Symfony/Components/DependencyInjection/Loader/IniFileLoader.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,21 @@ class IniFileLoader extends FileLoader
2626
/**
2727
* Loads a resource.
2828
*
29-
* @param string $file An INI file path
29+
* @param mixed $resource The resource
30+
* @param Boolean $main Whether this is the main load() call
31+
* @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration
3032
*
3133
* @return BuilderConfiguration A BuilderConfiguration instance
3234
*
3335
* @throws \InvalidArgumentException When ini file is not valid
3436
*/
35-
public function load($file)
37+
public function load($file, $main = true, BuilderConfiguration $configuration = null)
3638
{
3739
$path = $this->findFile($file);
3840

39-
$configuration = new BuilderConfiguration();
41+
if (null === $configuration) {
42+
$configuration = new BuilderConfiguration();
43+
}
4044

4145
$configuration->addResource(new FileResource($path));
4246

src/Symfony/Components/DependencyInjection/Loader/LoaderExtension.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Symfony\Components\DependencyInjection\Loader;
44

5+
use Symfony\Components\DependencyInjection\BuilderConfiguration;
6+
57
/*
68
* This file is part of the Symfony framework.
79
*
@@ -36,19 +38,20 @@ public function setConfiguration($name, $resource)
3638
/**
3739
* Loads a specific configuration.
3840
*
39-
* @param string The tag name
40-
* @param array An array of configuration values
41+
* @param string $tag The tag name
42+
* @param array $config An array of configuration values
43+
* @param BuilderConfiguration $configuration A BuilderConfiguration instance
4144
*
4245
* @return BuilderConfiguration A BuilderConfiguration instance
4346
*
4447
* @throws \InvalidArgumentException When provided tag is not defined in this extension
4548
*/
46-
public function load($tag, array $config)
49+
public function load($tag, array $config, BuilderConfiguration $configuration)
4750
{
4851
if (!method_exists($this, $method = $tag.'Load')) {
4952
throw new \InvalidArgumentException(sprintf('The tag "%s" is not defined in the "%s" extension.', $tag, $this->getNamespace()));
5053
}
5154

52-
return $this->$method($config);
55+
return $this->$method($config, $configuration);
5356
}
5457
}

src/Symfony/Components/DependencyInjection/Loader/LoaderExtensionInterface.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Symfony\Components\DependencyInjection\Loader;
44

5+
use Symfony\Components\DependencyInjection\BuilderConfiguration;
6+
57
/*
68
* This file is part of the Symfony framework.
79
*
@@ -31,12 +33,15 @@ public function setConfiguration($name, $resource);
3133
/**
3234
* Loads a specific configuration.
3335
*
34-
* @param string The tag name
35-
* @param array An array of configuration values
36+
* @param string $tag The tag name
37+
* @param array $config An array of configuration values
38+
* @param BuilderConfiguration $configuration A BuilderConfiguration instance
3639
*
3740
* @return BuilderConfiguration A BuilderConfiguration instance
41+
*
42+
* @throws \InvalidArgumentException When provided tag is not defined in this extension
3843
*/
39-
public function load($tag, array $config);
44+
public function load($tag, array $config, BuilderConfiguration $configuration);
4045

4146
/**
4247
* Returns the namespace to be used for this extension (XML namespace).

src/Symfony/Components/DependencyInjection/Loader/LoaderInterface.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Symfony\Components\DependencyInjection\Loader;
44

5+
use Symfony\Components\DependencyInjection\BuilderConfiguration;
6+
57
/*
68
* This file is part of the Symfony framework.
79
*
@@ -56,11 +58,13 @@ interface LoaderInterface
5658
* If you load file1.xml and file2.xml in this order, the value of complex
5759
* will be "foo".
5860
*
59-
* @param mixed $resource The resource
61+
* @param mixed $resource The resource
62+
* @param Boolean $main Whether this is the main load() call
63+
* @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration
6064
*
6165
* @return BuilderConfiguration A BuilderConfiguration instance
6266
*/
63-
function load($resource);
67+
function load($resource, $main = true, BuilderConfiguration $configuration = null);
6468

6569
static function registerExtension(LoaderExtensionInterface $extension);
6670
}

src/Symfony/Components/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,21 @@ class XmlFileLoader extends FileLoader
2929
/**
3030
* Loads an array of XML files.
3131
*
32-
* @param string $file An XML file path
32+
* @param mixed $resource The resource
33+
* @param Boolean $main Whether this is the main load() call
34+
* @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration
3335
*
3436
* @return BuilderConfiguration A BuilderConfiguration instance
3537
*/
36-
public function load($file)
38+
public function load($file, $main = true, BuilderConfiguration $configuration = null)
3739
{
3840
$path = $this->findFile($file);
3941

4042
$xml = $this->parseFile($path);
4143

42-
$configuration = new BuilderConfiguration();
44+
if (null === $configuration) {
45+
$configuration = new BuilderConfiguration();
46+
}
4347

4448
$configuration->addResource(new FileResource($path));
4549

@@ -58,6 +62,10 @@ public function load($file)
5862
// extensions
5963
$this->loadFromExtensions($configuration, $xml);
6064

65+
if ($main) {
66+
$configuration->mergeExtensionsConfiguration();
67+
}
68+
6169
return $configuration;
6270
}
6371

@@ -77,11 +85,11 @@ protected function parseImports(BuilderConfiguration $configuration, $xml, $file
7785
}
7886

7987
foreach ($xml->imports->import as $import) {
80-
$configuration->merge($this->parseImport($import, $file));
88+
$this->parseImport($configuration, $import, $file);
8189
}
8290
}
8391

84-
protected function parseImport($import, $file)
92+
protected function parseImport(BuilderConfiguration $configuration, $import, $file)
8593
{
8694
$class = null;
8795
if (isset($import['class']) && $import['class'] !== get_class($this)) {
@@ -102,7 +110,7 @@ protected function parseImport($import, $file)
102110

103111
$importedFile = $this->getAbsolutePath((string) $import['resource'], dirname($file));
104112

105-
return $loader->load($importedFile);
113+
return $loader->load($importedFile, false, $configuration);
106114
}
107115

108116
protected function parseDefinitions(BuilderConfiguration $configuration, $xml, $file)
@@ -325,12 +333,11 @@ protected function loadFromExtensions(BuilderConfiguration $configuration, $xml)
325333
}
326334

327335
$values = static::convertDomElementToArray($node);
328-
$config = $this->getExtension($node->namespaceURI)->load($node->localName, is_array($values) ? $values : array($values));
329-
330-
$r = new \ReflectionObject($this->getExtension($node->namespaceURI));
331-
$config->addResource(new FileResource($r->getFileName()));
336+
if (!is_array($values)) {
337+
$values = array();
338+
}
332339

333-
$configuration->merge($config);
340+
$configuration->loadFromExtension($this->getExtension($node->namespaceURI), $node->localName, $values);
334341
}
335342
}
336343

src/Symfony/Components/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,21 @@ class YamlFileLoader extends FileLoader
3232
/**
3333
* Loads an array of Yaml files.
3434
*
35-
* @param string $file A YAML file path
35+
* @param mixed $resource The resource
36+
* @param Boolean $main Whether this is the main load() call
37+
* @param BuilderConfiguration $configuration A BuilderConfiguration instance to use for the configuration
3638
*
3739
* @return BuilderConfiguration A BuilderConfiguration instance
3840
*/
39-
public function load($file)
41+
public function load($file, $main = true, BuilderConfiguration $configuration = null)
4042
{
4143
$path = $this->findFile($file);
4244

4345
$content = $this->loadFile($path);
4446

45-
$configuration = new BuilderConfiguration();
47+
if (null === $configuration) {
48+
$configuration = new BuilderConfiguration();
49+
}
4650

4751
$configuration->addResource(new FileResource($path));
4852

@@ -66,6 +70,10 @@ public function load($file)
6670
// extensions
6771
$this->loadFromExtensions($configuration, $content);
6872

73+
if ($main) {
74+
$configuration->mergeExtensionsConfiguration();
75+
}
76+
6977
return $configuration;
7078
}
7179

@@ -76,11 +84,11 @@ protected function parseImports(BuilderConfiguration $configuration, $content, $
7684
}
7785

7886
foreach ($content['imports'] as $import) {
79-
$configuration->merge($this->parseImport($import, $file));
87+
$this->parseImport($configuration, $import, $file);
8088
}
8189
}
8290

83-
protected function parseImport($import, $file)
91+
protected function parseImport(BuilderConfiguration $configuration, $import, $file)
8492
{
8593
$class = null;
8694
if (isset($import['class']) && $import['class'] !== get_class($this)) {
@@ -101,7 +109,7 @@ protected function parseImport($import, $file)
101109

102110
$importedFile = $this->getAbsolutePath($import['resource'], dirname($file));
103111

104-
return $loader->load($importedFile);
112+
return $loader->load($importedFile, false, $configuration);
105113
}
106114

107115
protected function parseDefinitions(BuilderConfiguration $configuration, $content, $file)
@@ -232,12 +240,7 @@ protected function loadFromExtensions(BuilderConfiguration $configuration, $cont
232240
$values = array();
233241
}
234242

235-
$config = static::getExtension($namespace)->load($tag, $values);
236-
237-
$r = new \ReflectionObject($this->getExtension($namespace));
238-
$config->addResource(new FileResource($r->getFileName()));
239-
240-
$configuration->merge($config);
243+
$configuration->loadFromExtension($this->getExtension($namespace), $tag, $values);
241244
}
242245
}
243246
}

tests/Symfony/Tests/Components/DependencyInjection/Loader/FileLoaderTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
namespace Symfony\Tests\Components\DependencyInjection\Loader;
1212

1313
use Symfony\Components\DependencyInjection\Builder;
14+
use Symfony\Components\DependencyInjection\BuilderConfiguration;
1415
use Symfony\Components\DependencyInjection\Loader\FileLoader;
1516

1617
class XmlDumperTest extends \PHPUnit_Framework_TestCase
@@ -44,7 +45,7 @@ class ProjectLoader extends FileLoader
4445
{
4546
public $paths;
4647

47-
public function load($resource)
48+
public function load($resource, $main = true, BuilderConfiguration $configuration = null)
4849
{
4950
}
5051

tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderExtensionTest.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,23 @@
1212

1313
require_once __DIR__.'/../../../../../fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php';
1414

15+
use Symfony\Components\DependencyInjection\BuilderConfiguration;
16+
1517
class LoaderExtensionTest extends \PHPUnit_Framework_TestCase
1618
{
1719
public function testLoad()
1820
{
1921
$extension = new \ProjectExtension();
2022

2123
try {
22-
$extension->load('foo', array());
24+
$extension->load('foo', array(), new BuilderConfiguration());
2325
$this->fail('->load() throws an InvalidArgumentException if the tag does not exist');
2426
} catch (\Exception $e) {
2527
$this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tag does not exist');
2628
$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');
2729
}
2830

29-
$config = $extension->load('bar', array('foo' => 'bar'));
31+
$config = $extension->load('bar', array('foo' => 'bar'), new BuilderConfiguration());
3032
$this->assertEquals(array('project.parameter.bar' => 'bar'), $config->getParameters(), '->load() calls the method tied to the given tag');
3133
}
3234
}

tests/Symfony/Tests/Components/DependencyInjection/Loader/LoaderTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
require_once __DIR__.'/../../../../../fixtures/Symfony/Components/DependencyInjection/includes/ProjectExtension.php';
1414

1515
use Symfony\Components\DependencyInjection\Loader\Loader;
16+
use Symfony\Components\DependencyInjection\BuilderConfiguration;
1617

1718
class ProjectLoader1 extends Loader
1819
{
19-
public function load($resource)
20+
public function load($resource, $main = true, BuilderConfiguration $configuration = null)
2021
{
2122
}
2223
}

0 commit comments

Comments
 (0)