-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Automatically process extensions when they implement CompilerPassInterface #13761
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
Conversation
55fdf96
to
8d0edd0
Compare
You get a 👍 from me for this idea. I've actually ran into this "issue" a few times myself. What about allowing callables to be passed to container itself? I know it would be a BC break for the current container, but it does allow you to flexibly add the passes at the right moment. Though the current PR makes it easier to add it to the most use cases, it will not allow you to register anything but the default. |
public function process(ContainerBuilder $container) | ||
{ | ||
foreach ($container->getExtensions() as $extension) { | ||
if (!$extension instanceof CompilerExtensionInterface) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about checking whether the extension implements CompilerPassInterface instead of introducing a different interface ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is that the CompilerPassInterface
requires a method called process()
, which I don't think is very describing in the Extension context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wouterj actually, compile()
is misleading as the container builder is not compiled here. It is still being processed, so I'll vote for process()
and using the existing interface.
Wouldn't it be better to call this class InlineCompilerPass
or ExtensionCompilerPass
?
8d0edd0
to
6c50013
Compare
I've updated the PR with the suggestions (removed new interface, reuse ping @symfony/deciders |
@wouterj but we can't register extension as instance of CompilerPassInterface ? https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/DependencyInjection/ContainerBuilder.php#L133 |
@aitboudad a class can implement multiple interfaces: class AppExtension implements ExtensionInterface, CompilerPassInterface
{ |
@wouterj then how to avoid the duplicate call of process if someone already addCompilerPass for an extension ? |
👍 |
Maybe dumb question, but is it possible/desirable to create a compiler tag for this instead of using the interface check? I'm not a big fan of "configuration by interface". |
@nicolas-grekas not sure how this would work. You'd need to register an extension as a service, right? This PR is all about decreasing amount of work the end user needs to do to get his compiler pass registered. DI Extension would also act as a compiler pass. |
@jakzal ok, understood, extensions classes are not meant for wide range reuse |
I'm 👍 btw :) |
Thank you @wouterj. |
…ompilerPassInterface (WouterJ) This PR was merged into the 2.7 branch. Discussion ---------- Automatically process extensions when they implement CompilerPassInterface | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | todo (if people are in favor of this PR) Compiler passes are very powerfull, but also quite strange to work with. Especially when you just need a very simple compiler pass (like https://github.com/symfony-cmf/RoutingBundle/blob/master/DependencyInjection/Compiler/SetRouterPass.php). For 3 lines of code, you need to tweak your bundle class and create a new class. When using the DI component standalone, compiler passes are even harder to work with, as DI extensions can't register them. I believe that's why libraries like Behat make their extensions compiler passes by default. I think it would be very easy to just implement an interface and have a `compile` method for the simple compiler pass stuff. If a bundle needs multiple compiler passes or need compiler passes to be executed at other times in the compile process, a bundle can use the normal compiler passes. But if it's just one simple thing, like replacing a definition or getting services with a specific tag, I think this method will be very usefull. Commits ------- 6c50013 Allowed extensions to inline compiler passes
This one has been inadvertently merged into the 2.7 version. Not a big deal, just for reference. |
…asses (WouterJ) This PR was squashed before being merged into the 2.8 branch (closes #5920). Discussion ---------- Document automatic registration of extension compiler passes | Q | A | --- | --- | Doc fix? | no | New docs? | yes (symfony/symfony#13761) | Applies to | 2.8+ | Fixed tickets | - Commits ------- 353df25 Document automatic registration of extension compiler passes
…ssInterface (nicolas-grekas) This PR was squashed before being merged into the 3.4 branch (closes #24257). Discussion ---------- [HttpKernel][DI] Enable Kernel to implement CompilerPassInterface | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - In the same spirit as #13761 that allowed DI exts to be also compiler passes, and as #23812 that allowed the kernel to listen to events, in our new bundle-less world, should we allow the kernel to register itself as a compiler pass? That would make some scenario possible (like having a `TestKernel` that turns some services public.) Commits ------- 6973a1a [HttpKernel][DI] Enable Kernel to implement CompilerPassInterface
Compiler passes are very powerfull, but also quite strange to work with. Especially when you just need a very simple compiler pass (like https://github.com/symfony-cmf/RoutingBundle/blob/master/DependencyInjection/Compiler/SetRouterPass.php). For 3 lines of code, you need to tweak your bundle class and create a new class.
When using the DI component standalone, compiler passes are even harder to work with, as DI extensions can't register them. I believe that's why libraries like Behat make their extensions compiler passes by default.
I think it would be very easy to just implement an interface and have a
compile
method for the simple compiler pass stuff. If a bundle needs multiple compiler passes or need compiler passes to be executed at other times in the compile process, a bundle can use the normal compiler passes. But if it's just one simple thing, like replacing a definition or getting services with a specific tag, I think this method will be very usefull.