Skip to content

Commit 9cd68ee

Browse files
committed
bug #22993 [DI] Autowiring exception thrown when inlined service is removed (weaverryan)
This PR was squashed before being merged into the 3.3 branch (closes #22993). Discussion ---------- [DI] Autowiring exception thrown when inlined service is removed | Q | A | ------------- | --- | Branch? | 3.3 | Bug fix? | yes | New feature? | no | BC breaks? | yes | Deprecations? | yes (on a new & internal method) | Tests pass? | yes | Fixed tickets | #22977 | License | MIT | Doc PR | n/a We suppress autowiring exceptions if a service is ultimately removed from the container. This fixes a bug where we incorrectly report that a service was NOT removed, when really, it WAS removed. This happens when `ServiceA` is inlined in `ServiceB`... but then `ServiceB` is removed from the container for being unused. Commits ------- 793b9a0 [DI] Autowiring exception thrown when inlined service is removed
2 parents 5e40e19 + 793b9a0 commit 9cd68ee

File tree

4 files changed

+62
-9
lines changed

4 files changed

+62
-9
lines changed

src/Symfony/Component/DependencyInjection/Compiler/AutowireExceptionPass.php

+15-1
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,23 @@ public function process(ContainerBuilder $container)
4444
$this->inlineServicePass = null;
4545

4646
foreach ($exceptions as $exception) {
47-
if ($container->hasDefinition($exception->getServiceId()) || in_array($exception->getServiceId(), $inlinedIds)) {
47+
if ($this->doesServiceExistInTheContainer($exception->getServiceId(), $container, $inlinedIds)) {
4848
throw $exception;
4949
}
5050
}
5151
}
52+
53+
private function doesServiceExistInTheContainer($serviceId, ContainerBuilder $container, array $inlinedIds)
54+
{
55+
if ($container->hasDefinition($serviceId)) {
56+
return true;
57+
}
58+
59+
// was the service inlined? Of so, does its parent service exist?
60+
if (isset($inlinedIds[$serviceId])) {
61+
return $this->doesServiceExistInTheContainer($inlinedIds[$serviceId], $container, $inlinedIds);
62+
}
63+
64+
return false;
65+
}
5266
}

src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public function setRepeatedPass(RepeatedPass $repeatedPass)
3636
/**
3737
* Returns an array of all services inlined by this pass.
3838
*
39-
* @return array Service id strings
39+
* The key is the inlined service id and its value is the service it was inlined into.
40+
*
41+
* @return array
4042
*/
4143
public function getInlinedServiceIds()
4244
{
@@ -57,7 +59,7 @@ protected function processValue($value, $isRoot = false)
5759

5860
if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
5961
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
60-
$this->inlinedServiceIds[] = $id;
62+
$this->inlinedServiceIds[$id] = $this->currentId;
6163

6264
if ($definition->isShared()) {
6365
return $definition;

src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireExceptionPassTest.php

+40-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function testThrowExceptionIfServiceInlined()
5454
$autowirePass = $this->getMockBuilder(AutowirePass::class)
5555
->getMock();
5656

57-
$autowireException = new AutowiringFailedException('foo_service_id', 'An autowiring exception message');
57+
$autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message');
5858
$autowirePass->expects($this->any())
5959
->method('getAutowiringExceptions')
6060
->will($this->returnValue(array($autowireException)));
@@ -63,10 +63,16 @@ public function testThrowExceptionIfServiceInlined()
6363
->getMock();
6464
$inlinePass->expects($this->any())
6565
->method('getInlinedServiceIds')
66-
->will($this->returnValue(array('foo_service_id')));
66+
->will($this->returnValue(array(
67+
// a_service inlined into b_service
68+
'a_service' => 'b_service',
69+
// b_service inlined into c_service
70+
'b_service' => 'c_service',
71+
)));
6772

68-
// don't register the foo_service_id service
6973
$container = new ContainerBuilder();
74+
// ONLY register c_service in the final container
75+
$container->register('c_service', 'stdClass');
7076

7177
$pass = new AutowireExceptionPass($autowirePass, $inlinePass);
7278

@@ -78,6 +84,37 @@ public function testThrowExceptionIfServiceInlined()
7884
}
7985
}
8086

87+
public function testDoNotThrowExceptionIfServiceInlinedButRemoved()
88+
{
89+
$autowirePass = $this->getMockBuilder(AutowirePass::class)
90+
->getMock();
91+
92+
$autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message');
93+
$autowirePass->expects($this->any())
94+
->method('getAutowiringExceptions')
95+
->will($this->returnValue(array($autowireException)));
96+
97+
$inlinePass = $this->getMockBuilder(InlineServiceDefinitionsPass::class)
98+
->getMock();
99+
$inlinePass->expects($this->any())
100+
->method('getInlinedServiceIds')
101+
->will($this->returnValue(array(
102+
// a_service inlined into b_service
103+
'a_service' => 'b_service',
104+
// b_service inlined into c_service
105+
'b_service' => 'c_service',
106+
)));
107+
108+
// do NOT register c_service in the container
109+
$container = new ContainerBuilder();
110+
111+
$pass = new AutowireExceptionPass($autowirePass, $inlinePass);
112+
113+
$pass->process($container);
114+
// mark the test as passed
115+
$this->assertTrue(true);
116+
}
117+
81118
public function testNoExceptionIfServiceRemoved()
82119
{
83120
$autowirePass = $this->getMockBuilder(AutowirePass::class)

src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ public function testProcessDoesNotSetLazyArgumentValuesAfterInlining()
252252
$this->assertSame('inline', (string) $values[0]);
253253
}
254254

255-
public function testGetInlinedServiceIds()
255+
public function testGetInlinedServiceIdData()
256256
{
257257
$container = new ContainerBuilder();
258258
$container
@@ -265,15 +265,15 @@ public function testGetInlinedServiceIds()
265265
;
266266

267267
$container
268-
->register('service')
268+
->register('other_service')
269269
->setArguments(array(new Reference('inlinable.service')))
270270
;
271271

272272
$inlinePass = new InlineServiceDefinitionsPass();
273273
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), $inlinePass));
274274
$repeatedPass->process($container);
275275

276-
$this->assertEquals(array('inlinable.service'), $inlinePass->getInlinedServiceIds());
276+
$this->assertEquals(array('inlinable.service' => 'other_service'), $inlinePass->getInlinedServiceIds());
277277
}
278278

279279
protected function process(ContainerBuilder $container)

0 commit comments

Comments
 (0)