Skip to content

Commit

Permalink
bug #21627 [DependencyInjection] make the service container builder r…
Browse files Browse the repository at this point in the history
…egister its own self referencing definition (hhamon)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DependencyInjection] make the service container builder register its own self referencing definition

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | ~
| License       | MIT
| Doc PR        | ~

Commits
-------

9c97496 [DependencyInjection] make the service container builder register the definition of its related service container service (and aliases) in order to make compiler passes be able to reference the special service_container service.
  • Loading branch information
fabpot committed Feb 28, 2017
2 parents 4a70919 + 9c97496 commit 526d396
Show file tree
Hide file tree
Showing 39 changed files with 234 additions and 21 deletions.
Expand Up @@ -40,10 +40,6 @@
<argument type="collection" />
</service>

<service id="Psr\Container\ContainerInterface" alias="service_container" public="false" />
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false" />
<service id="Symfony\Component\DependencyInjection\Container" alias="service_container" public="false" />

<service id="kernel" synthetic="true" />

<service id="filesystem" class="Symfony\Component\Filesystem\Filesystem" />
Expand Down
12 changes: 12 additions & 0 deletions src/Symfony/Component/DependencyInjection/ContainerBuilder.php
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\DependencyInjection;

use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
Expand Down Expand Up @@ -38,6 +39,7 @@
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
use Symfony\Component\DependencyInjection\LazyProxy\InheritanceProxyHelper;
use Symfony\Component\DependencyInjection\LazyProxy\InheritanceProxyInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;

Expand Down Expand Up @@ -117,6 +119,16 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private $vendors;

public function __construct(ParameterBagInterface $parameterBag = null)
{
parent::__construct($parameterBag);

$this->setDefinition('service_container', (new Definition(ContainerInterface::class))->setSynthetic(true));
$this->setAlias(PsrContainerInterface::class, new Alias('service_container', false));
$this->setAlias(ContainerInterface::class, new Alias('service_container', false));
$this->setAlias(Container::class, new Alias('service_container', false));
}

/**
* @var \ReflectionClass[] a list of class reflectors
*/
Expand Down
Expand Up @@ -15,6 +15,7 @@
require_once __DIR__.'/Fixtures/includes/ProjectExtension.php';

use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\Config\Resource\ComposerResource;
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\Config\Resource\DirectoryResource;
Expand All @@ -25,6 +26,7 @@
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
Expand All @@ -42,6 +44,22 @@

class ContainerBuilderTest extends TestCase
{
public function testDefaultRegisteredDefinitions()
{
$builder = new ContainerBuilder();

$this->assertCount(1, $builder->getDefinitions());
$this->assertTrue($builder->hasDefinition('service_container'));

$definition = $builder->getDefinition('service_container');
$this->assertInstanceOf(Definition::class, $definition);
$this->assertTrue($definition->isSynthetic());
$this->assertSame(ContainerInterface::class, $definition->getClass());
$this->assertTrue($builder->hasAlias(PsrContainerInterface::class));
$this->assertTrue($builder->hasAlias(ContainerInterface::class));
$this->assertTrue($builder->hasAlias(Container::class));
}

public function testDefinitions()
{
$builder = new ContainerBuilder();
Expand Down Expand Up @@ -203,7 +221,18 @@ public function testGetServiceIds()
$builder->register('foo', 'stdClass');
$builder->bar = $bar = new \stdClass();
$builder->register('bar', 'stdClass');
$this->assertEquals(array('foo', 'bar', 'service_container'), $builder->getServiceIds(), '->getServiceIds() returns all defined service ids');
$this->assertEquals(
array(
'service_container',
'foo',
'bar',
'Psr\Container\ContainerInterface',
'Symfony\Component\DependencyInjection\ContainerInterface',
'Symfony\Component\DependencyInjection\Container',
),
$builder->getServiceIds(),
'->getServiceIds() returns all defined service ids'
);
}

public function testAliases()
Expand Down Expand Up @@ -251,7 +280,7 @@ public function testGetAliases()

$builder->set('foobar', 'stdClass');
$builder->set('moo', 'stdClass');
$this->assertCount(0, $builder->getAliases(), '->getAliases() does not return aliased services that have been overridden');
$this->assertCount(3, $builder->getAliases(), '->getAliases() does not return aliased services that have been overridden');
}

