You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
bug symfony#48093 [DependencyInjection] don't move locator tag for service subscriber (RobertMe)
This PR was merged into the 4.4 branch.
Discussion
----------
[DependencyInjection] don't move locator tag for service subscriber
| Q | A
| ------------- | ---
| Branch? | 4.4
| Bug fix? | yes
| New feature? | no
| Deprecations? | no
| Tickets | -
| License | MIT
| Doc PR | -
<!--
Replace this notice by a short README for your feature/bugfix.
This will help reviewers and should be a good start for the documentation.
Additionally (see https://symfony.com/releases):
- Always add tests and ensure they pass.
- Bug fixes must be submitted against the lowest maintained branch where they apply
(lowest branches are regularly merged to upper ones so they get the fixes too).
- Features and deprecations must be submitted against the latest branch.
- For new features, provide some code snippets to help understand usage.
- Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
- Never break backward compatibility (see https://symfony.com/bc).
-->
**From the commit message:**
Decorators move tags applied to the decorated service to the decorating service. But this (sometimes) breaks when the decorated service is a service subscriber, which has the argument for the container explicitly set.
This mostly works because the locator for the service subscriber is applied twice. The RegisterServiceSubscriberPass which creates the locator also sets a binding on the service. The
ResolveServiceSubscriberPass replaces the arguments referencing the ContainerInterface or ServiceProviderInterface for those services tagged with the container.service_subscriber.locator tag. So when the argument isn't provided in the service definition it will automatically be set using the binding. And in case the argument is set, it will be replaced by the Resolver pass based on the tag.
But this thus breaks in case a service explicitly sets the argument (which means the binding isn't applied) and the service being decorated (meaning the locator tag is "lost"). So add the locator tag to the list of tags to keep on the original service.
**Explanation:**
I found this issue when decorating the `Router`. The `Router` (in `FrameworkBundle`) uses a service subscriber, but this lead to a deprecation message for autowiring `Psr\...\ContainerInterface`. Debugging also showed that the full container was injected, and not the extracted service locator (service locator service actually was logged as removed for being unused). After investigation the issue was found to be as described above. The `router` service is declared with an argument for the `$container` parameter of the constructor, i.e.:
```xml
<service id="router.default" class="Symfony\Bundle\FrameworkBundle\Routing\Router">
<argument type="service" id="Psr\Container\ContainerInterface" />
```
Which leads to the binding, as declared in the `RegisterServiceSubscribersPass` pass not being applied. Later on the `DecoratorServicePass` pass moves the tags of the decorated service to the decorating service, where it only keeps the `container.service_subscriber` tag on the original service, and moves the `container.service_subscriber.locator` tag to the decorating service. When afterwards the `ResolveServiceSubscribersPass` pass is executed it will replace the arguments to the `ContainerInterface` with the created locator service (as defined in the `RegisterServiceSubscribersPass`). But this then fails because the `container.service_subscriber.locator` tag isn't applied anymore.
So when the `router` isn't decorated the `ResolveServiceSubscribersPass` pass is the one which makes the service subscriber work, replacing the original argument as defined in the service definition. But when it is decorated this breaks because the tag is missing.
The unit tests didn't detect this because: 1. the container isn't injected (and thus not validated); 2. even with validation of the container it would work as the binding would be applied. This is why I also kept the original unit test (but expanding the test with validating the container), which would still pass (based on the binding), and adding the additional test which explicitly sets the `$container` argument, which would fail (for the binding not being applied, and the tag being missing because of the decorator).
Commits
-------
3c7dbb4 [DependencyInjection] don't move locator tag for service subscriber
0 commit comments