8000 feature #36389 [DI] allow decorators to reference their decorated ser… · symfony/symfony@9a6695c · GitHub
[go: up one dir, main page]

Skip to content

Commit 9a6695c

Browse files
committed
feature #36389 [DI] allow decorators to reference their decorated service using the special .inner id (nicolas-grekas)
This PR was merged into the 5.1-dev branch. Discussion ---------- [DI] allow decorators to reference their decorated service using the special `.inner` id | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - Right now, when one wants to decorate a service, one needs to reference the decorated service using `foo.inner`, where `foo` is the id of the decorating service. There are two issues with this IMHO: - it's weird to have to repeat the name of declaring service inside of it; - it doesn't play well with child definitions. In this PR, I propose to use `.inner` to fix both issues. Before: ```yaml services: decorating_service: arguments: [@decorating_service.inner] decorates: decorated_service ``` After: ```yaml services: decorating_service: arguments: [@.inner] decorates: decorated_service ``` Commits ------- 7b6f767 [DI] allow decorators to reference their decorated service using the special `.inner` id
2 parents c5bf92d + 7b6f767 commit 9a6695c

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
5.1.0
55
-----
66

7+
* allow decorators to reference their decorated service using the special `.inner` id
78
* added support to autowire public typed properties in php 7.4
89
* added support for defining method calls, a configurator, and property setters in `InlineServiceConfigurator`
910
* added possibility to define abstract service arguments

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,15 @@
2424
* @author Fabien Potencier <fabien@symfony.com>
2525
* @author Diego Saint Esteben <diego@saintesteben.me>
2626
*/
27-
class DecoratorServicePass implements CompilerPassInterface
27+
class DecoratorServicePass extends AbstractRecursivePass
2828
{
29+
private $innerId = '.inner';
30+
31+
public function __construct(?string $innerId = '.inner')
32+
{
33+
$this->innerId = $innerId;
34+
}
35+
2936
public function process(ContainerBuilder $container)
3037
{
3138
$definitions = new \SplPriorityQueue();
@@ -49,6 +56,10 @@ public function process(ContainerBuilder $container)
4956
if (!$renamedId) {
5057
$renamedId = $id.'.inner';
5158
}
59+
60+
$this->currentId = $renamedId;
61+
$this->processValue($definition);
62+
5263
$definition->innerServiceId = $renamedId;
5364
$definition->decorationOnInvalid = $invalidBehavior;
5465

@@ -96,4 +107,13 @@ public function process(ContainerBuilder $container)
96107
$container->setAlias($inner, $id)->setPublic($public)->setPrivate($private);
97108
}
98109
}
110+
111+
protected function processValue($value, bool $isRoot = false)
112+
{
113+
if ($value instanceof Reference && $this->innerId === (string) $value) {
114+
return new Reference($this->currentId, $value->getInvalidBehavior());
115+
}
116+
117+
return parent::processValue($value, $isRoot);
118+
}
99119
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass;
1717
use Symfony\Component\DependencyInjection\ContainerBuilder;
1818
use Symfony\Component\DependencyInjection\ContainerInterface;
19+
use Symfony\Component\DependencyInjection\Reference;
1920

2021
class DecoratorServicePassTest extends TestCase
2122
{
@@ -242,6 +243,20 @@ public function testProcessLeavesServiceLocatorTagOnOriginalDefinition()
242243
$this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags());
243244
}
244245

246+
public function testGenericInnerReference()
247+
{
248+
$container = new ContainerBuilder();
249+
$container->register('foo');
250+
251+
$container->register('bar')
252+
->setDecoratedService('foo')
253+
->setProperty('prop', new Reference('.inner'));
254+
255+
$this->process($container);
256+
257+
$this->assertEquals(['prop' => new Reference('bar.inner')], $container->getDefinition('bar')->getProperties());
258+
}
259+
245260
protected function process(ContainerBuilder $container)
246261
{
247262
$pass = new DecoratorServicePass();

0 commit comments

Comments
 (0)
0