feature #20634 [DI] Deprecate dumping an uncompiled container (ro0NL)

This PR was squashed before being merged into the 3.3-dev branch (closes #20634).

Discussion
----------

[DI] Deprecate dumping an uncompiled container

| Q             | A
| ------------- | ---
| Branch?       | "master"
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | https://github.com/symfony/symfony/pull/19673#issuecomment-242001836
| License       | MIT
| Doc PR        | reference to the documentation PR, if any

It makes the PHP dumper less complex. Compiled container goes in, compiled container goes out.

Relates to #19673

Commits
-------

da50fdb [DI] Deprecate dumping an uncompiled container
This commit is contained in:
Fabien Potencier 2016-12-19 09:23:26 +01:00
commit ed5b1d8968
7 changed files with 201 additions and 18 deletions

View File

@ -72,6 +72,10 @@ class PhpDumper extends Dumper
*/ */
public function __construct(ContainerBuilder $container) 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); parent::__construct($container);
$this->inlinedDefinitions = new \SplObjectStorage(); $this->inlinedDefinitions = new \SplObjectStorage();

View File

@ -35,12 +35,15 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
public function testDump() 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.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'); $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 = new ContainerBuilder();
$container->compile();
new PhpDumper($container); new PhpDumper($container);
} }
@ -97,7 +100,9 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
*/ */
public function testExportParameters($parameters) 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(); $dumper->dump();
} }
@ -114,25 +119,33 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
public function testAddParameters() public function testAddParameters()
{ {
$container = include self::$fixturesPath.'/containers/container8.php'; $container = include self::$fixturesPath.'/containers/container8.php';
$container->compile();
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services8.php', $dumper->dump(), '->dump() dumps parameters'); $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'; $container = include self::$fixturesPath.'/containers/container9.php';
$dumper = new PhpDumper($container); $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'); $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 = include self::$fixturesPath.'/containers/container9.php';
$container->compile(); $container->compile();
$dumper = new PhpDumper($container); $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'); $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->register('foo', 'FooClass')->addArgument(new \stdClass());
$container->compile();
$dumper = new PhpDumper($container);
try { try {
$dumper->dump(); $dumper->dump();
$this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); $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() public function testServicesWithAnonymousFactories()
{ {
$container = include self::$fixturesPath.'/containers/container19.php'; $container = include self::$fixturesPath.'/containers/container19.php';
$container->compile();
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services19.php', $dumper->dump(), '->dump() dumps services with anonymous factories'); $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 = new ContainerBuilder();
$container->register('bar$', 'FooClass'); $container->register('bar$', 'FooClass');
$container->register('bar$!', 'FooClass'); $container->register('bar$!', 'FooClass');
$container->compile();
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
eval('?>'.$dumper->dump(array('class' => $class))); eval('?>'.$dumper->dump(array('class' => $class)));
@ -169,6 +184,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo_bar', 'FooClass'); $container->register('foo_bar', 'FooClass');
$container->register('foobar', 'FooClass'); $container->register('foobar', 'FooClass');
$container->compile();
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
eval('?>'.$dumper->dump(array('class' => $class))); eval('?>'.$dumper->dump(array('class' => $class)));
@ -182,6 +198,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('bar', 'FooClass'); $container->register('bar', 'FooClass');
$container->register('foo_bar', 'FooClass'); $container->register('foo_bar', 'FooClass');
$container->compile();
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
eval('?>'.$dumper->dump(array( eval('?>'.$dumper->dump(array(
'class' => $class, 'class' => $class,
@ -203,6 +220,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
$def = new Definition('stdClass'); $def = new Definition('stdClass');
$def->setFactory($factory); $def->setFactory($factory);
$container->setDefinition('bar', $def); $container->setDefinition('bar', $def);
$container->compile();
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
$dumper->dump(); $dumper->dump();
} }
@ -285,6 +303,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
public function testDumpAutowireData() public function testDumpAutowireData()
{ {
$container = include self::$fixturesPath.'/containers/container24.php'; $container = include self::$fixturesPath.'/containers/container24.php';
$container->compile();
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
$this->assertEquals(file_get_contents(self::$fixturesPath.'/php/services24.php'), $dumper->dump()); $this->assertEquals(file_get_contents(self::$fixturesPath.'/php/services24.php'), $dumper->dump());

View File

@ -6,7 +6,7 @@ use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/** /**
* Container. * Container.
@ -24,6 +24,24 @@ class Container extends AbstractContainer
*/ */
public function __construct() 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;
} }
} }

View File

@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/** /**
* ProjectServiceContainer. * ProjectServiceContainer.
@ -23,6 +23,24 @@ class ProjectServiceContainer extends Container
*/ */
public function __construct() 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;
} }
} }

View File

@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/** /**
* ProjectServiceContainer. * ProjectServiceContainer.
@ -23,11 +23,29 @@ class ProjectServiceContainer extends Container
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); $this->services = array();
$this->methodMap = array( $this->methodMap = array(
'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService', 'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService',
'service_with_method_call_and_factory' => 'getServiceWithMethodCallAndFactoryService', '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;
} }
/** /**

View File

@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/** /**
* ProjectServiceContainer. * ProjectServiceContainer.
@ -23,10 +23,28 @@ class ProjectServiceContainer extends Container
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); $this->services = array();
$this->methodMap = array( $this->methodMap = array(
'foo' => 'getFooService', '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;
} }
/** /**

View File

@ -5,7 +5,7 @@ use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/** /**
* ProjectServiceContainer. * ProjectServiceContainer.
@ -23,7 +23,95 @@ class ProjectServiceContainer extends Container
*/ */
public function __construct() 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() protected function getDefaultParameters()
{ {
return array( return array(
'foo' => '%baz%', 'foo' => 'bar',
'baz' => 'bar', 'baz' => 'bar',
'bar' => 'foo is %%foo bar', 'bar' => 'foo is %foo bar',
'escape' => '@escapeme', 'escape' => '@escapeme',
'values' => array( 'values' => array(
0 => true, 0 => true,