-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DependencyInjection] Allow using expressions as service factories #45447
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
7ff5a05
to
9de21bb
Compare
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.
That is interesting! There are BC concerns we need to consider 🤔
Eg AbstractRecursivePass::getConstructor()
needs an update now, and classes in the FrameworkBundle's Descriptor namespace also.
Yeah, it might needs a bit of work to finish it, I wasn't really familiar with the DI components internal implementation before starting this PR so I might have missed some things. Concerning the Concerning BC breaks, the only one I see is concerning the typing of the factory property in case someone was writing a compiler pass that doesn't expect to receive an expression object from it. |
61aa6c9
to
65ff961
Compare
I've decided to go with returning the |
65ff961
to
098ad8b
Compare
Thinking about all this, what you want to achieve can be done by writing: $services->set(MyServiceInterface::class)
->factory('current')
->arg([expr("env('MY_ENV_VAR') ? service('some_service') : service('some_other_service')")]) If this works already, this proves we don't need to change any interfaces. Instead, we might want to improve the way this can be expressed. |
While working on the feature I thought of a similar workaround with a user defined identity function but it still feels like a hack and having a supported way of doing without any hacks would be better for documentation and discoverability. |
It took me a while to figure out an approach that could work, and here it is: #45512 |
Closing in favor of #45512 |
…ce factories (nicolas-grekas, jvasseur) This PR was squashed before being merged into the 6.1 branch. Discussion ---------- [DependencyInjection] Allow using expressions as service factories | Q | A | ------------- | --- | Branch? | 6.1 | Bug fix? | no | New feature? | yes | Deprecations? | yes | Tickets | - | License | MIT | Doc PR | - Replaces #45447 This PR allows using expressions as service factories: - in YAML: `factory: '@=service("foo").bar()'` - in PHP: `->factory(expr('service("foo").bar()'))` - in XML: `<factory expression="service('foo').bar()" />` In addition, it allows the corresponding expressions to get access to the arguments of the service definition using the `arg($index)` function and `args` variable inside expressions: ```yaml services: foo: factory: '@=arg(0).baz()' # works also: @=args.get(0).baz() arguments: ['@bar'] ``` Internally, instead of allowing `Expression` objects in `Definition` objects as in #45447, factory expressions are conveyed as a strings that starts with `@=`. This is chosen by taking inspiration from yaml and to not collide with any existing callable. Commits ------- c430989 [DependencyInjection] Allow using expressions as service factories
This makes it easier to create services base on more complex expressions like for example switching the implementation based on an env variable.
I often find myself having to do this kind of switching and having a way to do it directly in services configuration instead of having to create a factory for it would be great.
I was actually surprise by how small the required patch was to support it.