Problem/Motivation
Follow-up from #2124749: [meta] Stop using $request->attributes->get(MAGIC_KEY) as a public API.
The only request attribute that's used more than a couple of times is _system_path
- core/includes/path.inc (The actual file using (current_path() #2362227: Replace all instances of current_path())
- core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php (We need support for /d8/node kind of issues in destination redirect)
- core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php (We should log /d8/node instead of just "node")
core/lib/Drupal/Core/Form/FormSubmitter.php (Seems to be a usecase for a UrlGenerator::generateFromPath())fixed in #18- core/lib/Drupal/Core/Routing/RouteProvider.php (internal to the routing system)
- core/lib/Drupal/Core/Routing/UrlMatcher.php (internal to the routing system)
- core/modules/system/src/Plugin/Condition/RequestPath.php (possible to be replace maybe with using the path info + some replacing)
core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php (totally not needed, you can use the routing information)fixed in #20core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.phpfixed in #2288911: Use route name instead of system path in user maintenance mode subscriber
core/modules/views/src/Plugin/views/argument_default/Raw.php (same problem as FormSubmitter kind of)
#2362227: Replace all instances of current_path() gets rid of lots of 'hidden' usages, this issue should be able to take the fixes from that issue as a template.
Proposed resolution
For the cases where the concept of a path still has to exist we use a new service call CurrentPath, which stores similar to the
current route match, the path.
This issue though is able to get almost all instances beside of
a) The ones which are routing internal (path aliases) and code which explicitly checks for the internal path, not the request path.
Remaining tasks
User interface changes
API changes
Original report by @catch
Comment | File | Size | Author |
---|---|---|---|
#81 | interdiff.txt | 1.95 KB | dawehner |
#81 | 2372507-81.patch | 54.97 KB | dawehner |
#79 | interdiff.txt | 513 bytes | dawehner |
#79 | 2372507-79.patch | 54.69 KB | dawehner |
#77 | 2372507-77.patch | 54.69 KB | dawehner |
Comments
Comment #1
catchComment #2
catchComment #3
dawehnerNote: Most of _request_path is already using current_path() which we have a replacement for in case there is routing out.
Update the IS with some more description.
Comment #4
PinoloComment #5
mavimo CreditAttribution: mavimo commentedFirst patch, only for
core/lib/Drupal/Core/Form/FormSubmitter.php
Comment #6
dawehnerDump question ... isn't all you need $request->getPathInfo()? basically + http_build_query()? Then you could get rid of the currentRouteMatch dependency in total?
Comment #7
mavimo CreditAttribution: mavimo commented@dawehner yes and no.
We can just drop off the call to $request->attribute->get() with your suggested solution but the UrlGeneratorInterface definition:
require to use the
generateFromRoute
method that need to use the route (other methods are deprecated), so we can't use the$request->getPathInfo()
method to ensure that we don't need to rework it before drupal 8.0.0.Let me know if I'm in the right direction or not.
PS: attached patch remove some changes in tests that are not required.
Comment #8
mavimo CreditAttribution: mavimo commentedComment #9
tim.plunkettLet's see!
Comment #11
mavimo CreditAttribution: mavimo commentedPatch re-rolled
Comment #12
mavimo CreditAttribution: mavimo commentedComment #14
mavimo CreditAttribution: mavimo commentedComment #16
mavimo CreditAttribution: mavimo commentedComment #18
mavimo CreditAttribution: mavimo commentedFixed a test that require a redirect also when form submission is executed programmatically.
Comment #19
mavimo CreditAttribution: mavimo commentedIntroduced changes for:
core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php
Using the same approach to get current route and then compare it.
EDIT: sorry, my fault on interdiff extension :(
Comment #20
mavimo CreditAttribution: mavimo commentedComment #21
mavimo CreditAttribution: mavimo commentedComment #22
mavimo CreditAttribution: mavimo commented@dawehner individuate a "fix" for the test:
This disable redirect for forms submitted programmatically. This is the solution I suppose to be more clean because reduce the amount of code in the FormResolver and just set the test that is execute programmatically (in a form without route) to skip redirect step (there are no pages, so no redirect are possible).
A second solution can be to add a condition to skip redirect if there is not route defined for the current request:
this allow to skip redirection for forms without routing.
Opinions?
Comment #23
dawehnerDid you tried using
<current>
as route name?Comment #24
mavimo CreditAttribution: mavimo commented@dawehner do you mean in tests?
Comment #25
dawehnerWell, no, in actual used code.
For the particular example in FormBuilder I really wonder why we can't just use
$request->getUri()
given that its also an absolute URL, includinga query string.
Comment #26
dawehnerNeeds work to use
<current>
instead.Comment #27
dawehnerSo here is a way simpler approach.
Comment #29
mavimo CreditAttribution: mavimo commentedUsing the approach you indicate we don't re-calculate the URI after the form submission and the redirect is not correctly generate.
Eg, after submitting the LanguageConfiguration switching from a lang A to a lang B we need to re-define the page URI based on default language, language prefix & c. Using current URI can generate issue like: user change the language prefix from XX to YY, current URI use XX as path prefix, after the POST the form set the redirect to XX but the language don't exist (it's changed to YY) and user receive error. Some other issues are related to use the current URI without regenerate it (eg we don't remove the query string parameters, ..).
I think using the route based navigation & redirect (if possible) is better then use the current URI (that can be used as failback).
Comment #30
dawehnerGood point!
What so about using
<current>
like this?Comment #31
mavimo CreditAttribution: mavimo commented@dawehner sound really better :)
I'm working on this part in the last days:
and the only solution I found is a string manipulation from currentUri, but sound like a hack, and i don't like it :| I will update ASAP.
Comment #32
dawehnerYeah I think the only proper way is to have an actual API to get the system path.
Comment #33
jibranAny reason for this? Can we add a comment here?
Comment #34
mavimo CreditAttribution: mavimo commented@jibran see https://www.drupal.org/node/2372507#comment-9373435 I will add a comment on code.
Comment #35
RavindraSingh CreditAttribution: RavindraSingh commentedlast patch seems good to me. Moving it to RTBC
Comment #36
RavindraSingh CreditAttribution: RavindraSingh commentedComment #37
alexpott#33 should be addressed
Comment #38
mavimo CreditAttribution: mavimo commented@alexpott @RavindraSingh @jibran added comment required on #33
Comment #39
andyceo CreditAttribution: andyceo commentedComment #40
RavindraSingh CreditAttribution: RavindraSingh commented140 character long in a single line. needs breakpoint.
Also, Formatted some whitelines.
Comment #41
tim.plunkettOnly limit comments to 80 characters, never actual PHP code.
No need to touch these lines.
Comment #42
mavimo CreditAttribution: mavimo commented@tim.plunkett take a look to #38 I think it's ok.
Comment #43
dawehnerSo why did you skipped the usage of
<current>
again? All what your code is doing is the exact same thing, but with just more effort.Comment #44
dawehnerMerged in the interdiff in 38 with the approach in 30.
... I think at this point it seems tricky to replace more of the
_system_path
examples.Comment #45
dawehnerRemoved two more instances.
Comment #46
dawehnerSome work to get rid of some more examples
Comment #48
dawehnerThis could be it.
Comment #50
catchComment #53
BerdirThis is not so pretty, and possibly easy to do incorrectly and not notice if you are not in a subpath?
Maybe we could add the basepath by default, we have the $event available in there, with an argument to disable that?
Comment #54
dawehnerAdapted the code to accept both a relative URL and a path, if you think its worth.
Note: The bugfix was discussed with timplunkett yesterday
On top of it, I ensured that the unit test works and wrote some additional integration test
Comment #55
dawehnerHere is an idea I had in mind .. have an object similar to CurrentRouteMatch which stores the path. Yes, its discouraged to use it, but there are examples where you simply can't get around it. Not sure whether I like this approach yet though.
Comment #57
joelpittet@dawehner the idea you had in mind in #55 with CurrentPath seems very straight forward. Moves some of the internals out of the way and saves from having to know you need the current request object, or how to get it if you don't have it.
+1 to #55
Comment #58
dawehnerWell yeah, its straightforward, but whether its the way to go, I don't know. Anyone else has an oppinion? I guess I should just first try to push it to green.
Comment #59
znerol CreditAttribution: znerol commented#55 is what I've tried to propose in #2239009-15: Remove public direct usage of the '_system_path' request attribute, so definitely +1 from me.
Comment #60
dawehner@znerol
Great to give an ok from you! Just to be clear, I still think we should
Let's fix the failures quickly/
Comment #61
tim.plunkettI like this new approach too, it's much better than any other ideas we've brainstormed.
Grepping for _system_path, the only remaining occurrence is in a comment in RouteProviderTest, let's kill that too.
Maybe we should retitle the issue to clarify that we're completely removing _system_path?
Comment #62
dawehnerAlright
Fixed that instance and tried to update the IS
Comment #63
Wim LeersI like the overall direction. Mainly have some concerns about what "a path" now is exactly: Symfony-style (for full consistency), or "D7-style" (for legacy reasons)? IMHO that distinction either needs to go away (Symfony-style everywhere in this patch), or needs to be thoroughly explained and stressed on
CurrentPath
.s/url/Drupal root-relative URL/
Since AFAICT absolute URLs aren't supported (which makes sense).
Actually, even that is confusing. What this really is, is a path as defined in a
*.routing.yml
file, right? And optionally, a path as in a D7-style "path".The fact that I'm so confused by this means we should clarify this.
I think a comment for this is desirable.
"though" sounds wrong to me here. "unfortunately" fits better.
Static, not internal?
This stores a "D7-style path", not the path as defined in Symfony routes. Do we really want that?
I'd have expected this would have to be
'/'
?EDIT: ahh, this is a "D7-style path", because the corresponding test coverage does assert
'/'
. So… that makes this even more confusing, because we're actually working with a SymfonyRoute
object, which always works with a leading slash.s/skip redirect step/skip the redirect step/
Could use a comment saying that this verifies
<current>
is mapped to the frontpage when missing.Confusing sentence.
Extraneous newline added.
Comment #64
dawehner@wim
Thank you for the review!!
Well, I blame berdir in #53. If you ask me, this is not a public API here, so requiring a URL, instead of a path is a good thing, IMHO.
To be clear, I think path processing should at that point continue dealing with paths, because otherwise they would have to be renamed to URLProcessing for example which probably would be too much of an API change
without that much of a win.
Let's change it, but I don't care that much, to be honest.
Well, some users append a "/" at the moment, some don't and would have to shave it off.
Well, to be clear, it doesn't matter, because of the following code in the UrlGenerator:
Let's change it.
Improved.
Comment #65
Wim LeersSo this was a bug? Missing test coverage then :(
From IRC:
So then my biggest remaining concern is that
CurrentPath
should excessively strongly stress that it's NOT a Symfony route's path, but the processed path, and potentially a path alias, i.e. the .I wish I had a more precise suggestion than that, but I don't. Perhaps effulgentsia does?
Comment #66
dawehnerNo Its not
UrlGenerator($route('/')) == UrlGenerator($route(''));
... its a feature of the systemAt least having no slash here makes it clear that its not the incoming path, but whether and how to name it better I'm not sure.
Comment #67
dawehnerAdapt the issue title.
Comment #68
BerdirPff, now it's my fault :p
I was just thinking out loud on how to improve that. I'm not sure if making sub-requests is that much of an internal API?
Also, @WimLeers nicely shows why I suggested to make this easier, see #2368987-66: Move internal page caching to a module to avoid relying on config get on runtime, you can *not* just hardcode a leading / when working with a url string.
Comment #69
dawehnerWell, the API is the http kernel ... its just the
makeSubrequest
method which is a protected method ofDefaultExceptionHtmlSubscriber
.Comment #70
larowlan<3
current
This comment doesn't make sense
Other than that, looks RTBC to me - these are nits that could be fixed on commit.
Comment #71
dawehnerThank you for your quick review!
Mh, curren is not proper australian english?
Comment #72
larowlanThanks
Please refer to this instructional video regarding Australian English https://www.youtube.com/watch?v=DHQRZXM-4xI (probably should say NSFW, some may find it offensive)
Note: Australians love self deprecating humour.
Comment #73
tim.plunkettI was also reviewing this, I found no other nitpicks and already +1'd the direction in #61.
RTBC++
Comment #74
dawehnerIt would be great to get a +1 from crell, honestly.
Comment #75
webchickSummoning him.
Comment #76
Crell CreditAttribution: Crell commentedWe haven't gotten rid of drupal_get_destination() yet? Oh bother... Is there a follow-up to do so? If not, let's file it before this is committed.
This does change what the message will be, but I think it's a good change anyway. (Report the URI that the user requested, not the internal one.)
I would actually suggest we rename this class to something like CurrentPathStack or similar (and then the variables that reference it, too). As is, it suggest that it's a static computed value rather than a service. I spent 10 minutes typing up a long screed below about how passing that to the constructor of various other services makes the services brittle and dependent on the request it was instantiated with before I remembered it was a lookup table, not a value. It's still ugly and wrong because it's stateful but we can at least name it such that people are less likely to confuse it with a value object.
It may not be possible to resolve at this point, but this suggests that we are locking in the idea that sometimes paths have a leading /, sometimes not. If this is the last time we're futzing with _system_path (as it was the main place that non-/ paths came from), can we clean that up at the same time? Let's leave the / on. The patch is "only" 50 KB, and I suspect it's already touching all the places we'd need to modify anyway.
This is the kind of thing that we should clean up.
8 service dependencies is a strong code smell. So is the previous 7, though... Is there no way we can clean this up?
As noted above, these should be using /-based paths now.
Comment #77
dawehnerThank you for your review crell!
Sure, here is a follow up
#2426805: Modernize drupal_get_destination()
You know, its 50/50, but I agree, let's change it. Many people requested that already.
Do you want to know my opinion? The problem is not the breadcrumb builder but rather the problem that the routing system (symfony routing + our additions)
is not written in a good reusable way, but rather we just put things on top of an existing design. All those services are needed, when you basically want
to rerun routing. I won't change things for now, I hope this is okay.
You know, this is at least consistent with
RequestMatchStack
andAccountProxy
kinda. Its the same general problem.Comment #79
dawehnerHa, broken core is broken.
Comment #81
dawehnerLet's fix the remaining issues.
Comment #82
dawehnerCrell made his review, let's remove the assignment field again.
Comment #83
larowlanback again
Comment #84
larowlanSeeing similar issues in #2090115: Don't install a module when its default configuration has unmet dependencies for config.installer - do we have a strong opinion on something of a proxy service?
Then services needing all five could just rely on the proxy service?
Comment #85
dawehner@larowlan
Let's discuss that, because there are potentially more to use.
Comment #86
catchMade one change on commit. s/better/rather/.
Committed/pushed to 8.0.x, thanks!
Comment #88
BerdirI'm a bit confused by #76.4 (leading /) and the changes based on that. At least, we need a follow-up to fix the documentation in CurrentPathStack::getPath() because that still says it returns it without a leading /, and given that it is 50/50 when we need a leading / it, maybe there should be an easier way to get the path without leading /? IMHO, leading / was always a good way to differentiate between a url string (which is yet another thing, as commented above, it also includes the subfolder you're in) and the path.
#2430805: Fix CurrentPathStack::getPath() documentation that says it has no leading / (and make it easier to actually get that?)
Comment #90
xjm