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
-------
7b6f767fbe
[DI] allow decorators to reference their decorated service using the special `.inner` id
This commit is contained in:
commit
9a6695c094
@ -4,6 +4,7 @@ CHANGELOG
|
||||
5.1.0
|
||||
-----
|
||||
|
||||
* allow decorators to reference their decorated service using the special `.inner` id
|
||||
* added support to autowire public typed properties in php 7.4
|
||||
* added support for defining method calls, a configurator, and property setters in `InlineServiceConfigurator`
|
||||
* added possibility to define abstract service arguments
|
||||
|
@ -24,8 +24,15 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Diego Saint Esteben <diego@saintesteben.me>
|
||||
*/
|
||||
class DecoratorServicePass implements CompilerPassInterface
|
||||
class DecoratorServicePass extends AbstractRecursivePass
|
||||
{
|
||||
private $innerId = '.inner';
|
||||
|
||||
public function __construct(?string $innerId = '.inner')
|
||||
{
|
||||
$this->innerId = $innerId;
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$definitions = new \SplPriorityQueue();
|
||||
@ -49,6 +56,10 @@ class DecoratorServicePass implements CompilerPassInterface
|
||||
if (!$renamedId) {
|
||||
$renamedId = $id.'.inner';
|
||||
}
|
||||
|
||||
$this->currentId = $renamedId;
|
||||
$this->processValue($definition);
|
||||
|
||||
$definition->innerServiceId = $renamedId;
|
||||
$definition->decorationOnInvalid = $invalidBehavior;
|
||||
|
||||
@ -96,4 +107,13 @@ class DecoratorServicePass implements CompilerPassInterface
|
||||
$container->setAlias($inner, $id)->setPublic($public)->setPrivate($private);
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue($value, bool $isRoot = false)
|
||||
{
|
||||
if ($value instanceof Reference && $this->innerId === (string) $value) {
|
||||
return new Reference($this->currentId, $value->getInvalidBehavior());
|
||||
}
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class DecoratorServicePassTest extends TestCase
|
||||
{
|
||||
@ -242,6 +243,20 @@ class DecoratorServicePassTest extends TestCase
|
||||
$this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags());
|
||||
}
|
||||
|
||||
public function testGenericInnerReference()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo');
|
||||
|
||||
$container->register('bar')
|
||||
->setDecoratedService('foo')
|
||||
->setProperty('prop', new Reference('.inner'));
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertEquals(['prop' => new Reference('bar.inner')], $container->getDefinition('bar')->getProperties());
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new DecoratorServicePass();
|
||||
|
Reference in New Issue
Block a user