public function testSetAliases()
Expand Down Expand Up @@ -538,7 +567,7 @@ public function testMerge()
$config->setDefinition('baz', new Definition('BazClass'));
$config->setAlias('alias_for_foo', 'foo');
$container->merge($config);
$this->assertEquals(array('foo', 'bar', 'baz'), array_keys($container->getDefinitions()), '->merge() merges definitions already defined ones');
$this->assertEquals(array('service_container', 'foo', 'bar', 'baz'), array_keys($container->getDefinitions()), '->merge() merges definitions already defined ones');

$aliases = $container->getAliases();
$this->assertTrue(isset($aliases['alias_for_foo']));
Expand Down
Expand Up @@ -70,6 +70,7 @@ public function testDumpAnonymousServices()
$this->assertEquals('<?xml version="1.0" encoding="utf-8"?>
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" synthetic="true"/>
<service id="foo" class="FooClass">
<argument type="service">
<service class="BarClass">
Expand All @@ -79,6 +80,9 @@ public function testDumpAnonymousServices()
</service>
</argument>
</service>
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
<service id="Symfony\Component\DependencyInjection\Container" alias="service_container" public="false"/>
</services>
</container>
', $dumper->dump());
Expand All @@ -91,10 +95,14 @@ public function testDumpEntities()
$this->assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\"?>
<container xmlns=\"http://symfony.com/schema/dic/services\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd\">
<services>
<service id=\"service_container\" class=\"Symfony\Component\DependencyInjection\ContainerInterface\" synthetic=\"true\"/>
<service id=\"foo\" class=\"FooClass\Foo\">
<tag name=\"foo&quot;bar\bar\" foo=\"foo&quot;barřž€\"/>
<argument>foo&lt;&gt;&amp;bar</argument>
</service>
<service id=\"Psr\Container\ContainerInterface\" alias=\"service_container\" public=\"false\"/>
<service id=\"Symfony\Component\DependencyInjection\ContainerInterface\" alias=\"service_container\" public=\"false\"/>
<service id=\"Symfony\Component\DependencyInjection\Container\" alias=\"service_container\" public=\"false\"/>
</services>
</container>
", $dumper->dump());
Expand All @@ -117,14 +125,22 @@ public function provideDecoratedServicesData()
array("<?xml version=\"1.0\" encoding=\"utf-8\"?>
<container xmlns=\"http://symfony.com/schema/dic/services\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd\">
<services>
<service id=\"service_container\" class=\"Symfony\Component\DependencyInjection\ContainerInterface\" synthetic=\"true\"/>
<service id=\"foo\" class=\"FooClass\Foo\" decorates=\"bar\" decoration-inner-name=\"bar.woozy\"/>
<service id=\"Psr\Container\ContainerInterface\" alias=\"service_container\" public=\"false\"/>
<service id=\"Symfony\Component\DependencyInjection\ContainerInterface\" alias=\"service_container\" public=\"false\"/>
<service id=\"Symfony\Component\DependencyInjection\Container\" alias=\"service_container\" public=\"false\"/>
</services>
</container>
", include $fixturesPath.'/containers/container15.php'),
array("<?xml version=\"1.0\" encoding=\"utf-8\"?>
<container xmlns=\"http://symfony.com/schema/dic/services\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd\">
<services>
<service id=\"service_container\" class=\"Symfony\Component\DependencyInjection\ContainerInterface\" synthetic=\"true\"/>
<service id=\"foo\" class=\"FooClass\Foo\" decorates=\"bar\"/>
<service id=\"Psr\Container\ContainerInterface\" alias=\"service_container\" public=\"false\"/>
<service id=\"Symfony\Component\DependencyInjection\ContainerInterface\" alias=\"service_container\" public=\"false\"/>
<service id=\"Symfony\Component\DependencyInjection\Container\" alias=\"service_container\" public=\"false\"/>
</services>
</container>
", include $fixturesPath.'/containers/container16.php'),
Expand Down
Expand Up @@ -3,5 +3,5 @@ digraph sc {
node [fontsize="11" fontname="Arial" shape="record"];
edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"];

node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface, Symfony\Component\DependencyInjection\Container)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"];
}
Expand Up @@ -3,8 +3,8 @@ digraph sc {
node [fontsize="13" fontname="Verdana" shape="square"];
edge [fontsize="12" fontname="Verdana" color="white" arrowhead="closed" arrowsize="1"];

node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface, Symfony\Component\DependencyInjection\Container)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=square, fillcolor="grey", style="filled"];
node_foo [label="foo\nFooClass\n", shape=square, fillcolor="grey", style="filled"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=square, fillcolor="green", style="empty"];
node_bar [label="bar\n\n", shape=square, fillcolor="red", style="empty"];
node_foo -> node_bar [label="" style="filled"];
}
Expand Up @@ -3,8 +3,8 @@ digraph sc {
node [fontsize="11" fontname="Arial" shape="record"];
edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"];

node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface, Symfony\Component\DependencyInjection\Container)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo [label="foo\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
node_bar [label="bar\n\n", shape=record, fillcolor="#ff9999", style="filled"];
node_foo -> node_bar [label="" style="filled"];
}
Expand Up @@ -3,8 +3,8 @@ digraph sc {
node [fontsize="11" fontname="Arial" shape="record"];
edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"];

node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo [label="foo\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_bar [label="bar\nBarClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
node_foo -> node_bar [label="" style="filled"];
}
Expand Up @@ -3,5 +3,5 @@ digraph sc {
node [fontsize="11" fontname="Arial" shape="record"];
edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"];

node_service_container [label="service_container\nContainer14\\ProjectServiceContainer\n", shape=record, fillcolor="#9999ff", style="filled"];
node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface, Symfony\Component\DependencyInjection\Container)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"];
}
Expand Up @@ -3,6 +3,6 @@ digraph sc {
node [fontsize="11" fontname="Arial" shape="record"];
edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"];

node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface, Symfony\Component\DependencyInjection\Container)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo [label="foo\n%foo.class%\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
}
Expand Up @@ -3,6 +3,7 @@ digraph sc {
node [fontsize="11" fontname="Arial" shape="record"];
edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"];

node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface, Symfony\Component\DependencyInjection\Container)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo [label="foo (alias_for_foo)\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo_baz [label="foo.baz\nBazClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_bar [label="bar\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
Expand Down Expand Up @@ -30,7 +31,6 @@ digraph sc {
node_lazy_context_ignore_invalid_ref [label="lazy_context_ignore_invalid_ref\nLazyContext\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_closure_proxy [label="closure_proxy\nBarClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_locator [label="service_locator\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"];
node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"];
node_foobaz [label="foobaz\n\n", shape=record, fillcolor="#ff9999", style="filled"];
Expand Down
Expand Up @@ -29,6 +29,11 @@ class Container extends AbstractContainer
public function __construct()
{
$this->services = array();
$this->normalizedIds = array(
'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface',
'symfony\\component\\dependencyinjection\\container' => 'Symfony\\Component\\DependencyInjection\\Container',
'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface',
);

$this->aliases = array();
}
Expand Down
Expand Up @@ -28,6 +28,11 @@ class ProjectServiceContainer extends Container
public function __construct()
{
$this->services = array();
$this->normalizedIds = array(
'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface',
'symfony\\component\\dependencyinjection\\container' => 'Symfony\\Component\\DependencyInjection\\Container',
'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface',
);

$this->aliases = array();
}
Expand Down
Expand Up @@ -30,6 +30,11 @@ public function __construct()
$this->parameters = $this->getDefaultParameters();

$this->services = array();
$this->normalizedIds = array(
'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface',
'symfony\\component\\dependencyinjection\\container' => 'Symfony\\Component\\DependencyInjection\\Container',
'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface',
);
$this->methodMap = array(
'test' => 'getTestService',
);
Expand Down
Expand Up @@ -34,6 +34,11 @@ public function __construct()
$this->parameters = $this->getDefaultParameters();

$this->services = array();
$this->normalizedIds = array(
'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface',
'symfony\\component\\dependencyinjection\\container' => 'Symfony\\Component\\DependencyInjection\\Container',
'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface',
);
$this->methodMap = array(
'test' => 'getTestService',
);
Expand Down
Expand Up @@ -28,6 +28,11 @@ class ProjectServiceContainer extends Container
public function __construct()
{
$this->services = array();
$this->normalizedIds = array(
'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface',
'symfony\\component\\dependencyinjection\\container' => 'Symfony\\Component\\DependencyInjection\\Container',
'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface',
);
$this->methodMap = array(
'bar' => 'getBarService',
);
Expand Down
Expand Up @@ -28,6 +28,11 @@ class ProjectServiceContainer extends Container
public function __construct()
{
$this->services = array();
$this->normalizedIds = array(
'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface',
'symfony\\component\\dependencyinjection\\container' => 'Symfony\\Component\\DependencyInjection\\Container',
'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface',
);
$this->methodMap = array(
'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService',
'service_with_method_call_and_factory' => 'getServiceWithMethodCallAndFactoryService',
Expand Down

0 comments on commit 526d396

Please sign in to comment.