diff --git a/src/Symfony/Components/DependencyInjection/Container.php b/src/Symfony/Components/DependencyInjection/Container.php index 48415b202773..5aa62f8a1359 100644 --- a/src/Symfony/Components/DependencyInjection/Container.php +++ b/src/Symfony/Components/DependencyInjection/Container.php @@ -72,10 +72,17 @@ public function __construct(ParameterBagInterface $parameterBag = null) } /** - * Freezes the container parameter bag. + * Freezes the container. + * + * This method does two things: + * + * * Parameter values are resolved; + * * The parameter bag is freezed. */ public function freeze() { + $this->parameterBag->resolve(); + $this->parameterBag = new FrozenParameterBag($this->parameterBag->all()); } diff --git a/src/Symfony/Components/DependencyInjection/ContainerBuilder.php b/src/Symfony/Components/DependencyInjection/ContainerBuilder.php index ec46a30888a8..5e4611d5e8a0 100644 --- a/src/Symfony/Components/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Components/DependencyInjection/ContainerBuilder.php @@ -79,6 +79,10 @@ public function addObjectResource($object) */ public function loadFromExtension(LoaderExtensionInterface $extension, $tag, array $values = array()) { + if (true === $this->isFrozen()) { + throw new \LogicException('Cannot load from an extension on a frozen container.'); + } + $namespace = $extension->getAlias(); $this->addObjectResource($extension); @@ -187,6 +191,10 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV */ public function merge(ContainerBuilder $container) { + if (true === $this->isFrozen()) { + throw new \LogicException('Cannot merge on a frozen container.'); + } + $this->addDefinitions($container->getDefinitions()); $this->addAliases($container->getAliases()); $this->parameterBag->add($container->getParameterBag()->all()); @@ -215,10 +223,16 @@ public function getExtensionContainers() } /** - * Commits the extension configuration into the main configuration - * and resolves parameter values. + * Freezes the container. + * + * This method does four things: + * + * * The extension configurations are merged; + * * Parameter values are resolved; + * * The parameter bag is freezed; + * * Extension loading is disabled. */ - public function commit() + public function freeze() { $parameters = $this->parameterBag->all(); $definitions = $this->definitions; @@ -233,9 +247,7 @@ public function commit() $this->addAliases($aliases); $this->parameterBag->add($parameters); - foreach ($this->parameterBag->all() as $key => $value) { - $this->parameterBag->set($key, $this->getParameterBag()->resolveValue($value)); - } + parent::freeze(); } /** diff --git a/src/Symfony/Components/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Components/DependencyInjection/Dumper/XmlDumper.php index 62bf2c64e72a..13954f4f4bc7 100644 --- a/src/Symfony/Components/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Components/DependencyInjection/Dumper/XmlDumper.php @@ -42,7 +42,13 @@ protected function addParameters() return ''; } - return sprintf(" \n%s \n", $this->convertParameters($this->escape($this->container->getParameterBag()->all()), 'parameter', 4)); + if ($this->container->isFrozen()) { + $parameters = $this->escape($this->container->getParameterBag()->all()); + } else { + $parameters = $this->container->getParameterBag()->all(); + } + + return sprintf(" \n%s \n", $this->convertParameters($parameters, 'parameter', 4)); } protected function addService($id, $definition) diff --git a/src/Symfony/Components/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Components/DependencyInjection/Dumper/YamlDumper.php index 65c9c0c63245..d2f528744f19 100644 --- a/src/Symfony/Components/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Components/DependencyInjection/Dumper/YamlDumper.php @@ -128,7 +128,13 @@ protected function addParameters() return ''; } - return Yaml::dump(array('parameters' => $this->prepareParameters($this->container->getParameterBag()->all())), 2); + if ($this->container->isFrozen()) { + $parameters = $this->prepareParameters($this->container->getParameterBag()->all()); + } else { + $parameters = $this->container->getParameterBag()->all(); + } + + return Yaml::dump(array('parameters' => $parameters), 2); } /** diff --git a/src/Symfony/Components/DependencyInjection/ParameterBag/ParameterBag.php b/src/Symfony/Components/DependencyInjection/ParameterBag/ParameterBag.php index 5132ab8dfe84..e9afe168ebca 100644 --- a/src/Symfony/Components/DependencyInjection/ParameterBag/ParameterBag.php +++ b/src/Symfony/Components/DependencyInjection/ParameterBag/ParameterBag.php @@ -105,6 +105,16 @@ public function has($name) return array_key_exists(strtolower($name), $this->parameters); } + /** + * Replaces parameter placeholders (%name%) by their values for all parameters. + */ + public function resolve() + { + foreach ($this->parameters as $key => $value) { + $this->parameters[$key] = $this->resolveValue($value); + } + } + /** * Replaces parameter placeholders (%name%) by their values. * @@ -120,31 +130,24 @@ public function resolveValue($value) $args[$this->resolveValue($k)] = $this->resolveValue($v); } - $value = $args; - } else if (is_string($value)) { - if (preg_match('/^%([^%]+)%$/', $value, $match)) { - // we do this to deal with non string values (boolean, integer, ...) - // the preg_replace_callback converts them to strings - if (!array_key_exists($name = strtolower($match[1]), $this->parameters)) { - throw new \RuntimeException(sprintf('The parameter "%s" must be defined.', $name)); - } - - $value = $this->parameters[$name]; - } else { - $parameters = $this->parameters; - $replaceParameter = function ($match) use ($parameters, $value) - { - if (!array_key_exists($name = strtolower($match[2]), $parameters)) { - throw new \RuntimeException(sprintf('The parameter "%s" must be defined (used in the following expression: "%s").', $name, $value)); - } - - return $parameters[$name]; - }; - - $value = str_replace('%%', '%', preg_replace_callback('/(?get(strtolower($match[1])); + } + + return str_replace('%%', '%', preg_replace_callback(array('/(?get(strtolower($match[1])); } } diff --git a/tests/Symfony/Tests/Components/DependencyInjection/ContainerBuilderTest.php b/tests/Symfony/Tests/Components/DependencyInjection/ContainerBuilderTest.php index 9115ca7c1f39..cd73f5eb3b4c 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/ContainerBuilderTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/ContainerBuilderTest.php @@ -313,14 +313,14 @@ public function testMerge() $config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%'))); $container->merge($config); ////// FIXME - $container->commit(); + $container->freeze(); $this->assertEquals(array('bar' => 'foo', 'foo' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones'); $container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo'))); $config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%', 'baz' => '%foo%'))); $container->merge($config); ////// FIXME - $container->commit(); + $container->freeze(); $this->assertEquals(array('bar' => 'foo', 'foo' => 'foo', 'baz' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones'); $container = new ContainerBuilder(); diff --git a/tests/Symfony/Tests/Components/DependencyInjection/CrossCheckTest.php b/tests/Symfony/Tests/Components/DependencyInjection/CrossCheckTest.php index 4c0349595c3e..eae20d6dca58 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/CrossCheckTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/CrossCheckTest.php @@ -32,22 +32,24 @@ public function testCrossCheck($fixture, $type) $loaderClass = 'Symfony\\Components\\DependencyInjection\\Loader\\'.ucfirst($type).'FileLoader'; $dumperClass = 'Symfony\\Components\\DependencyInjection\\Dumper\\'.ucfirst($type).'Dumper'; - $container1 = new ContainerBuilder(); - $loader1 = new $loaderClass($container1); - $loader1->load(self::$fixturesPath.'/'.$type.'/'.$fixture); - $container1->setParameter('path', self::$fixturesPath.'/includes'); + $tmp = tempnam('sf_service_container', 'sf'); + + $loader1 = new $loaderClass(); + file_put_contents($tmp, file_get_contents(self::$fixturesPath.'/'.$type.'/'.$fixture)); + $container1 = $loader1->load($tmp); $dumper = new $dumperClass($container1); - $tmp = tempnam('sf_service_container', 'sf'); file_put_contents($tmp, $dumper->dump()); - $container2 = new ContainerBuilder(); - $loader2 = new $loaderClass($container2); - $loader2->load($tmp); - $container2->setParameter('path', self::$fixturesPath.'/includes'); + $loader2 = new $loaderClass(); + $container2 = $loader2->load($tmp); unlink($tmp); + $this->assertEquals($container2->getAliases(), $container1->getAliases(), 'loading a dump from a previously loaded container returns the same container'); + $this->assertEquals($container2->getDefinitions(), $container1->getDefinitions(), 'loading a dump from a previously loaded container returns the same container'); + $this->assertEquals($container2->getParameterBag()->all(), $container1->getParameterBag()->all(), '->getParameterBag() returns the same value for both containers'); + $this->assertEquals(serialize($container2), serialize($container1), 'loading a dump from a previously loaded container returns the same container'); $this->assertEquals($container2->getParameterBag()->all(), $container1->getParameterBag()->all(), '->getParameterBag() returns the same value for both containers'); diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/containers/container8.php b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/containers/container8.php index 59331078f6b6..44c9b51686e9 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/containers/container8.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/containers/container8.php @@ -4,8 +4,9 @@ use Symfony\Components\DependencyInjection\ParameterBag\ParameterBag; $container = new ContainerBuilder(new ParameterBag(array( - 'FOO' => 'bar', - 'bar' => 'foo is %foo bar', + 'FOO' => '%baz%', + 'baz' => 'bar', + 'bar' => 'foo is %%foo bar', 'values' => array(true, false, null, 0, 1000.3, 'true', 'false', 'null'), ))); diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/php/services8.php b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/php/services8.php index 4a6e266dcd2b..3ec1a8deff60 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/php/services8.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/php/services8.php @@ -47,8 +47,9 @@ public function findAnnotatedServiceIds($name) protected function getDefaultParameters() { return array( - 'foo' => 'bar', - 'bar' => 'foo is %foo bar', + 'foo' => '%baz%', + 'baz' => 'bar', + 'bar' => 'foo is %%foo bar', 'values' => array( 0 => true, 1 => false, diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/xml/services8.xml b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/xml/services8.xml index 59dba00c1d62..f21f290eb3e3 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/xml/services8.xml +++ b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/xml/services8.xml @@ -4,7 +4,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd"> - bar + %baz% + bar foo is %%foo bar true diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/yaml/services8.yml b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/yaml/services8.yml index c1cd7a91483f..c09e9d9da4f9 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/yaml/services8.yml +++ b/tests/Symfony/Tests/Components/DependencyInjection/Fixtures/yaml/services8.yml @@ -1,5 +1,6 @@ parameters: - foo: bar + foo: '%baz%' + baz: bar bar: 'foo is %%foo bar' values: [true, false, null, 0, 1000.3, 'true', 'false', 'null'] diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Loader/XmlFileLoaderTest.php b/tests/Symfony/Tests/Components/DependencyInjection/Loader/XmlFileLoaderTest.php index a2933c4cb6fb..2e993a6a2057 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Loader/XmlFileLoaderTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/Loader/XmlFileLoaderTest.php @@ -173,7 +173,7 @@ public function testExtensions() // extension without an XSD $config = $loader->load('extensions/services1.xml'); - $config->commit(); + $config->freeze(); $services = $config->getDefinitions(); $parameters = $config->getParameterBag()->all(); @@ -185,7 +185,7 @@ public function testExtensions() // extension with an XSD $config = $loader->load('extensions/services2.xml'); - $config->commit(); + $config->freeze(); $services = $config->getDefinitions(); $parameters = $config->getParameterBag()->all(); diff --git a/tests/Symfony/Tests/Components/DependencyInjection/Loader/YamlFileLoaderTest.php b/tests/Symfony/Tests/Components/DependencyInjection/Loader/YamlFileLoaderTest.php index 0ef6173654a5..f1de7625843b 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/Loader/YamlFileLoaderTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/Loader/YamlFileLoaderTest.php @@ -107,7 +107,7 @@ public function testExtensions() $loader = new ProjectLoader3(self::$fixturesPath.'/yaml'); $config = $loader->load('services10.yml'); - $config->commit(); + $config->freeze(); $services = $config->getDefinitions(); $parameters = $config->getParameterBag()->all(); diff --git a/tests/Symfony/Tests/Components/DependencyInjection/ParameterBag/ParameterBagTest.php b/tests/Symfony/Tests/Components/DependencyInjection/ParameterBag/ParameterBagTest.php index 3aa93f28528f..539fdb6fb084 100644 --- a/tests/Symfony/Tests/Components/DependencyInjection/ParameterBag/ParameterBagTest.php +++ b/tests/Symfony/Tests/Components/DependencyInjection/ParameterBag/ParameterBagTest.php @@ -97,18 +97,18 @@ public function testResolveValue() $bag = new ParameterBag(array()); try { $bag->resolveValue('%foobar%', array()); - $this->fail('->resolveValue() throws a RuntimeException if a placeholder references a non-existant parameter'); + $this->fail('->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existant parameter'); } catch (\Exception $e) { - $this->assertInstanceOf('\RuntimeException', $e, '->resolveValue() throws a RuntimeException if a placeholder references a non-existant parameter'); - $this->assertEquals('The parameter "foobar" must be defined.', $e->getMessage(), '->resolveValue() throws a RuntimeException if a placeholder references a non-existant parameter'); + $this->assertInstanceOf('\InvalidArgumentException', $e, '->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existant parameter'); + $this->assertEquals('The parameter "foobar" must be defined.', $e->getMessage(), '->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existant parameter'); } try { $bag->resolveValue('foo %foobar% bar', array()); - $this->fail('->resolveValue() throws a RuntimeException if a placeholder references a non-existant parameter'); + $this->fail('->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existant parameter'); } catch (\Exception $e) { - $this->assertInstanceOf('\RuntimeException', $e, '->resolveValue() throws a RuntimeException if a placeholder references a non-existant parameter'); - $this->assertEquals('The parameter "foobar" must be defined (used in the following expression: "foo %foobar% bar").', $e->getMessage(), '->resolveValue() throws a RuntimeException if a placeholder references a non-existant parameter'); + $this->assertInstanceOf('\InvalidArgumentException', $e, '->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existant parameter'); + $this->assertEquals('The parameter "foobar" must be defined.', $e->getMessage(), '->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existant parameter'); } } }