Problem/Motivation
After the introduction of the route match class we can get rid of a lot of the magic attributes of the request.
Let's try to replace a lot of them
Proposed resolution
Replace usages of the request attributes with the request match.
We don't convert the calls to _system_path in this issue, there is a separate one for that already.
Left over calls to ->attributes->get(MAGIC_KEY) after this issue:
Targets
Occurrences of '->attributes->get(' in Project
core (37 usages found)
core/lib/Drupal/Core/Controller (3 usages found)
ControllerResolver.php (2 usages found)
(92: 32) if (!$controller = $request->attributes->get('_controller')) {
(141: 77) $raw_parameters = $request->attributes->has('_raw_variables') ? $request->attributes->get('_raw_variables') : [];
// Internal detail of the routing system
TitleResolver.php (1 usage found)
(60: 38) if (($raw_parameters = $request->attributes->get('_raw_variables'))) {
// Similar class as the controller resolver, just for titles
core/lib/Drupal/Core/EventSubscriber (6 usages found)
ContentControllerSubscriber.php (1 usage found)
(51: 18) if (!$request->attributes->get('_format')) {
// _format is a magic key of the request class, see Request::getRequestFormat() #2364011: [meta] External caches mix up response formats on URLs where content negotiation is in use might affect those
ContentFormControllerSubscriber.php (1 usage found)
(68: 25) if ($form = $request->attributes->get('_form')) {
// _format is the way how we deal with forms, also just a internal detail. Contrib does not have to care about it
DefaultExceptionHtmlSubscriber.php (2 usages found)
(100: 28) $system_path = $request->attributes->get('_system_path');
(112: 60) $sub_request->attributes->set('exception', $request->attributes->get('exception'));
// 'exception' is still there, you could consider it as detail, but its the "api" to get the parent exception, when you render a exception page
ExceptionLoggingSubscriber.php (2 usages found)
(50: 77) $this->logger->get('access denied')->warning(String::checkPlain($request->attributes->get('_system_path')));
(63: 78) $this->logger->get('page not found')->warning(String::checkPlain($request->attributes->get('_system_path')));
core/lib/Drupal/Core/Form (1 usage found)
FormSubmitter.php (1 usage found)
(142: 60) $url = $this->urlGenerator->generateFromPath($request->attributes->get('_system_path'), array(
core/lib/Drupal/Core/Routing (6 usages found)
RouteMatch.php (4 usages found)
(84: 17) if ($request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) {
(86: 26) if ($raw = $request->attributes->get('_raw_variables')) {
(90: 17) $request->attributes->get(RouteObjectInterface::ROUTE_NAME),
(91: 17) $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT),
// the route match itself, ... somewhere needs to happen the magic :)
RouteProvider.php (1 usage found)
(116: 29) $path = '/' . $request->attributes->get('_system_path');
UrlMatcher.php (1 usage found)
(34: 29) $path = '/' . $request->attributes->get('_system_path');
core/lib/Drupal/Core/Routing/Enhancer (1 usage found)
AuthenticationEnhancer.php (1 usage found)
(58: 40) $auth_provider_triggered = $request->attributes->get('_authentication_provider');
// Internal detail (might change, see the various related issues to that)
core/modules/config_translation/src (1 usage found)
ConfigNamesMapper.php (1 usage found)
(365: 73) $this->langcode = $route_match->getParameter('langcode') ?: $request->attributes->get('langcode');
// We have a todo for that, see #2295255: Convert ConfigMapperInterface::populateFromRequest() to use RouteMatch
core/modules/rest/src/Access (1 usage found)
CSRFAccessCheck.php (1 usage found)
(57: 23) $cookie = $request->attributes->get('_authentication_provider') == 'cookie';
// Same internal detail
core/modules/system/src/Plugin/Condition (1 usage found)
RequestPath.php (1 usage found)
(146: 21) $path = $request->attributes->get('_system_path');
core/modules/system/src/Tests/HttpKernel (2 usages found)
StackKernelIntegrationTest.php (2 usages found)
(48: 32) $this->assertEqual($request->attributes->get('_hello'), 'world');
(49: 32) $this->assertEqual($request->attributes->get('_previous_optional_argument'), 'test_argument');
// Just tests ... here.
core/modules/system/tests/modules/form_test/src (1 usage found)
FormTestControllerObject.php (1 usage found)
(42: 53) $form['request_attribute']['#markup'] = $request->attributes->get('request_attribute');
core/modules/system/tests/modules/httpkernel_test/src/HttpKernel (1 usage found)
TestMiddleware.php (1 usage found)
(51: 71) $request->attributes->set('_previous_optional_argument', $request->attributes->get('_optional_argument'));
core/modules/system/tests/modules/theme_test/src/EventSubscriber (2 usages found)
ThemeTestSubscriber.php (2 usages found)
(35: 29) $current_path = $request->attributes->get('_system_path');
(60: 29) $current_path = $request->attributes->get('_system_path');
core/modules/views/src/Plugin/views/argument_default (1 usage found)
Raw.php (1 usage found)
(96: 38) $path = $this->view->getRequest()->attributes->get('_system_path')
Usage in comments (1 usage found)
d8 (1 usage found)
core/lib/Drupal/Core/Controller (1 usage found)
ControllerResolverInterface.php (1 usage found)
(24: 49) * The controller attribute like in $request->attributes->get('_controller')
Remaining tasks
User interface changes
API changes
Original report by @effulgentsia
Follow-up to #2238217: Introduce a RouteMatch class.
Beta phase evaluation
| Issue category | Task: part of the critical #2124749: [meta] Stop using $request->attributes->get(MAGIC_KEY) as a public API |
|---|---|
| Issue priority | Critical, because its part of #2124749: [meta] Stop using $request->attributes->get(MAGIC_KEY) as a public API |
| Disruption | Just internal changes inside drupal itself |
| Comment | File | Size | Author |
|---|---|---|---|
| #51 | interdiff.txt | 1.75 KB | dawehner |
| #51 | 2281619-51.patch | 48.97 KB | dawehner |
Comments
Comment #1
catchComment #2
tim.plunkettGoing to look at this.
Comment #3
tim.plunkettI looked at breadcrumbs first, and realized it was a sizable change on its own (and an API change), so I split it out to #2292025: Convert BreadcrumbBuilderInterface applies() and build() to use RouteMatch.
Comment #4
tim.plunkettA bunch of remaining usages are because we don't have something like #1837388: Provide a ParamConverter than can upcast any entity..
I also opened a couple child issues.
Here is what I have so far.
Comment #6
tim.plunkett"yeah, you need all the semicolons"
- @drumm
Comment #8
tim.plunkettFixed some tests.
Comment #10
tim.plunkettComment #11
tim.plunkettRerolled and added more fixes.
Comment #13
tim.plunkettThere are a bunch of weird problems with config_translation, I might need to split those out to a new issue. Removing for now.
Comment #14
xjmDiscussed with @tim.plunkett and @effulgentsia. We'll add @todos in this patch for the remaining issues Tim hasn't solved yet here (c_t, quickedit, maybe others) and then should be in good shape for beta with this.
Comment #15
tim.plunkettWith these changes and the child issues, we cover everything except the explicit test coverage for $request->attributes.
Comment #16
effulgentsia commentedThis patch adds 9 calls to
RouteMatch::createFromRequest(). I think most, if not all, of those are wrong. I think in general, we want code to keep $request and $route_match as separate concepts, not assume that the latter is always derived from the former.Note that in HEAD, outside of tests and CurrentRouteMatch, we have only one place where "outside" code calls RouteMatch::createFromRequest() and that sole place is being removed in #2292217: ThemeNegotiator::determineActiveTheme() should not require a RouteMatch to be passed in.
Comment #17
dawehnerJust reviewed a bit. Classical example of doing too much in a match, honestly.
Can we somehow move the authentication after routing? AccessSubscriber::onKernelRequestAccessCheck happens after routing already
Can we just have two methods on the title resolver, one using the request + route?
Does that mean that the route match should be maybe part of the response event (maybe as part of the request *hides*)
Here we should inject the current route match as dependency, shouldn't we?
Comment #18
znerol commentedYes we should, but that's not too easy mostly because maintenance mode, see #2286971: Remove dependency of current_user on request and authentication manager and its child-issues.
Comment #19
dawehnerI will extract a couple of the usages here in #2330363: Enhance the controller resolver to get a route match class
Comment #20
dawehnerAnother related issue #2327387: Add the current route match to FormBase
Comment #21
dawehner#2238981: Change controllers to receive route parameters in their signature rather than via $request->attributes is another subissue
Comment #22
chx commentedSo according to #18 this issue should be set to postponed with a [pp-2] prefix?
Comment #23
tim.plunkettStill needs an issue summary. I'm not sure how much core has changed since #15, but there might be better ways to do this now.
Comment #24
dawehnerThis is kind of a similar to #2124749: [meta] Stop using $request->attributes->get(MAGIC_KEY) as a public API or at least a child.
Comment #25
dawehnerA hell lot of the instances got converted in the meantime.
This is a list of things which is not covered yet by this patch:
Comment #27
dawehnerAlright.
Comment #29
dawehnerLet's see, how many failures are left.
Comment #31
dawehnerFixed some of the tests.
Comment #33
dawehner.
Comment #35
dawehnerups, my fail.
Comment #36
amateescu commented@effulgentsia says in #16 that
RouteMatch::createFromRequest()is not a good pattern to use, so I wonder if we should inject the $route_match service instead?Same here.
This wouldn't be needed if we do 1., because we'd have the route match available from the parent class.
Maybe it would be easier if we leave all the Config*Mapper changes to #2295255: Convert ConfigMapperInterface::populateFromRequest() to use RouteMatch?
Same as 1. and 3.
Also related to the points above, the change notice for RouteMatch (https://www.drupal.org/node/2295317) lists
If you have a request available, you can just RouteMatch::createFromRequest($request).as the first way of using it. Based on #16, should we update the change notice to say that we need to useRouteMatch::createFromRequest($request)only when we have a $request and no way of injecting the route match service? I'd be really curious to see an example of that.Comment #37
dawehnerOkay, let's first figure out #2294157: Switch getOptions() and getRouteParameters() within LocalActionInterface and LocalTaskInterface to use RouteMatch as it deals with the fact whether / how to use the route match.
Comment #38
dawehnerUpdate this issue to be postponed
Comment #39
dawehnerAlright, a recent reroll.
Comment #40
dawehnerWorked on a proper issue summary
Comment #41
amateescu commentedI'm also removing this one in #2094499: Convert "Manage (form) display" forms to be the official entity edit forms for EntityView[Form]Display objects :)
Comment #42
dawehnerNice, so RTBC ? ;)
Comment #43
amateescu commentedI was more like hoping you would prefer to keep that hunk out of the patch, but apparently not :P
It looks like #36.4 is still not done. And here's another in-depth review:
Looks like we can remove this member now.
Pretty sure this is unused now :)
Something went wrong here...
Same here.
This one doesn't seem to be needed.
I realize this is test code but it tests exactly the thing we're trying to move away from. Is it worth keeping it?
Not used?
In all the other places you injected the current_route_match service, any reason for not doing it here too?
This plugin already extends ContainerFactoryPluginInterface, why not inject the service instead?
Unrelated I think.
Comment #44
dawehnerThank you for your review!!!
Alright, let's get rid of that hunk
Good catch!
Fair
In terms of test coverage it makes sense to convert to the more often used API.
Fixed that.
Well, the problem is that you need the route match for the passed in request. Expanded the stacked route match interface to allow that.
Yup
Given that the other issue doesn't have any proper patch yet,
Okay, then let's do that.
Comment #46
dawehnerOkay, breaking the login form is a bad idea :)
Comment #48
amateescu commentedYes, don't do that! :)
The last remaining test fail is quite interesting and I think it shows a flaw in the way (or timing) RequestMatch objects are created, because they don't have custom request attributes added by an event. Now I'm glad I brought up #43.6.
Comment #49
dawehnerWell, to be clear here, the route match just contains parameters which are part of the URL, not arbitrary request attributes.
In this test we do update arbitrary request attributes, so well let's keep it, the test ensure that you can inject the request object.
Comment #50
amateescu commentedRight, that explanation makes sense. I found a few more really small nitpicks which are not worth blocking a critical and can be fixed on commit if you don't want to roll a new patch.
Missing newline.
Same here.
Can be just {@inheritdoc}.
Comment #51
dawehnerThank you for the RTBC, but there is no reason to not fix these nitpicks.
Don't blame the patch, blame storm :)
Comment #52
alexpottTalking @dawehener in IRC he says the changes to this are a bug - do we need to add tests for this?
Should we not keep the comment?
Comment #53
dawehnerNote:
ControllerResolverTestis changed as part of this patch.It is not valid anymore ...
Comment #54
alexpottThanks @dawehner.
Committed 1e08b50 and pushed to 8.0.x. Thanks!
Comment #56
dawehnerThank you a ton alex!
Comment #57
amateescu commentedA bit sad to see that the fancy new "Credit & committing" stuff is still not used at its full potential (e.g. for reviewers)..
Comment #58
xjm@amateescu, one issue is that the form is pure JS (it looks like you can save a list of who to credit, but actually nothing is saved). I think there's an issue to improve this but I wasn't able to locate it.
Comment #60
cilefen commented#2830631: Remove code that tries to use _raw_variables for route argument resolution as it does not work is saying the changes to ControllerResolver in terms of not using the raw parameters constitutes a bug.