From da50fdb8e2cf4f7714d0dce3c90cb4ddc1ed4d46 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Fri, 25 Nov 2016 14:27:11 +0100 Subject: [PATCH] [DI] Deprecate dumping an uncompiled container --- .../DependencyInjection/Dumper/PhpDumper.php | 4 + .../Tests/Dumper/PhpDumperTest.php | 31 ++++-- .../Tests/Fixtures/php/services1-1.php | 22 ++++- .../Tests/Fixtures/php/services1.php | 22 ++++- .../Tests/Fixtures/php/services19.php | 22 ++++- .../Tests/Fixtures/php/services24.php | 22 ++++- .../Tests/Fixtures/php/services8.php | 96 ++++++++++++++++++- 7 files changed, 201 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index f827ac013c..a333377482 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -72,6 +72,10 @@ class PhpDumper extends Dumper */ public function __construct(ContainerBuilder $container) { + if (!$container->isFrozen()) { + @trigger_error('Dumping an uncompiled ContainerBuilder is deprecated since version 3.3 and will not be supported anymore in 4.0. Compile the container beforehand.', E_USER_DEPRECATED); + } + parent::__construct($container); $this->inlinedDefinitions = new \SplObjectStorage(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 57469b9bed..7625eabfad 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -35,12 +35,15 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase public function testDump() { - $dumper = new PhpDumper($container = new ContainerBuilder()); + $container = new ContainerBuilder(); + $container->compile(); + $dumper = new PhpDumper($container); $this->assertStringEqualsFile(self::$fixturesPath.'/php/services1.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class'); $this->assertStringEqualsFile(self::$fixturesPath.'/php/services1-1.php', $dumper->dump(array('class' => 'Container', 'base_class' => 'AbstractContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Dump')), '->dump() takes a class and a base_class options'); $container = new ContainerBuilder(); + $container->compile(); new PhpDumper($container); } @@ -97,7 +100,9 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase */ public function testExportParameters($parameters) { - $dumper = new PhpDumper(new ContainerBuilder(new ParameterBag($parameters))); + $container = new ContainerBuilder(new ParameterBag($parameters)); + $container->compile(); + $dumper = new PhpDumper($container); $dumper->dump(); } @@ -114,25 +119,33 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase public function testAddParameters() { $container = include self::$fixturesPath.'/containers/container8.php'; + $container->compile(); $dumper = new PhpDumper($container); $this->assertStringEqualsFile(self::$fixturesPath.'/php/services8.php', $dumper->dump(), '->dump() dumps parameters'); } - public function testAddService() + /** + * @group legacy + * @expectedDeprecation Dumping an uncompiled ContainerBuilder is deprecated since version 3.3 and will not be supported anymore in 4.0. Compile the container beforehand. + */ + public function testAddServiceWithoutCompilation() { - // without compilation $container = include self::$fixturesPath.'/containers/container9.php'; $dumper = new PhpDumper($container); $this->assertEquals(str_replace('%path%', str_replace('\\', '\\\\', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9.php')), $dumper->dump(), '->dump() dumps services'); + } - // with compilation + public function testAddService() + { $container = include self::$fixturesPath.'/containers/container9.php'; $container->compile(); $dumper = new PhpDumper($container); $this->assertEquals(str_replace('%path%', str_replace('\\', '\\\\', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9_compiled.php')), $dumper->dump(), '->dump() dumps services'); - $dumper = new PhpDumper($container = new ContainerBuilder()); + $container = new ContainerBuilder(); $container->register('foo', 'FooClass')->addArgument(new \stdClass()); + $container->compile(); + $dumper = new PhpDumper($container); try { $dumper->dump(); $this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); @@ -145,6 +158,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase public function testServicesWithAnonymousFactories() { $container = include self::$fixturesPath.'/containers/container19.php'; + $container->compile(); $dumper = new PhpDumper($container); $this->assertStringEqualsFile(self::$fixturesPath.'/php/services19.php', $dumper->dump(), '->dump() dumps services with anonymous factories'); @@ -156,6 +170,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase $container = new ContainerBuilder(); $container->register('bar$', 'FooClass'); $container->register('bar$!', 'FooClass'); + $container->compile(); $dumper = new PhpDumper($container); eval('?>'.$dumper->dump(array('class' => $class))); @@ -169,6 +184,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase $container = new ContainerBuilder(); $container->register('foo_bar', 'FooClass'); $container->register('foobar', 'FooClass'); + $container->compile(); $dumper = new PhpDumper($container); eval('?>'.$dumper->dump(array('class' => $class))); @@ -182,6 +198,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase $container = new ContainerBuilder(); $container->register('bar', 'FooClass'); $container->register('foo_bar', 'FooClass'); + $container->compile(); $dumper = new PhpDumper($container); eval('?>'.$dumper->dump(array( 'class' => $class, @@ -203,6 +220,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase $def = new Definition('stdClass'); $def->setFactory($factory); $container->setDefinition('bar', $def); + $container->compile(); $dumper = new PhpDumper($container); $dumper->dump(); } @@ -285,6 +303,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase public function testDumpAutowireData() { $container = include self::$fixturesPath.'/containers/container24.php'; + $container->compile(); $dumper = new PhpDumper($container); $this->assertEquals(file_get_contents(self::$fixturesPath.'/php/services24.php'), $dumper->dump()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php index 0415d702a7..8f0d484866 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php @@ -6,7 +6,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; /** * Container. @@ -24,6 +24,24 @@ class Container extends AbstractContainer */ public function __construct() { - parent::__construct(); + $this->services = array(); + + $this->aliases = array(); + } + + /** + * {@inheritdoc} + */ + public function compile() + { + throw new LogicException('You cannot compile a dumped frozen container.'); + } + + /** + * {@inheritdoc} + */ + public function isFrozen() + { + return true; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1.php index e95d960fab..5325f965d2 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1.php @@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; /** * ProjectServiceContainer. @@ -23,6 +23,24 @@ class ProjectServiceContainer extends Container */ public function __construct() { - parent::__construct(); + $this->services = array(); + + $this->aliases = array(); + } + + /** + * {@inheritdoc} + */ + public function compile() + { + throw new LogicException('You cannot compile a dumped frozen container.'); + } + + /** + * {@inheritdoc} + */ + public function isFrozen() + { + return true; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php index e89c3c8f8e..cf23fc7fff 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php @@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; /** * ProjectServiceContainer. @@ -23,11 +23,29 @@ class ProjectServiceContainer extends Container */ public function __construct() { - parent::__construct(); + $this->services = array(); $this->methodMap = array( 'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService', 'service_with_method_call_and_factory' => 'getServiceWithMethodCallAndFactoryService', ); + + $this->aliases = array(); + } + + /** + * {@inheritdoc} + */ + public function compile() + { + throw new LogicException('You cannot compile a dumped frozen container.'); + } + + /** + * {@inheritdoc} + */ + public function isFrozen() + { + return true; } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php index a9724152f8..82772dc75a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php @@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; /** * ProjectServiceContainer. @@ -23,10 +23,28 @@ class ProjectServiceContainer extends Container */ public function __construct() { - parent::__construct(); + $this->services = array(); $this->methodMap = array( 'foo' => 'getFooService', ); + + $this->aliases = array(); + } + + /** + * {@inheritdoc} + */ + public function compile() + { + throw new LogicException('You cannot compile a dumped frozen container.'); + } + + /** + * {@inheritdoc} + */ + public function isFrozen() + { + return true; } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php index 252a35d03b..7994926c45 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php @@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; /** * ProjectServiceContainer. @@ -23,7 +23,95 @@ class ProjectServiceContainer extends Container */ public function __construct() { - parent::__construct(new ParameterBag($this->getDefaultParameters())); + $this->parameters = $this->getDefaultParameters(); + + $this->services = array(); + + $this->aliases = array(); + } + + /** + * {@inheritdoc} + */ + public function compile() + { + throw new LogicException('You cannot compile a dumped frozen container.'); + } + + /** + * {@inheritdoc} + */ + public function isFrozen() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getParameter($name) + { + $name = strtolower($name); + + if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters) || isset($this->loadedDynamicParameters[$name]))) { + throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); + } + if (isset($this->loadedDynamicParameters[$name])) { + return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + + return $this->parameters[$name]; + } + + /** + * {@inheritdoc} + */ + public function hasParameter($name) + { + $name = strtolower($name); + + return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters) || isset($this->loadedDynamicParameters[$name]); + } + + /** + * {@inheritdoc} + */ + public function setParameter($name, $value) + { + throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + + /** + * {@inheritdoc} + */ + public function getParameterBag() + { + if (null === $this->parameterBag) { + $parameters = $this->parameters; + foreach ($this->loadedDynamicParameters as $name => $loaded) { + $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + $this->parameterBag = new FrozenParameterBag($parameters); + } + + return $this->parameterBag; + } + + private $loadedDynamicParameters = array(); + private $dynamicParameters = array(); + + /** + * Computes a dynamic parameter. + * + * @param string The name of the dynamic parameter to load + * + * @return mixed The value of the dynamic parameter + * + * @throws InvalidArgumentException When the dynamic parameter does not exist + */ + private function getDynamicParameter($name) + { + throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); } /** @@ -34,9 +122,9 @@ class ProjectServiceContainer extends Container protected function getDefaultParameters() { return array( - 'foo' => '%baz%', + 'foo' => 'bar', 'baz' => 'bar', - 'bar' => 'foo is %%foo bar', + 'bar' => 'foo is %foo bar', 'escape' => '@escapeme', 'values' => array( 0 => true,