Skip to content

Navigation Menu

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

[DependencyInjection] Service subscriber without autowire #60272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from

Conversation

Neirda24
Copy link
Contributor

@Neirda24 Neirda24 commented Apr 25, 2025

Q A
Branch? 7.3
Bug fix? no
New feature? yes
Deprecations? no
Issues Fix #...
License MIT

TL;DR

We needed to use the ServiceSubscriber feature in a reusable Bundle.
The best practices for Bundles is to not use the Autowire feature.
But the way service subscriber are registered / resolved only works with autowired services at the moment.

The goal of this PR is to provide a way to easily extract the Locator for a service subscriber class / definition and use it in a custom compiler pass for example.

class MyPass implements CompilerPassInterface
{
    public function process(...)
    {
        $myServiceSubscriber = $container->getDefinition('my_service_subscriber');

        $locator = RegisterServiceSubscribersPass::registerLocator($container, 'my_service_subscriber');

        $myServiceSubscriber->addMethodCall('setContainer', [$locator]);
    }
}

More details

  1. The ServiceSubscriberInterface is parsed by the RegisterServiceSubscribersPass if the service definition has the container.service_subscriber
  2. It process the getSubscribedServices static method to cerate a $serviceMap
  3. It registers a ServiceLocator specific for this Service
  4. It adds a tag container.service_subscriber.locator with the id of the service locator
  5. It automatically binds the locator on the service for anything matching PsrContainerInterface
  6. later on, it goes through ResolveServiceSubscribersPass which clears tags + inject the locator

There is mo way to insert a compiler pass in between those two, they have the same priority in the same PassConfig type.

Apart from re-doing all the logic ourselves, there are no easy way to create a service locator solely based on the interface.

Why do I need to use a ServiceSubscriber in my Bundle ?

Our bundle provides extension points, allowing developers to create their own services that integrate seamlessly with the bundle's internal logic. This improves the developer experience (DX) by simplifying service wiring.

Since we can't predict in advance which services these extensions will depend on, using a ServiceSubscriber is ideal. It allows us to support dynamic dependencies without requiring developers to write a compiler pass.

For example, if a developer adds a trait like TwigAwareTrait to a class, the twig service becomes a dependency. We want to give them the flexibility to inject such additional services—beyond those provided by default in the service locator—in a clean and declarative way.

@Neirda24 Neirda24 changed the title Service subscriber without autowire [DependencyInjection] Service subscriber without autowire Apr 25, 2025
@stof
Copy link
Member

stof commented Apr 25, 2025

I'd like to understand more what issue you face.

I'm using ServiceSubscriberInterface on a non-autowired service since years: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/901069c01e20ef4d6c4e0d638428656ae5bedcdf/src/Resources/config/change_password.xml#L24-L27

You need to configure your setContainer call explicitly, by referencing either PsrContainerInterface::class or ServiceProviderInterface::class (as those are the bindings registered by

@Neirda24
Copy link
Contributor Author

I'd like to understand more what issue you face.

I'm using ServiceSubscriberInterface on a non-autowired service since years: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/901069c01e20ef4d6c4e0d638428656ae5bedcdf/src/Resources/config/change_password.xml#L24-L27

You need to configure your setContainer call explicitly, by referencing either PsrContainerInterface::class or ServiceProviderInterface::class (as those are the bindings registered by

Oh. Didn't know this and din't figured out either. Let me try it out and maybe open a PR on documentation. If it works on my side I will close this PR. Thank you @stof

@Neirda24
Copy link
Contributor Author

Neirda24 commented May 4, 2025

@stof : indeed it works. thank you for your insight. Should I close this Pr then ?

@OskarStark
Copy link
Contributor

Yes and maybe provide something to the documentation to make this more discoverable?

@stof
Copy link
Member

stof commented May 13, 2025

It would indeed be great to document the way to configure service subscribers when not using autowiring.

@Neirda24
Copy link
Contributor Author

opened an issue to track this : symfony/symfony-docs#20959 and will get on it ASAP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.