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
-------
793b9a001f
[DI] Autowiring exception thrown when inlined service is removed
This commit is contained in:
commit
9cd68ee77e
@ -44,9 +44,23 @@ class AutowireExceptionPass implements CompilerPassInterface
|
|||||||
$this->inlineServicePass = null;
|
$this->inlineServicePass = null;
|
||||||
|
|
||||||
foreach ($exceptions as $exception) {
|
foreach ($exceptions as $exception) {
|
||||||
if ($container->hasDefinition($exception->getServiceId()) || in_array($exception->getServiceId(), $inlinedIds)) {
|
if ($this->doesServiceExistInTheContainer($exception->getServiceId(), $container, $inlinedIds)) {
|
||||||
throw $exception;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,9 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
|
|||||||
/**
|
/**
|
||||||
* Returns an array of all services inlined by this pass.
|
* 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()
|
public function getInlinedServiceIds()
|
||||||
{
|
{
|
||||||
@ -57,7 +59,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
|
|||||||
|
|
||||||
if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
|
if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
|
||||||
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
|
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
|
||||||
$this->inlinedServiceIds[] = $id;
|
$this->inlinedServiceIds[$id] = $this->currentId;
|
||||||
|
|
||||||
if ($definition->isShared()) {
|
if ($definition->isShared()) {
|
||||||
return $definition;
|
return $definition;
|
||||||
|
@ -54,7 +54,7 @@ class AutowireExceptionPassTest extends TestCase
|
|||||||
$autowirePass = $this->getMockBuilder(AutowirePass::class)
|
$autowirePass = $this->getMockBuilder(AutowirePass::class)
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$autowireException = new AutowiringFailedException('foo_service_id', 'An autowiring exception message');
|
$autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message');
|
||||||
$autowirePass->expects($this->any())
|
$autowirePass->expects($this->any())
|
||||||
->method('getAutowiringExceptions')
|
->method('getAutowiringExceptions')
|
||||||
->will($this->returnValue(array($autowireException)));
|
->will($this->returnValue(array($autowireException)));
|
||||||
@ -63,10 +63,16 @@ class AutowireExceptionPassTest extends TestCase
|
|||||||
->getMock();
|
->getMock();
|
||||||
$inlinePass->expects($this->any())
|
$inlinePass->expects($this->any())
|
||||||
->method('getInlinedServiceIds')
|
->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();
|
$container = new ContainerBuilder();
|
||||||
|
// ONLY register c_service in the final container
|
||||||
|
$container->register('c_service', 'stdClass');
|
||||||
|
|
||||||
$pass = new AutowireExceptionPass($autowirePass, $inlinePass);
|
$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()
|
public function testNoExceptionIfServiceRemoved()
|
||||||
{
|
{
|
||||||
$autowirePass = $this->getMockBuilder(AutowirePass::class)
|
$autowirePass = $this->getMockBuilder(AutowirePass::class)
|
||||||
|
@ -252,7 +252,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
|
|||||||
$this->assertSame('inline', (string) $values[0]);
|
$this->assertSame('inline', (string) $values[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetInlinedServiceIds()
|
public function testGetInlinedServiceIdData()
|
||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
$container
|
$container
|
||||||
@ -265,7 +265,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
|
|||||||
;
|
;
|
||||||
|
|
||||||
$container
|
$container
|
||||||
->register('service')
|
->register('other_service')
|
||||||
->setArguments(array(new Reference('inlinable.service')))
|
->setArguments(array(new Reference('inlinable.service')))
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -273,7 +273,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
|
|||||||
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), $inlinePass));
|
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), $inlinePass));
|
||||||
$repeatedPass->process($container);
|
$repeatedPass->process($container);
|
||||||
|
|
||||||
$this->assertEquals(array('inlinable.service'), $inlinePass->getInlinedServiceIds());
|
$this->assertEquals(array('inlinable.service' => 'other_service'), $inlinePass->getInlinedServiceIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function process(ContainerBuilder $container)
|
protected function process(ContainerBuilder $container)
|
||||||
|
Reference in New Issue
Block a user