From 793b9a001f5fa09a501322aa4dcb8a3506fb6da2 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 31 May 2017 10:32:39 -0400 Subject: [PATCH] [DI] Autowiring exception thrown when inlined service is removed --- .../Compiler/AutowireExceptionPass.php | 16 ++++++- .../Compiler/InlineServiceDefinitionsPass.php | 6 ++- .../Compiler/AutowireExceptionPassTest.php | 43 +++++++++++++++++-- .../InlineServiceDefinitionsPassTest.php | 6 +-- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowireExceptionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowireExceptionPass.php index 2ee9427a15..a1ed422f73 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowireExceptionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowireExceptionPass.php @@ -44,9 +44,23 @@ class AutowireExceptionPass implements CompilerPassInterface $this->inlineServicePass = null; foreach ($exceptions as $exception) { - if ($container->hasDefinition($exception->getServiceId()) || in_array($exception->getServiceId(), $inlinedIds)) { + if ($this->doesServiceExistInTheContainer($exception->getServiceId(), $container, $inlinedIds)) { throw $exception; } } } + + private function doesServiceExistInTheContainer($serviceId, ContainerBuilder $container, array $inlinedIds) + { + if ($container->hasDefinition($serviceId)) { + return true; + } + + // was the service inlined? Of so, does its parent service exist? + if (isset($inlinedIds[$serviceId])) { + return $this->doesServiceExistInTheContainer($inlinedIds[$serviceId], $container, $inlinedIds); + } + + return false; + } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php index b084d7e4dc..a2eb511c64 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php @@ -36,7 +36,9 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe /** * Returns an array of all services inlined by this pass. * - * @return array Service id strings + * The key is the inlined service id and its value is the service it was inlined into. + * + * @return array */ public function getInlinedServiceIds() { @@ -57,7 +59,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) { $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); - $this->inlinedServiceIds[] = $id; + $this->inlinedServiceIds[$id] = $this->currentId; if ($definition->isShared()) { return $definition; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireExceptionPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireExceptionPassTest.php index 092b6401c4..8cd03f578a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireExceptionPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireExceptionPassTest.php @@ -54,7 +54,7 @@ class AutowireExceptionPassTest extends TestCase $autowirePass = $this->getMockBuilder(AutowirePass::class) ->getMock(); - $autowireException = new AutowiringFailedException('foo_service_id', 'An autowiring exception message'); + $autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message'); $autowirePass->expects($this->any()) ->method('getAutowiringExceptions') ->will($this->returnValue(array($autowireException))); @@ -63,10 +63,16 @@ class AutowireExceptionPassTest extends TestCase ->getMock(); $inlinePass->expects($this->any()) ->method('getInlinedServiceIds') - ->will($this->returnValue(array('foo_service_id'))); + ->will($this->returnValue(array( + // a_service inlined into b_service + 'a_service' => 'b_service', + // b_service inlined into c_service + 'b_service' => 'c_service', + ))); - // don't register the foo_service_id service $container = new ContainerBuilder(); + // ONLY register c_service in the final container + $container->register('c_service', 'stdClass'); $pass = new AutowireExceptionPass($autowirePass, $inlinePass); @@ -78,6 +84,37 @@ class AutowireExceptionPassTest extends TestCase } } + public function testDoNotThrowExceptionIfServiceInlinedButRemoved() + { + $autowirePass = $this->getMockBuilder(AutowirePass::class) + ->getMock(); + + $autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message'); + $autowirePass->expects($this->any()) + ->method('getAutowiringExceptions') + ->will($this->returnValue(array($autowireException))); + + $inlinePass = $this->getMockBuilder(InlineServiceDefinitionsPass::class) + ->getMock(); + $inlinePass->expects($this->any()) + ->method('getInlinedServiceIds') + ->will($this->returnValue(array( + // a_service inlined into b_service + 'a_service' => 'b_service', + // b_service inlined into c_service + 'b_service' => 'c_service', + ))); + + // do NOT register c_service in the container + $container = new ContainerBuilder(); + + $pass = new AutowireExceptionPass($autowirePass, $inlinePass); + + $pass->process($container); + // mark the test as passed + $this->assertTrue(true); + } + public function testNoExceptionIfServiceRemoved() { $autowirePass = $this->getMockBuilder(AutowirePass::class) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php index d241758b04..0eaea411f1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php @@ -252,7 +252,7 @@ class InlineServiceDefinitionsPassTest extends TestCase $this->assertSame('inline', (string) $values[0]); } - public function testGetInlinedServiceIds() + public function testGetInlinedServiceIdData() { $container = new ContainerBuilder(); $container @@ -265,7 +265,7 @@ class InlineServiceDefinitionsPassTest extends TestCase ; $container - ->register('service') + ->register('other_service') ->setArguments(array(new Reference('inlinable.service'))) ; @@ -273,7 +273,7 @@ class InlineServiceDefinitionsPassTest extends TestCase $repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), $inlinePass)); $repeatedPass->process($container); - $this->assertEquals(array('inlinable.service'), $inlinePass->getInlinedServiceIds()); + $this->assertEquals(array('inlinable.service' => 'other_service'), $inlinePass->getInlinedServiceIds()); } protected function process(ContainerBuilder $container)