-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpKernel] Handle multi-attribute controller arguments #40307
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
05ba4cb
to
bbef5bd
Compare
src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php
Outdated
Show resolved
Hide resolved
bbef5bd
to
9331628
Compare
I though of allowing multiple attributes when originally designing it but couldn't see the use-case. I see this feature as a potential replacement for the It's true that allowing multiple attributes doesn't limit the feature while allowing a potential new use case. The only things we will lose are:
Overall I would say I am slightly in disfavor of this PR since I see no use case for it while it has a few drawbacks but that's not a strong opinion. |
BTW, this PR is missing the update to the UserValueResolver to no longer use the deprecated API. |
9331628
to
cf03bcb
Compare
07c36bb
to
e55c7a8
Compare
Thank you for reviewing.
I can imagine use cases other than value resolution (e.g. decoration, introspection, validation...). Making the assumption that only one attribute will be needed feels wrong to me.
Fixed |
f14e5c8
to
de855a9
Compare
src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php
Outdated
Show resolved
Hide resolved
c13d68b
to
9c0b580
Compare
src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php
Outdated
Show resolved
Hide resolved
9c0b580
to
921d638
Compare
src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php
Outdated
Show resolved
Hide resolved
871adb3
to
c2c54e6
Compare
c2c54e6
to
d771e44
Compare
src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php
Show resolved
Hide resolved
$representative = \get_class($representative); | ||
foreach ($param->getAttributes() as $reflectionAttribute) { | ||
if (class_exists($reflectionAttribute->getName())) { | ||
$attributes[] = $reflectionAttribute->newInstance(); |
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.
I'm still not convinced we should call newInstance()
on arbitrary attributes. Do we have a way to whitelist relevant attributes beforehand? Note that this is more or less what the now-deprecated ArgumentInterface
did for us.
Alternatively: Can we make the newInstance()
call lazy, so we only perform it if $argumentMetadata->getAttributes(MyAttribute::class)
is called?
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.
Sure, we could use some closures for that. But is it really worth it? Instantiation should not be heavy...
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.
It shouldn't. Still, we trigger autoloading and attribute validation and execute someone else's code here. The reflection API intentionally gives us a way to prevent this. Why shouldn't we use it?
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.
Well, the autoloading will get triggered anyway when using getAttributes
in IS_INSTANCEOF
mode since we have an argument resolver in Symfony that does that it will be triggered anyway.
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.
You are right, autoloading might be triggered anyway if we use IS_INSTANCEOF
.
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 scope of the argument value resolver covers Symfony controllers exclusively.
Controllers are auto-registered callables that are executed at runtime, which might use third-party extensions we don't even know about. I mean, we do run someone else's code all the time in this area (take e.g sensio/framework-extra-bundle param converters... reflection-based logic is way more heavy there.)
So, after thinking twice at the possible alternatives, I propose to keep this PR as-is and iterate.
If someone comes up with a problematic case, we can reconsider pretty easily.
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.
I propose to keep this PR as-is and iterate.
👍🏻 We agree on the goal of the PR and discuss an implementation detail here. Let's merge and I'll try to create a follow-up PR to avoid unwanted newInstance()
calls.
If someone comes up with a problematic case, we can reconsider pretty easily.
Sorry for being so persistent here. I'd like to avoid the problematic case before the bugfix becomes a BC break.
Thanks Robin for working on this feature, this is much appreciated. |
Currently, the
ArgumentMetadata
class used for controller argument value resolution can only hold one attribute per controller argument, while a method argument can take multiple attributes.This allows accessing all attributes for a given argument, and deprecates the
ArgumentInterface
because it is not needed.Spotted by @nicolas-grekas.