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] Add#[Target] to tell how a dependency is used and hint named autowiring aliases#40800
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
carsonbot commentedApr 14, 2021
Hey! I think@fancyweb has recently worked with this code. Maybe they can help review this? Cheers! Carsonbot |
weaverryan commentedApr 14, 2021
Hi! Thanks for always thinking of new ways to frame & solve these problems :). function __construct(#[Purpose('review.state_machine')]WorkflowInterface$workflow) It looks like function __construct(#[Purpose('review.state_machine')]$workflow) I... think I "get" what the idea is... but it doesn't feel happy to me yet. I would still prefer to configure this in my service config... especially if that config is written in PHP :) |
nicolas-grekas commentedApr 14, 2021 • 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.
Except that the corresponding service identifier isnot necessarily
Right now, this isnot something that is configured in any of these files: bundles declare named autowiring aliases with :) |
fancyweb commentedApr 15, 2021
I love the idea. TBH, I never use argument name autowiring because I want my constructor argument to be However, I have a concern about the attribute name too. Purpose seems vague. Could it be something more explicit? |
javiereguiluz commentedApr 15, 2021
I like this proposal! Thank you! The name function__construct(#[Purpose('review.state_machine')]WorkflowInterface$workflow) {}function__construct(#[Inject('review.state_machine')]WorkflowInterface$workflow) {} |
stof commentedApr 15, 2021
The |
nicolas-grekas commentedApr 15, 2021 • 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.
Naming things... :)
Purpose is the most accurate to me, but the 2 others found fit also. |
fancyweb commentedApr 15, 2021 • 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.
Why? We could use the same attribute for another feature? |
nicolas-grekas commentedApr 15, 2021
Because that's what "description" means... :) |
fancyweb commentedApr 15, 2021
Could we correlate the attribute name with how we use it, for example |
nicolas-grekas commentedApr 15, 2021
I think that's too technical yes (and not accurate enough also: this is not a named autowiring alias). When you decide to name an argument I think that this attribute should keep that conceptual decoupling. Ie we should provide a way for class authors to make their classes more descriptive. Then, later on, if this added description is useful to autowiring, that's a match and a win. If we don't do this, we miss all the conceptual benefits of descriptive programming IMHO. |
fancyweb commentedApr 15, 2021
Thank you for the explanation. I understand it better now but there is still a difference for me. Originally, there is a decoupling because having an argument, whatever its name, is something required. However, using the attribute is optional. As a Symfony user, I'm not going to use the attribute to describe my argument, I have PHP comments for that. If I use the attribute, it's because I know something precise will happen. I like the idea of the conceptual decoupling though because we could maybe reuse it for another future feature and then describing one time the arg for many benefits would be awesome. But atm, IMHO, it will be easier for a random Symfony user to understand what the attribute is doing if its name is less generic. |
stof commentedApr 15, 2021
@fancyweb PHP comments are only about describing it for humans (as they are unstructured). PHP 8 attributes are precisely about describing the code for machines |
ro0NL commentedApr 15, 2021
a generic concept cannot have a less generic name :) to me being able to use local naming, eg. we can argue the attr should be moved to the service contract layer eventually to convey decoupled concepts, rather than being Symfony/DI specific still. What i like to propose is to make the list of "purposes" explicit. Eg. |
ro0NL commentedApr 15, 2021 • 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.
im also curious if registerAliasForAutowiring should be called registerPurposeForAutowiring with optin to aliasing (thus have both) edit: it's called registerAliasForArgument and $name can be the purpose name, never mind -_- |
Nyholm left a comment
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.
Cool. I also like this feature.
From a user's perspective. I don't really understand "Purpose". In my mind it sound more like a "wish" or "intent". Ie, "I like to have a 'review.state_machine', but it does not matter too much what I get".
I likeTarget andInject.
Uh oh!
There was an error while loading.Please reload this page.
ro0NL commentedApr 15, 2021 • 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.
see alsohttps://english.stackexchange.com/questions/323400/intention-vs-purpose i tend to agree "purpose" sounds more explicit towardsthe outcome, whereas "intended" would only implya certain outcome |
weaverryan commentedApr 16, 2021
Where can a user "look up" the possible values (e.g. A lot of people seem to dislike Also, what error would I get if I passed an incorrect value? And what error would I get if I used this in a totally inappropriate spot, like for an argument that has no type-hint at all... or an argument thatdoes have a type-hint, but where there is only one autowireable "type"?
For "humans", we can just describe the documentation in phpdoc. I understand that this attribute is specifically so that we can describe the purpose of an argument in a machine-readable language. And so, is there any other concrete usage of Cheers! |
ro0NL commentedApr 16, 2021 • 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.
purpose: i shall use this workflow for reviewing only personally, as a class author, i'd like to convey the first: "i cannot use this workflow for anything but reviewing" regardless of how i name my arguments ($flow, $workfFlow, $service, $totallyUnrelated). if the system injects a single autowireble type which should not be used for "some purpose", that's a user's config bug IMHO. At this point it couldnt provide anything else, and the user's config may very well be implying a single worflow fits all purposes 🤷 i think purpose + arg without typehint can be a compile error yes 🤔 i've no other use cases in mind yet, but |
javiereguiluz commentedApr 16, 2021
I would still use (1) (2) If you run (3) In the Symfony Docs (https://symfony.com/doc/current/workflow.html#accessing-the-workflow-in-a-class) we say this: useApp\Entity\BlogPost;useSymfony\Component\Workflow\WorkflowInterface;class MyClass{private$blogPublishingWorkflow;// this injects the blog_publishing workflow configured beforepublicfunction__construct(WorkflowInterface$blogPublishingWorkflow) {$this->blogPublishingWorkflow =$blogPublishingWorkflow; }// ...} Summary:
function__construct(#[Inject('review.state_machine')]WorkflowInterface$workflow) {} |
#[Purpose] to tell how a dependency is used and hint named autowiring aliases#[Target] to tell how a dependency is used and hint named autowiring aliasesnicolas-grekas commentedApr 16, 2021 • 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.
We should still be true to SOLID, and to "Inversion of Control".
This comment would be wrong. This does not inject anything. Symfony injects (IoC rules), and Symfony might read that attribute, but only if instructed to do so. I hope the doc will be careful into explaining things in the correct order, which is: classes declare their dependencies, and the outside world is responsible for providing the appropriate dependencies that fit both the need of the class, and the need of that outside world. A better wording would be "Symfony will inject the blog_publishing workflow configured before". |
nicolas-grekas commentedApr 16, 2021
I updated the PR to use |
Nyholm commentedApr 16, 2021
Im happy with using From my (the users) point of view: Im writing a class, I need some dependencies and I do want my arguments to map/target another service I've written. I can define that an argument will "target" a specific service. I understand that it is wrong, but this is my mindset when I write a service. |
stof commentedApr 16, 2021
@javiereguiluz |
nicolas-grekas commentedApr 16, 2021 • 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.
The exact same errors that you get when using named autowiring aliases already. That is: if a default autorwiring alias exists you'll get the corresponding service and no error, otherwise you'll get the suggestions computed by AutowiringPass.@lyrixx mentioned that these suggestions could be improved and he's right, but that's unrelated to this PR.
Nothing, as expected, because declarative programming means that.
Not yet, future will tell :) I think |
Uh oh!
There was an error while loading.Please reload this page.
…d and hint named autowiring aliases
Nyholm commentedApr 19, 2021
Thank you |
This PR was submitted for the 5.x branch but it was merged into the 4.4 branch instead.Discussion----------[Workflow] Updated wording on commentThis comes from a suggestion insymfony/symfony#40800Commits-------6f2c11a [Workflow] Updated wording on comment
Uh oh!
There was an error while loading.Please reload this page.
Right now, when one wants to target a specific service in a list of candidates, we rely on the name of the argument in addition to the type-hint, eg:
function foo(WorkflowInterface $reviewStateMachine)The deal is that by giving the argument a name that matches the target use case of the required dependency, we make autowiring more useful.
But sometimes, being able to de-correlate the name of the argument and the purpose is desired.
This PR introduces a new
#[Target]attribute on PHP8 that allows doing so. The previous example could be written as such thanks to it:function foo(#[Target('review.state_machine')] WorkflowInterface $workflow)That's all folks :)