8000 [DI] Service decoration: autowire the inner service · symfony/symfony@fdf91e0 · GitHub
[go: up one dir, main page]

Skip to content

Commit fdf91e0

Browse files
committed
[DI] Service decoration: autowire the inner service
1 parent 6470380 commit fdf91e0

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@
1313

1414
use Symfony\Component\DependencyInjection\ContainerBuilder;
1515
use Symfony\Component\DependencyInjection\Alias;
16+
use Symfony\Component\DependencyInjection\Definition;
17+
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
18+
use Symfony\Component\DependencyInjection\Reference;
1619

1720
/**
1821
* Overwrites a service but keeps the overridden one.
1922
*
2023
* @author Christophe Coevoet <stof@notk.org>
2124
* @author Fabien Potencier <fabien@symfony.com>
2225
* @author Diego Saint Esteben <diego@saintesteben.me>
26+
* @author Kévin Dunglas <dunglas@gmail.com>
2327
*/
2428
class DecoratorServicePass implements CompilerPassInterface
2529
{
@@ -62,6 +66,44 @@ public function process(ContainerBuilder $container)
6266
}
6367

6468
$container->setAlias($inner, $id)->setPublic($public)->setPrivate($private);
69+
$this->autowire($container, $definition, $renamedId);
70+
}
71+
}
72+
73+
private function autowire(ContainerBuilder $container, Definition $definition, string $renamedId): void
74+
{
75+
if (
76+
!$definition->isAutowired() ||
77+
null === ($innerClass = $container->findDefinition($renamedId)->getClass()) ||
78+
!($reflectionClass = $container->getReflectionClass($definition->getClass())) ||
79+
!$reflectionMethod = $reflectionClass->getConstructor()
80+
) {
81+
return;
82+
}
83+
84+
$innerIndex = null;
85+
foreach ($reflectionMethod->getParameters() as $index => $parameter) {
86+
if (
87+
null === ($type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, true)) ||
88+
!is_a($innerClass, $type, true)
89+
) {
90+
continue;
91+
}
92+
93+
if () {
94+
continue;
95+
}
96+
97+
if (null !== $innerIndex) {
98+
// There is more than one argument of the type of the decorated class
99+
return;
100+
}
101+
102+
$innerIndex = $index;
103+
}
104+
105+
if (null !== $innerIndex) {
106+
$definition->setArgument($innerIndex, new Reference($renamedId));
65107
}
66108
}
67109
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Symfony\Component\DependencyInjection\Alias;
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
1717
use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass;
18+
use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
19+
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarDecorator;
1820

1921
class DecoratorServicePassTest extends TestCase
2022
{
@@ -144,6 +146,21 @@ public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinitio
144146
$this->assertEquals(array('bar' => array('attr' => 'baz'), 'foobar' => array('attr' => 'bar')), $container->getDefinition('baz')->getTags());
145147
}
146148

149+
public function testAutowire()
150+
{
151+
$container = new ContainerBuilder();
152+
$container->register(Bar::class, Bar::class);
153+
$container
154+
->register(BarDecorator::class, BarDecorator::class)
155+
->setDecoratedService(Bar::class)
156+
->setAutowired(true)
157+
;
158+
159+
$this->process($container);
160+
161+
$this->assertSame('Symfony\Component\DependencyInjection\Tests\Fixtures\BarDecorator.inner', (string) $container->getDefinition(BarDecorator::class)->getArgument(1));
162+
}
163+
147164
protected function process(ContainerBuilder $container)
148165
{
149166
$repeatedPass = new DecoratorServicePass();
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
13+
14+
use Psr\Log\LoggerInterface;
15+
16+
/**
17+
* @author Kévin Dunglas <dunglas@gmail.com>
18+
*/
19+
class BarDecorator implements BarInterface
20+
{
21+
public function __construct(LoggerInterface $logger, BarInterface $decorated)
22+
{
23+
}
24+
}

0 commit comments

Comments
 (0)
0