Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d2ea9bd

Browse filesBrowse files
committed
[DI] Service decoration: autowire the inner service
1 parent 4ef0b3e commit d2ea9bd
Copy full SHA for d2ea9bd

File tree

Expand file treeCollapse file tree

5 files changed

+145
-0
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+145
-0
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,18 @@
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;
19+
use Symfony\Component\DependencyInjection\TypedReference;
1620

1721
/**
1822
* Overwrites a service but keeps the overridden one.
1923
*
2024
* @author Christophe Coevoet <stof@notk.org>
2125
* @author Fabien Potencier <fabien@symfony.com>
2226
* @author Diego Saint Esteben <diego@saintesteben.me>
27+
* @author Kévin Dunglas <dunglas@gmail.com>
2328
*/
2429
class DecoratorServicePass implements CompilerPassInterface
2530
{
@@ -62,6 +67,38 @@ public function process(ContainerBuilder $container)
6267
}
6368

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

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php
+50Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
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;
20+
use Symfony\Component\DependencyInjection\Tests\Fixtures\NonAutowirableBarDecorator;
1821

1922
class DecoratorServicePassTest extends TestCase
2023
{
@@ -144,6 +147,53 @@ public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinitio
144147
$this->assertEquals(array('bar' => array('attr' => 'baz'), 'foobar' => array('attr' => 'bar')), $container->getDefinition('baz')->getTags());
145148
}
146149

150+
public function testAutowire()
151+
{
152+
$container = new ContainerBuilder();
153+
$container->register(Bar::class, Bar::class);
154+
$container
155+
->register(BarDecorator::class, BarDecorator::class)
156+
->setDecoratedService(Bar::class)
157+
->setAutowired(true)
158+
;
159+
160+
$this->process($container);
161+
162+
$definition = $container->getDefinition(BarDecorator::class);
163+
$this->assertCount(1, $definition->getArguments(), 'The "$logger" argument must not be autowired.');
164+
$this->assertSame('Symfony\Component\DependencyInjection\Tests\Fixtures\BarDecorator.inner', (string) $definition->getArgument(1));
165+
}
166+
167+
public function testDoNotAutowireWhenSeveralArgumentOfTheType()
168+
{
169+
$container = new ContainerBuilder();
170+
$container->register(Bar::class, Bar::class);
171+
$container
172+
->register(NonAutowirableBarDecorator::class, NonAutowirableBarDecorator::class)
173+
->setDecoratedService(Bar::class)
174+
->setAutowired(true)
175+
;
176+
177+
$this->process($container);
178+
179+
$this->assertEmpty($container->getDefinition(NonAutowirableBarDecorator::class)->getArguments());
180+
}
181+
182+
public function testDoNotAutowireWhenNoConstructor()
183+
{
184+
$container = new ContainerBuilder();
185+
$container->register(Bar::class, Bar::class);
186+
$container
187+
->register(NoConstructor::class, NoConstructor::class)
188+
->setDecoratedService(Bar::class)
189+
->setAutowired(true)
190+
;
191+
192+
$this->process($container);
193+
194+
$this->assertEmpty($container->getDefinition(NoConstructor::class)->getArguments());
195+
}
196+
147197
protected function process(ContainerBuilder $container)
148198
{
149199
$repeatedPass = new DecoratorServicePass();
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
class BarDecorator implements BarInterface
17+
{
18+
public function __construct(LoggerInterface $logger, BarInterface $decorated)
19+
{
20+
}
21+
}
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
class NoConstructor
15+
{
16+
}
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
class NonAutowirableBarDecorator implements BarInterface
17+
{
18+
public function __construct(LoggerInterface $logger, BarInterface $decorated1, BarInterface $decorated2)
19+
{
20+
}
21+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.