From adf18198f6ec0c22ca3c140f6f7c2c55a981931c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 1 Dec 2017 14:14:10 +0100 Subject: [PATCH] [DI] Fix false-positive circular exception --- .../DependencyInjection/Dumper/PhpDumper.php | 2 +- .../Tests/ContainerBuilderTest.php | 3 ++ .../Tests/Dumper/PhpDumperTest.php | 3 ++ .../containers/container_almost_circular.php | 9 +++++ .../php/services_almost_circular_private.php | 20 +++++++++++ .../php/services_almost_circular_public.php | 36 +++++++++++++++++++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index fb933ce757f5a..2dbdd0acd6ce7 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -478,7 +478,7 @@ private function addServiceInlinedDefinitions($id, Definition $definition, \SplO // $b = new ServiceB(); // $a = new ServiceA(ServiceB $b); // $b->setServiceA(ServiceA $a); - if ($this->hasReference($id, array($def->getArguments(), $def->getFactory()))) { + if (isset($inlinedDefinition[$definition]) && $this->hasReference($id, array($def->getArguments(), $def->getFactory()))) { throw new ServiceCircularReferenceException($id, array($id)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index bbc2c01ef075a..4fc89eb0b472a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -1263,6 +1263,9 @@ public function testAlmostCircular($visibility) $this->assertSame($foo2, $foo2->bar->foobar->foo); $this->assertSame(array(), (array) $container->get('foobar4')); + + $foo5 = $container->get('foo5'); + $this->assertSame($foo5, $foo5->bar->foo); } public function provideAlmostCircular() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index b70dc7b172b28..7455dd6cde681 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -782,6 +782,9 @@ public function testAlmostCircular($visibility) $this->assertSame($foo2, $foo2->bar->foobar->foo); $this->assertSame(array(), (array) $container->get('foobar4')); + + $foo5 = $container->get('foo5'); + $this->assertSame($foo5, $foo5->bar->foo); } public function provideAlmostCircular() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php index 6d73b3ec6c774..dff937ccdbb7f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php @@ -46,4 +46,13 @@ $container->register('foobar4', 'stdClass')->setPublic(true) ->addArgument(new Reference('foo4')); +// loop on the constructor of a setter-injected dep with property + +$container->register('foo5', 'stdClass')->setPublic(true) + ->setProperty('bar', new Reference('bar5')); + +$container->register('bar5', 'stdClass')->setPublic($public) + ->addArgument(new Reference('foo5')) + ->setProperty('foo', new Reference('foo5')); + return $container; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php index 1707f8912781f..ea0e155f30735 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php @@ -27,6 +27,7 @@ public function __construct() 'bar3' => 'getBar3Service', 'foo' => 'getFooService', 'foo2' => 'getFoo2Service', + 'foo5' => 'getFoo5Service', 'foobar4' => 'getFoobar4Service', ); @@ -39,6 +40,7 @@ public function getRemovedIds() 'Psr\\Container\\ContainerInterface' => true, 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, 'bar' => true, + 'bar5' => true, 'foo4' => true, 'foobar' => true, 'foobar2' => true, @@ -125,6 +127,24 @@ protected function getFoo2Service() return $this->services['foo2'] = new \FooCircular($a); } + /** + * Gets the public 'foo5' shared service. + * + * @return \stdClass + */ + protected function getFoo5Service() + { + $this->services['foo5'] = $instance = new \stdClass(); + + $a = new \stdClass(${($_ = isset($this->services['foo5']) ? $this->services['foo5'] : $this->getFoo5Service()) && false ?: '_'}); + + $a->foo = $instance; + + $instance->bar = $a; + + return $instance; + } + /** * Gets the public 'foobar4' shared service. * diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php index 5d4d9b0f29cf9..36961d1c853d5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php @@ -25,9 +25,11 @@ public function __construct() $this->methodMap = array( 'bar' => 'getBarService', 'bar3' => 'getBar3Service', + 'bar5' => 'getBar5Service', 'foo' => 'getFooService', 'foo2' => 'getFoo2Service', 'foo4' => 'getFoo4Service', + 'foo5' => 'getFoo5Service', 'foobar' => 'getFoobarService', 'foobar2' => 'getFoobar2Service', 'foobar3' => 'getFoobar3Service', @@ -93,6 +95,26 @@ protected function getBar3Service() return $instance; } + /** + * Gets the public 'bar5' shared service. + * + * @return \stdClass + */ + protected function getBar5Service() + { + $a = ${($_ = isset($this->services['foo5']) ? $this->services['foo5'] : $this->getFoo5Service()) && false ?: '_'}; + + if (isset($this->services['bar5'])) { + return $this->services['bar5']; + } + + $this->services['bar5'] = $instance = new \stdClass($a); + + $instance->foo = $a; + + return $instance; + } + /** * Gets the public 'foo' shared service. * @@ -139,6 +161,20 @@ protected function getFoo4Service() return $instance; } + /** + * Gets the public 'foo5' shared service. + * + * @return \stdClass + */ + protected function getFoo5Service() + { + $this->services['foo5'] = $instance = new \stdClass(); + + $instance->bar = ${($_ = isset($this->services['bar5']) ? $this->services['bar5'] : $this->getBar5Service()) && false ?: '_'}; + + return $instance; + } + /** * Gets the public 'foobar' shared service. *