-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Description
Symfony version(s) affected: 3.4 and newer (and older)
Description
A service that is marked as a service subscriber is not properly configured in the service container if that service is also decorated.
Instead of an on-the-fly generated mini-container, it gets the regular container.
How to reproduce
- Create a service that also implements ServiceSubscriberInterface
- Make that service use a private service
- Try to access that private service via the provided container
- This works just fine
But if you do this:
- Configure a decorate-tag for that ServiceSubscriberInterface-service
- Try to execute the same code with regards to the private service
- The provided container will now throw an exception about accessing a private service (or it being inlined/removed)
This is caused by the fact that all tags from decorated services are removed (in DecoratorServicePass) and 'moved' to the decorating "outer" service. This is correct behavior for most tags, but not for all.
Possible Solution
I'd guess none of the container.-tags should be moved, but at least not those that are intended to change how a specific service is configured rather than how it behaves to the "outside world" (i.e. container.service_subscriber and possibly container.service_locator).
If so, the tags should be moved more carefully here:
symfony/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php
Line 67 in 0bdf10a
$definition->setTags(array_merge($decoratingDefinition->getTags(), $definition->getTags())); |
Additional context
The behavior can fairly easily be seen by inspecting the container using debug:container
Non-decorated variant:
---------------- ------------------------------------------------------
Option Value
---------------- ------------------------------------------------------
Service ID DecoratedService
Class DecoratedService
Tags container.service_subscriber
Public yes
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
Arguments Service(.service_locator..eNNqBr.DecoratedService)
---------------- ------------------------------------------------------
Decorated variant, the tag is moved to the decorating service, which causes the generic service_container to be passed as argument.
The 'inner' service:
---------------- ----------------------------------------------------------------
Option Value
---------------- ----------------------------------------------------------------
Service ID DecoratedService.inner
Class DecoratedService
Tags -
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
Arguments Service(service_container)
---------------- ----------------------------------------------------------------
The 'decorating' service:
----------------- -----------------------------------------------------------
Option Value
----------------- -----------------------------------------------------------
Service ID DecoratingService
Class DecoratingService
Tags container.service_subscriber
Public yes
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured no
Arguments Service(DecoratedService.inner)
----------------- -----------------------------------------------------------