While working on #2031473: Convert menu local actions to plugins so that we can generate dynamic titles and paths we realized that the attributes array contains just the upcasted value, but there are serveral use cases where we really need the original value. The most obvious one is generating a Drupal path for a route with a dynamic pattern like /node/{node}/edit
Just replace the value won't fly, so the new value has to be stored somewhere else. The idea is to use a property bag
stored in $request->attributes->get('_raw_variables')
In order to still allow nice injection into controllers/whatever else, the controller resolver (which is a class which puts arguments from the request and together with the information about the controller, figures out the needed values).
Follow-up
#2034857: What to do with raw request attributes vs. converted (upcast) attributes
Comment | File | Size | Author |
---|---|---|---|
#55 | 2031487-55.patch | 7.28 KB | pwolanin |
#55 | 2031487-48-55.increment.txt | 798 bytes | pwolanin |
#48 | 2031487-48.patch | 7.28 KB | pwolanin |
#48 | 2031487-47-48.increment.txt | 2.91 KB | pwolanin |
#47 | 2031487-47.patch | 7.23 KB | fubhy |
Comments
Comment #1
dawehnerComment #2
fubhy CreditAttribution: fubhy commentedI did the same on my typed data resolver sandbox as part of the ParamConverter refactoring/cleanup (including some other things). So yeah, we _really_ don't want to override our request attributes like we do now and instead put the upcast values somewhere else so we can still retrieve the original values.
+1
We can either commit that here (if green and after a good review) or together with the param converter refactoring.
Comment #4
dawehnerList of access checkers which deal with upcasted values:
Comment #5
fubhy CreditAttribution: fubhy commentedWe discussed this during the WSCCI meeting yesterday and agreed that it is necessary to solve this somehow. I am still wondering if it's better to keep a copy of the raw values somewhere and continue to do the upcasting by overriding in the actual attributes array or do what this patch does now (adding another ParameterBag to the attributes where we put the converted values).
Comment #7
fubhy CreditAttribution: fubhy commentedComment #8
dawehnerYou could also just use $map[$index] = $request->get('converted')->get($matches['placeholder'], $request->attributes->get($matches['placeholder']));
Comment #9
dawehnerUse proper unit tests.
Comment #10
fubhy CreditAttribution: fubhy commentedAdding a follow-up for discussing whether it might be better to instead store the raw values somewhere else and keep doing these overrides.
#2034857: What to do with raw request attributes vs. converted (upcast) attributes
Let's proceed with this issue though as it helps to unblock/cleanup other things that rely on UrlGenerator (local actions, tasks, etc).
Comment #12
dawehnerAs this blocks a proper local actions/local tasks api I consider this as major.
In general I also like the raw approach, whatever works, but to be honest we should just agree on one approach.
Comment #13
tim.plunkettComment #14
fubhy CreditAttribution: fubhy commentedJudging by the latest replies on the other issue I guess we now agreed on storing a copy of the raw values instead. I like that much better. I have got a patch for that on my office pc waiting to be uploaded. Will post it here in the morning.
Comment #15
fubhy CreditAttribution: fubhy commentedStoring a backup of the raw values seems much simpler indeed. What about something like this? I believe the ParamConverter is the right place to store the backup as it also knows which things were converted.
I made sure this patch touches as few files as possible and thus also reverted the architectural changes made to the ParamConverterManager previously in this issue. We are doing those in the DX issue anyways.
Comment #17
fubhy CreditAttribution: fubhy commentedComment #18
dawehnerSome more documentation what goes on and why we are doing it should be added.
Any reason why there is still is_object on there?
Comment #20
fubhy CreditAttribution: fubhy commentedThanks for the review.
Should be green now.
Comment #21
dawehnerThank you very much.
Comment #22
Crell CreditAttribution: Crell commentedAre you sure about that? Why wouldn't I want the object just because I have no type hint? It could be a highly variable object in some cases.
(You're free to push back and say that in that case you can bloody well upcast it yourself if you feel that's appropriate.)
Comment #23
Crell CreditAttribution: Crell commentedEh, never mind. :-) Crosspost.
Comment #24
fubhy CreditAttribution: fubhy commentedOh, we are still doing upcasting, even if there is no type hint. It's just that we do not pass the upcasted object in the argument if there is no typehint. You can still pull it from the request if you wanted to:
So yeah, I am pretty sure it's okay to do this. What are you going to do in your controller if you don't even know that it's a object of some sort? How are you going to interact with it? There is just a limited number of things you can do without knowing what object you are actually working with (if we are speaking about realistic, real-world use-cases).
Comment #25
alexpottThe issue summary says...
Also...
The messages here are incorrect. They should be saying what we expect to happen because when it fails, the statement fails to be true.
Comment #25.0
alexpottUpdated issue summary.
Comment #25.1
dawehnerblub
Comment #26
pwolanin CreditAttribution: pwolanin commentedfixing title
Comment #26.0
pwolanin CreditAttribution: pwolanin commentedblub
Comment #27
pwolanin CreditAttribution: pwolanin commentedIs _raw really the right key to use here?
Also, would it make sense to add the UID from the user object as the _raw 'account' value (the new global user object)?
Comment #28
dawehnerSo there are quite a lot of places which applied the opposite logic when switching to phpunit ...
Comment #29
pwolanin CreditAttribution: pwolanin commentedper later discussion - maybe not sensible to sick account in there globally - individual consumers can handle that.
Comment #30
fubhy CreditAttribution: fubhy commentedPeter suggested we should go with a colon instead. I have no strong preference. I just feel that our request attributes are getting quite messy quickly and we seem to dump unrelated stuff in there all the time. We really need to find a solution for that.
Also @see #2043781: Drupal::request()->attributes->get('account') may conflict with an account object loaded from the path ... Or think about HtmlFormController (form_state / form). Ugh
Let's find a convention. Or even better, find some other place for this stuff.
Comment #31
pwolanin CreditAttribution: pwolanin commentedMotivation for colon is that is something that should never appear in a variable taken from the URI http://tools.ietf.org/html/rfc6570
I don't think the logic is quite right here - we should keep the value in :raw even if it was not converted, otherwise we have to go hunting for it later.
Comment #32
pwolanin CreditAttribution: pwolanin commentedper discussion with fubhy in IRC - this keeps a copy of all the raw values that are names of variables in the route path pattern.
This should make it much simpler to supply all the needed parameters for the route e.g. for the URL generator.
Comment #33
jibranCan we use
_raw
instead of:raw
?Comment #34
pwolanin CreditAttribution: pwolanin commented@jibran - why? We should use something that can never be a path variable name.
Comment #36
pwolanin CreditAttribution: pwolanin commented#32: 2031487-32.patch queued for re-testing.
Comment #37
dawehnerAnother possible prefix "#" would be at least more common in Drupal world.
Comment #38
fubhy CreditAttribution: fubhy commentedWe should go back to _ actually now that I thought about it more. It gives us the possibility to get it passed as $_raw.
Comment #39
dawehnerWhat is the usecase for that? If someone really wants the raw values, it is fine to get it manually from the request object.
Comment #40
pwolanin CreditAttribution: pwolanin commented@dawhhner - the assertion is that some controller would want that instead of the whole request. I can see both sides of that argument - and I dont' really liek the symfony _ prefix habbit.
Comment #41
Crell CreditAttribution: Crell commentedNevertheless, _-prefixing for "Special" is the Symfony convention and the convention we're already using in a bunch of places. I am very -1 on introducing more special characters. We're not Perl. :-)
Comment #42
dawehnerI agree, let's not assume that the developer is stupid.
Comment #43
fubhy CreditAttribution: fubhy commentedAgreed.
Comment #44
Crell CreditAttribution: Crell commentedLet's get on with it then.
Comment #45
Dries CreditAttribution: Dries commentedPatch no longer applies after the parameter router patch. Needs a quick re-roll.
Comment #46
fubhy CreditAttribution: fubhy commentedComment #47
fubhy CreditAttribution: fubhy commentedRe-roll
Comment #48
pwolanin CreditAttribution: pwolanin commentedI think "_raw" is too vague. This converts it to "_raw_variables" since these are the raw values corresponding to the Route variables (i.e. path slugs like {node})
Comment #48.0
pwolanin CreditAttribution: pwolanin commentedelaborate use case
Comment #49
dawehnerUpdated the summary.
Comment #51
pwolanin CreditAttribution: pwolanin commented#48: 2031487-48.patch queued for re-testing.
Comment #53
pwolanin CreditAttribution: pwolanin commented#48: 2031487-48.patch queued for re-testing.
Comment #55
pwolanin CreditAttribution: pwolanin commentedhmm this was a real fail:
Looks like fubhy's last re-roll removed the $route variable by mistake. This puts it back.
Comment #56
jibranRTBC as per #49
Comment #57
catchNot 100% about raw variables, but seems better than _raw. Committed/pushed to 8.x
Will need a change notice.
Comment #58
dawehnerAdded one paragraph to the main route system change notice: https://drupal.org/node/1800686/revisions/view/2764405/2780643
Comment #59
dawehner.
Comment #60
larowlanChange notice is fine
Comment #61.0
(not verified) CreditAttribution: commentedblub