Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[DependencyInjection] Introduce a flag to enable setter autowiring#19631
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Ocramius commentedAug 16, 2016
Looks good to me! 👍 |
ro0NL commentedAug 16, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
What about allowing a collection of setters to autowire; |
dunglas commentedAug 16, 2016
@ro0NL I don't think there is much benefit compared to the existing calls: -[setMailer, ['@app.mailer']] |
Ocramius commentedAug 16, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
To clarify on why this change is needed, enabling auto-wiring without this flag could cause a BC break. Given following example service: class Foo{private$baz;publicfunction__construct(Bar$bar) {$this->baz =$bar; }publicfunctionsetBaz(Taz$taz) {$this->baz =$taz; }} Turning auto-wiring on in earlier Current This PR reverts the behavior to just |
ro0NL commentedAug 16, 2016
@dunglas guess so, it's considerable though. There will be situations you want toideally autowire 9/10 methods and face a all or nothing choice: go with autowiring or configure 9 services. We fully lose the autowiring benefit then.. which can be a, pragmatic, pain :-) |
Ocramius commentedAug 16, 2016
It's still out of the 80/20 use-case, from the looks of it. |
ro0NL commentedAug 16, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Agree :) edit: consider calls: -[setBar, [@arg]] -setFoo# autowired |
ro0NL commentedAug 16, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Yeah, i think i like autowire:true[autowire_]calls: -setBar -setFoo better than setters_autowired:true Or |
nicolas-grekas commentedAug 16, 2016
👍 |
1 similar comment
fabpot commentedAug 16, 2016
👍 |
chalasr commentedAug 16, 2016
Should we consider this for inheritance? At least makechildren inherit the flag and maybe allow themto change it? Actually doing it afterwards for the 👍 |
weaverryan commentedAug 17, 2016
I'm worried about usability. If you wantfull autowiring, it'll now be: autowire:trueautowire_setters:true That's a lot of work for something that's purely for rapid development. But, we need to keep BC also. What about this suggestion, which includes part of@ro0NL's idea: # A) deprecated, but would only autowire the constructor, allows BCautowire:true# B) would autowire everything, including settersautowiring:true# C) or, use an array to opt into only certain methodsautowiring:[__construct] This is also - accidentally - more flexible. |
chalasr commentedAug 17, 2016
Even more flexible, IMHO having to list the methods to autowire would indeed reduce the benefit of using this feature rather than fully fill The proposed flag sounds nice, keeping autowire managing only constructors per default which stay logic to me. Otherwise, what about a choice? autowiring:constructorautowiring:settersautowiring:[constructor, setters] (Depreciating the current flag) |
Ocramius commentedAug 17, 2016
@weaverryan regarding usability, this is a reminder that setter injection is generally harmful, and while it's a nice-to-have, it's usually to be discouraged. |
ro0NL commentedAug 17, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
This, imo, explains why it should be verbose. edit: i rather be explicit in what methods are called (autowired or not). The shortcut ( |
dunglas commentedAug 17, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I also agree with@Ocramius, we should discourage setter injection (it should be opt-in). I added initial support for setter autowiring (#17608) to ease the creation of Symfony controllers that don't depend of the container (#18193). Such classes will basically be automatically registered (e.g.:DunglasActionBundle), the user will not have to care about enabling setters autowiring by itself. Developpers wanting to always enable setters autowiring in other contexts can create a userland a compiler pass to do it. |
weaverryan commentedAug 17, 2016
Is it harmful? The user is already opting into magic. I'm not saying this is wrong, but I want to challenge the statement. Is there some evidence we can look at to support / contest this?
I'm interested in setter autowiring because of the potential to have traits with setters and helper methods - e.g. My proposal (#19631 (comment)) offers BC, ease-of-use and control... but assumes the best default mode for autowiring isconstructors and setters. |
Ocramius commentedAug 17, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Yes, due to basic design of service dependency immutability.
The comment about setter injection can be taken completely out of the scope of this PR or of the dependency injection component. |
dunglas commentedAug 17, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Yes, it's basically the same use case. But for such cases, a compiler pass can automatically enable setters autowiring (for instance if the service implements a given interface). |
weaverryan commentedAug 17, 2016
Ok, I'm getting out-voted, and the arguments are sound. 👍 for the current approach |
ro0NL commentedAug 18, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Just to clarify; this will call any defined IMO, it's the same trickiness what we currently try to avoid. |
dunglas commentedAug 18, 2016
ro0NL commentedAug 18, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I see. How does this solve optional dependencies? I don't want Point is: you need to know at all time, whenever you define a setter, on whatever level in the class-chain, it's gonna be called (if enabled). It's tricky, period. :) edit: i understand it's somewhat the current behavior, hence i can live with this approach. Just saying ;-) |
dunglas commentedAug 18, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
What do you think about the following config, it should satisfy everybody's needs and is backward compatible: autowire:true# constructor autowiringautowire:[__construct, setFoo, setBar]# autowire whitelisted methods onlyautowire:'*'# autowire constructor + every setters (following existing rules for setters autowiring) |
ro0NL commentedAug 18, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
What about autowire:true# enables constructor autowiring by default, if disabled no autowiring whatsoever happensautowire_calls:[autowireThis, andThat]# additional method calls to be autowiredautowire_setters:true# adds all setters to autowire_calls This looks intuitive.. but is limiting in a way, you can only autowire method calls when the constructor is autowired. |
nicolas-grekas commentedAug 18, 2016
I prefer@dunglas proposal because the various configurations are mutually exclusive, but having several keys allows setting several of them at once, and from a DX perspective requires remembering 3 keys. |
ro0NL commentedAug 18, 2016
Okay then.. let's do it :) Thanks for letting me clarify my point. |
ro0NL commentedAug 18, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@dunglas just thought of using bitwise flags, on php level it's pretty verbose; $definition->setAutowired(Definition::CONSTRUCTOR|Definition::SETTERS);// true = Definition::CONSTRUCTOR// array = whitelistif ($definition->getAutowired() & Definition::SETTERS) { } For yaml autowire:!php/const:Definition::FULL or allow the |
dunglas commentedAug 18, 2016
|
ro0NL commentedAug 18, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Understand, hence i proposed allowing the |
dunglas commentedAug 18, 2016
My proposal is more flexible and easier to learn (though) |
ro0NL commentedAug 18, 2016
Easier to learn, i guess so ;-) my proposal allows for adding Anyway, lets move on. |
stof commentedAug 18, 2016
@ro0NL your proposal shows the wrong Yaml snippet. It would be like this: autowire:!php/const:Symfony\Component\DependencyInjection\Definition::FULL |
ro0NL commentedAug 18, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Left that out intentionally 👼 i know it's a no-go in some ways (too verbose i guess), but im looking at this from the php side first. |
nicolas-grekas commentedAug 22, 2016
Status: needs work |
chalasr commentedSep 26, 2016
As said, it would be a BC break to don't get this merged for 3.2. |
dunglas commentedSep 26, 2016
I'll do it for the 3.2 release. If it's not ready, we'll revert the introduction of setter autowiring (and reintroduce it in 3.3) but I'll find the time to finish this PR. |
dunglas commentedOct 5, 2016
I opened a new PR implementing#19631 (comment):#20167 |
…configurable (dunglas)This PR was merged into the 3.3-dev branch.Discussion----------[DependencyInjection] Make method (setter) autowiring configurable| Q | A || --- | --- || Branch? | master || Bug fix? | no || New feature? | yes || BC breaks? | no || Deprecations? | maybe? || Tests pass? | yes || Fixed tickets |#19631 || License | MIT || Doc PR |symfony/symfony-docs#7041 |Follow up of#19631. Implements#19631 (comment):Edit: the last supported format:``` yamlservices: foo: class: Foo autowire: ['__construct', 'set*'] # Autowire constructor and all setters autowire: true # Converted by loaders in `autowire: ['__construct']` for BC autowire: ['foo', 'bar'] # Autowire only `foo` and `bar` methods```Outdated:``` yamlautowire: true # constructor autowiringautowire: [__construct, setFoo, setBar] # autowire whitelisted methods onlyautowire: '*' # autowire constructor + every setters (following existing rules for setters autowiring)```- [x] Allow to specify the list of methods in the XML loader- [x] Add tests for the YAML loaderCommits-------6dd53c7 [DependencyInjection] Introduce method injection for autowiring
…configurable (dunglas)This PR was merged into the 3.3-dev branch.Discussion----------[DependencyInjection] Make method (setter) autowiring configurable| Q | A || --- | --- || Branch? | master || Bug fix? | no || New feature? | yes || BC breaks? | no || Deprecations? | maybe? || Tests pass? | yes || Fixed tickets | #19631 || License | MIT || Doc PR |symfony/symfony-docs#7041 |Follow up of #19631. Implementssymfony/symfony#19631 (comment):Edit: the last supported format:``` yamlservices: foo: class: Foo autowire: ['__construct', 'set*'] # Autowire constructor and all setters autowire: true # Converted by loaders in `autowire: ['__construct']` for BC autowire: ['foo', 'bar'] # Autowire only `foo` and `bar` methods```Outdated:``` yamlautowire: true # constructor autowiringautowire: [__construct, setFoo, setBar] # autowire whitelisted methods onlyautowire: '*' # autowire constructor + every setters (following existing rules for setters autowiring)```- [x] Allow to specify the list of methods in the XML loader- [x] Add tests for the YAML loaderCommits-------6dd53c7 [DependencyInjection] Introduce method injection for autowiring
Uh oh!
There was an error while loading.Please reload this page.
This PR follows a discussion with@Ocramius:https://twitter.com/Ocramius/status/754630452045029376
It makes setter injection opt-in.
ping@weaverryan