Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[HttpKernel] Fix ArgumentValueResolver for arguments default null#21333
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
chalasr commentedJan 18, 2017 • 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.
There is no BC break nor deprecation here, please remove the corresponding labels, my bad sorry. |
50b4bc7 tod49390dCompare| foreach ($reflection->getParameters()as$param) { | ||
| $arguments[] =newArgumentMetadata($param->getName(),$this->getType($param),$this->isVariadic($param),$this->hasDefaultValue($param),$this->getDefaultValue($param),$param->allowsNull()); | ||
| $arguments[] =newArgumentMetadata($param->getName(),$this->getType($param),$this->isVariadic($param),$this->hasDefaultValue($param),$this->getDefaultValue($param),$this->isDefaultNull($param)); |
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.
ReflectionParameter::allowsNull() returns true for mandatory arguments which don't have any type hint i.e:function ($foo); // allowsNull(): true
Here we only want to know if the argument is default null, or has a typehint which allows null i.e.?type
d49390d to0473c18Comparelinaori commentedJan 18, 2017
How come it injects |
chalasr commentedJan 18, 2017 • 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.
Not sure but I believe the current implementation makes the Request resolver is just skipped so the default value wins. It can be reproduced with a fresh SE, changing the provided |
linaori commentedJan 18, 2017
But that would mean that this code is not hit properly:https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestValueResolver.php#L30-L38 Can you confirm this? Because this code is responsible for setting the request if it's supported and should work with the original setup (in theory). |
chalasr commentedJan 18, 2017 • 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.
@iltar I can confirm this since using But right now I'm not able to say what exactly is wrong with the current implem, the patch made here avoids the only doubts I have about the origin of the issue (one being |
0473c18 to46758c7Comparelinaori commentedJan 18, 2017
I'll try to reproduce it tomorrow. Maybe it's a sequence issue, because in theory this is only not called when something else already supports it and the |
46758c7 to86931d5Comparechalasr commentedJan 18, 2017 • 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.
Right! I looked deeper into and fact is that the RequestAttributeValueResolver is the culprit. |
linaori commentedJan 18, 2017 • 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.
@chalasr is there a specific reason that this line is returning true?https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php#L30 Perhaps the |
chalasr commentedJan 18, 2017 • 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.
Did not considered that :/ then the current fix is not good, it just gives a lower priority to the request attribute resolver so it is called after the request/user resolver.
Right again! A Not sure what's the proper way to fix this :/ Any idea@iltar? |
linaori commentedJan 18, 2017
I think we have to check why the attributes are created but empty, perhaps this is done for the parameter converters? An additional check could be to check if it |
chalasr commentedJan 18, 2017 • 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.
Not sure but there're good chances. Note that these attributes stay null at the end (from the controller itself) since I do not have any param converter explicitly configured
Could you please develop?
If you mean adding an additional check inside |
linaori commentedJan 18, 2017 • 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 edit: Not PC but attribute resolver should be called first |
86931d5 to426fafcComparechalasr commentedJan 18, 2017 • 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 updated this for reverting the previous changes and only adding the additional |
| $argumentName =$argument->getName(); | ||
| return$request->attributes->has($argumentName) &&null !==$request->attributes->get($argumentName); |
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.
Hmm I'm curious what happens if you have this:
$request->attributes->set('required', null);public function fooAction(string $required);edit: probably already broken/proper error in an old version?
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.
Using:
/** * @Route("/", name="homepage", defaults={"required": null}) */publicfunctionindexAction(string$required){}
Controller "AppBundle\Controller\DefaultController::indexAction()" requires that you provide a value for the "$required" argument [...]
Changing the signature toindexAction(string $required = null); orindexAction(?string $required); works of course.
Same behavior on 3.0, run into the same exception if the attribute is null.
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.
But this will now break the case where an attribute was set tonull deliberately. Isn't that a BC break?
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.
Indeed, it is...
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.
With this signature it would fail already, you just simply can't set it tonull anymore and it will trigger the resolver.
// call this with null, it will still trigger the resolverpublicfunction fooAction(UserInterface$user =null);
But I'm still curious as of why the request values are null in the attribute bag.
@xabbuh regarding the above example, that would fail already. Also I don't think that values not mapped in the route should be affecting the parameter resolvers:
/{required}with(string $required)= allowed to be set to null but will throw an error as its required/with(string $required)!= allowed to set to null, as it was not added in the route definition
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.
@iltar it happens only when the argument has a default, I'll look if avoiding this breaks something but I think you're right. If we can remove this magic then the resolver stays as it is and continue to work as expected in case the attribute is set explicitly
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.
If you ask me, routing information should not be affected by arguments in the method that are not mapped in the route, but that's exactly what happens right now 😢
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.
@iltar No, I mean a parameter without a type hint and without a default value.
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.
@xabbuh it could even break for ones that are type-hinted as objects with null as default value I think, which is what we are trying to fix. The current approach is definitely not the good one.
routing information should not be affected by arguments in the method that are not mapped in the route
I agree, but I don't know if it is expected somewhere internally (if someone has an hint?), nor where it happens
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.
@xabbuh I agree on that point. If the compiled route would be without the default value, everything will work as expected
chalasr commentedJan 19, 2017
@iltar My bad, I forgot to revert it. The diff is clean now |
c9f527f toe31ad5aComparelinaori commentedJan 19, 2017
Nice! 👍 So just for the confirmation, this behavior is only present with annotations? |
chalasr commentedJan 19, 2017
Yes, it is only present for annotations, which make this bug exists only when using them. |
linaori 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.
Seems like a double fix to me
e31ad5a to2c808caComparefabpot commentedJan 19, 2017 • 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.
chalasr commentedJan 19, 2017 • 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.
@fabpot I found it and was about to add a comment for clarifying this patch after discussed it with@iltar and@xabbuh on slack. The code removed here seems unnecessary, arguments with default values properly keep their default value even after removing it, same on 3.0. @lyrixx Could you please confirm that this code is no more needed and that removing it in 2.7 would not break anything? The bug fixed here exists on 2.7 as well, before that argument value resolvers were introduced. |
fabpot commentedJan 19, 2017
If the tests added back then by@lyrixx still work after the removal, I would say that this is safe to do on 2.7 instead of 3.1. Any drawbacks? |
2c808ca tof014cb6Comparef014cb6 tod3fa8a1Comparechalasr commentedJan 19, 2017
Changed the target to 2.7. Tests seem green, let's see the build. |
lyrixx commentedJan 19, 2017
Actually I don't know. The best way to know it is to test in a real project I guess. |
chalasr commentedJan 19, 2017
Ok thanks, tried out on 2.7 and it works as expected (for the record:screenshot on a fresh 2.7). |
fabpot commentedJan 19, 2017
Thank you@chalasr. |
…lt null (chalasr)This PR was merged into the 2.7 branch.Discussion----------[HttpKernel] Fix ArgumentValueResolver for arguments default null| Q | A| ------------- | ---| Branch? | 2.7| Bug fix? | yes| New feature? | no| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | n/a| License | MIT| Doc PR | n/aIf an argument has `null` as default value __and annotations are used for routing__, then it is not resolved by the ArgumentResolver e.g:```phppublic function showAction(Request $request) { dump($request); // Request object}public function showAction(?Request $request) { dump($request); // Request object}public function showAction(Request $request = null) { dump($request); // null}```To me, the last example should have been a Request object too.Note that it is the same behavior when using `UserInterface` or whatever, I ran into this issue while trying to dump a user for a route accepting both anonymous and authenticated requests, the argument was always null while `$this->getUser()` returned the expected value. According tohttp://symfony.com/blog/new-in-symfony-3-2-user-value-resolver-for-controllers it should have worked through the argument.I propose to make it works as a bugfix.Any suggestion for improving the patch will be really welcomed. ping@iltarCommits-------d3fa8a1 Avoid setting request attributes from signature arguments in AnnotationClassLoader… attributes handling (chalasr)This PR was merged into the 2.7 branch.Discussion----------[Routing] Fix BC break in AnnotationClassLoader defaults attributes handling| Q | A| ------------- | ---| Branch? | 2.7| Bug fix? | no| New feature? | no| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets |77289b9#commitcomment-20572462| License | MIT| Doc PR | n/aThis fixes a BC break introduced in#21333. Instead of removing the automatic request attributes creation, we keep it but only for attributes that are mandatory (i.e. present in the route path).Thanks to@iltar for the idea.Commits-------1d298f0 [Routing] Fix BC break in AnnotationClassLoader defaults attributes handling
Uh oh!
There was an error while loading.Please reload this page.
If an argument has
nullas default valueand annotations are used for routing, then it is not resolved by the ArgumentResolver e.g:To me, the last example should have been a Request object too.
Note that it is the same behavior when using
UserInterfaceor whatever, I ran into this issue while trying to dump a user for a route accepting both anonymous and authenticated requests, the argument was always null while$this->getUser()returned the expected value. According tohttp://symfony.com/blog/new-in-symfony-3-2-user-value-resolver-for-controllers it should have worked through the argument.I propose to make it works as a bugfix.
Any suggestion for improving the patch will be really welcomed. ping@iltar