- Issue created by @plach
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
This sounds similar to layout builder's section storage plugins which use context definitions to find matching plugins but don't have a way to order/weight plugins if there are multiple matches.
Experience builder could also use something similar - 🇬🇧United Kingdom catch
Also sounds similar-ish to breadcrumb builders (currently tagged services with an ::applies() method), a pattern which I recently copied for a contrib module. Not sure if it's actually applicable to breadcrumb builders but it did remind me of them.
- 🇨🇭Switzerland berdir Switzerland
IMHO: A primary reason for using plugins is to manage multiple instances and configuration for them, something that by definition isn't really needed for first-applicable-implementation wins.
Tagged services seem sufficient for this, breadcrumb builders is a valid example, so is for example the theme negotiator. It's pretty well standardized using the service_id_collector tag, see theme.negotiator and services tagged with theme_negotiator. Also supports priority.
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
One thing plugins have that tagged services don't is derivatives.
- 🇮🇹Italy plach Venezia
Thanks for the feedback :)
@catch:
Yep, and of course we have field widgets and formatters that have a similar
isApplicable
method. The main difference is that it's static. Having to instantiate the plugin to check its applicability is by design in the PoC code, since the logic may require to do more than just evaluating definition values.@berdir:
Tagged services seem sufficient for this, breadcrumb builders is a valid example, so is for example the theme negotiator. It's pretty well standardized using the service_id_collector tag, see theme.negotiator and services tagged with theme_negotiator. Also supports priority
Good point. I think there was a similar conversation when discussing the implementation of the language negotiation system: in the end we went with plugins but tagged services would likely have worked just as fine. At the time I was concerned with not burdening the DIC with too many services, but this is less of a concern.
@larowlan:
One thing plugins have that tagged services don't is derivatives.
Another good point :)
I definitely leveraged derivatives in combination with applicable plugins in one of my client projects. Being able to write custom logic for each plugin implementation but also to rely on derivatives for simpler strategies varying only by some parameter value (stored in the plugin definition) was definitely useful.
Which is my main objection to @berdir's point:
A primary reason for using plugins is to manage multiple instances and configuration for them, something that by definition isn't really needed for first-applicable-implementation wins.
It's definitely true that I never relied on plugin configuration in the client projects that are using the PoC code :)
- 🇨🇭Switzerland berdir Switzerland
Yes, I was just thinking about language negotiation stuff while I wrote my comment, some of them actually do have some configuration, but it's configuration that's stored globally in a single place. Can't have differently configured negotiator plugins.
You can kind of can register multiple services with a service provider, instead of the plugin definition you could pass in that logic in the constructor. But container-build time is trickier to manage, many things aren't fully available yet then. But you could also loop over something within the service itself. Coming back to the configuration point, if you don't need to manage differently configured variants, that should be fairly easy.
- 🇮🇹Italy plach Venezia
You can kind of can register multiple services with a service provider, instead of the plugin definition you could pass in that logic in the constructor. [...] But you could also loop over something within the service itself.
I can imagine passing something analogous to a plugin definition stored in the
.services.yml
file via service arguments, but I'm not sure I follow your suggestions: would you mind posting some pseudo-code? :) - 🇨🇭Switzerland berdir Switzerland
I'm not saying it's a good idea just that it's possible:
foreach (range(1, 5) as $i) { $container->register('mymodule.foo.' . $i, Foo::class) ->addTag('tag_foo') ->addArgument($i); }
But with my follow-up sentence, what I meant is that with plugins, having derivative plugins gives you distinct, reference things, e.g. specific menu blocks that you can place and use multiple times with different configuration. If all you care about is that any of the plugins take care of it, you don't need and you can just loop over your variations in your applies() of a single class.