Problem/Motivation
Upcasting of route named Views parameters does not work. For instance, I'm expecting that a %user Views argument, which is set to validate as a valid user entity, will be upcasted to a user entity object. Running the following code should pass:
$account = \Drupal::routeMatch()->getParameter('user');
assert($account instanceof \Drupal\user\UserInterface);
Instead, the route matcher is still returning the raw argument as user ID.
Proposed resolution
Allow named parameters upcating to entities. Use the argument validation plugin to determine if a named parameter can be upcasted to its entity object.
Remaining tasks
None.
User interface changes
None.
API changes
Named Views arguments, validating as entities, are now upcasted as entity objects.
Data model changes
None.
Release notes snippet
If a named Views argument is validated as an entity then it will upcast as entity object.
| Comment | File | Size | Author |
|---|---|---|---|
| #75 | 2528166-75.patch | 8.8 KB | johan.s |
| #66 | 2528166-65.test-only.patch | 5.54 KB | claudiu.cristea |
Issue fork drupal-2528166
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #1
webflo commentedComment #3
dawehneryeah that is not really enough, I mean, this will try to upcast things which aren't necessarily entities.
Comment #6
webflo commentedI think we can use the argument validation plugin to find the proper entity type.
Comment #7
webflo commentedComment #8
dawehnerAs written in IRC I'm wondering whether it would be a good idea to have some flag, hidden from the UI maybe even, to enable that kind of behaviour.
Comment #13
branana commentedModified the patch from #6 so that it would apply to 8.5.
Comment #15
hanoiiThis helped using %user as a named argument and a contextual filter with "User ID from route context".
I am not sure why tests are failing, seems unrelated. Might try to look.
I would ask though, why %user didn't work with this patch. In regular routes on yaml you only need to provide a type hint in case you don't use one of the known named parameters. And as such, I would have expected that %user worked regardless.
Comment #16
hanoiiComment #17
hanoiiTaxonomy edit page is broken, gives fatal error. I guess that's why tests were failing.
Comment #18
hanoiiNot setting an empty parameters when there's none helps with the fatal issue, likely because taxonomy/term/% is a view.
Comment #22
jonathan_hunt commented@hanoii The patch in #18 applies for me on 8.8.5, thanks.
Comment #23
dwwInteresting issue / patch.
For this to be RTBC, it'll need test coverage for changes to this class.
!empty() instead?
s/==/===/
Thanks,
-Derek
Comment #24
dpiExperiences and risks for this issue are similar to #2730631: Upcast node and node_revision parameters of node revision routes
Comment #25
pavnish commented@dww i am working on it.
Comment #26
pavnish commentedI am unable to apply the patch #18 on 9.1.x need to re-roll for 9.1.x
Comment #27
pavnish commented@dww I have created a new patch for this i was unable to apply this patch on 9.1 and 9.0
For #23
#23.1: The test case already exist and run successfully
PHPUnit 8.5.4 by Sebastian Bergmann and contributors.
Testing Drupal\Tests\views\Unit\Plugin\display\PathPluginBaseTest
.............. 14 / 14 (100%)
Time: 309 ms, Memory: 12.00 MB
OK (14 tests, 94 assertions)
#23.2: Changes has been done
#23.3: Changes has been done
Please review
Comment #28
dwwThanks for the updates, @pavnish!
1. Please provide an interdiff with a new patch to make it easier to see what you changed.
2. Thanks for finding Drupal\Tests\views\Unit\Plugin\display\PathPluginBaseTest -- however, that class has no coverage of this bug report, or we wouldn't have the bug in the first place. ;) The point is, we need to expand that test to cover the behavioral changes introduced with this patch. That's why I added the 'Needs tests' tag -- we need to test *this* bug, not just have any test coverage at all of the class where the bug fix is happening.
3. The best practice is to make such changes to the test, and upload a patch that only includes the changes to the test, without the underlying bug fix. You can call this patch something like "2528166-{comment_number}.test-only.patch". Upload that first, then upload the full patch with both the test changes and the fix. The test-only should fail, and it should fail in a way that makes sense to reveal the bug. Then the full patch should pass all tests (old and new/changed). That way, the core committers can review the test-only to see what it takes to trigger the bug, verify that the test is legitimate, and then see that the new test coverage passes once the fix is applied. This helps verify the bug fix is correct, and ensures we won't re-break the bug with future changes to core.
Thanks!
-Derek
Comment #29
dwwp.s. For extra credit (more quickly see the failed test results, save pointless bot cycles, save the DA $$), your test-only patch can include changes to core/drupalci.yml to tell the bot to only run the new/changed test(s). For a recent example, see https://www.drupal.org/files/issues/2020-05-17/3136668-27.orphaned-and-p... from #3136668-27: Invalid system.schema key_value entry causes fatal on updating to 8.8.5
Enjoy,
-Derek
Comment #30
dwwp.p.s. Upon closer read, that's maybe not the most clear example, since it included *some* of the proposed fix. ;) This is a cleaner example:
#2830326-32: Broken link to 'Put your site into maintenance mode' on update.php results in WSOD
https://www.drupal.org/files/issues/2020-05-15/2830326-32.8_8_x.test-onl...
Comment #31
pavnish commentedComment #32
pavnish commented@dww
RE #28.1 interdiff added
RE ##28.2 Need help.
Comment #33
pavnish commentedNeed work on #28.2 #28.3
Comment #34
pavnish commentedComment #35
dww@pavnish: Thanks. The point of #23.2 is that empty() checks for existence and truth in 1 call. So you can replace all of:
with:
Re: #28.2: Yeah, to write good test coverage for this, you need to understand what "upcast named arguments" means, and what functionality it unlocks. ;) I'll freely admit it's not clear from reading the issue summary. It's basically the plumbing in core that gives you a loaded object in a route Controller callback based on the value of a specific part of a URL, if you specify the route with something like {node} or {user} or whatever. So, we need a test that sets up a view to use an argument that expects some kind of entity, and then make sure that the underlying functionality gets the right kind of entity object. Or something. ;) Honestly, I'm not totally sure myself what "bug" this is fixing, what functionality doesn't work, etc. I know how to make use of a named argument in a Controller callback, but I'm not sure how/why Views itself would care about that. I'd have to dig a lot deeper, and I don't have time for that anytime soon. Hopefully someone else who cares about this can better articulate what functionality is broken as a result of this omission. A summary update would help a lot, so tagging for that, too.
Thanks/sorry,
-Derek
Comment #36
pavnish commentedComment #37
pavnish commentedComment #38
nitesh624Comment #39
nitesh624Comment #40
nitesh624Comment #41
nitesh624done changes suggested in #35
replace all of:
if (isset($a['b']) and $a['b'] == TRUE)) {
with:
if (!empty($a['b'])) {
Comment #42
nitesh624Comment #43
nitesh624Comment #44
dwwThanks. We still need tests and an issue summary update.
Comment #45
jibranUnfortunately, this not a single instance where we have to fix this. #2847224: Add views argument_default for getting Entity ID from URL and #2847233: Allow entity field value as argument_default also needs this functionality. It is not just that Views plugins need this, in contrib moderation_sidebar #3047936: Generic support for any entity type and metatags see
metatag_get_route_entityneed this as well.I think we need an issue to add a service for the entity system which will reliably provide the parameter from the route with the correct version and access. IOW, convert
metatag_get_route_entityto a core service which is the best solution for this problem IMO.Comment #46
claudiu.cristeaIt's not enough to inspect the argument validator plugin ID. There are cases when the plugin ID has a pattern different than
entity:{entity_type}, see\Drupal\user\Plugin\views\argument_validator\UserName. In that case we still can upcast the route parameter to an entity.@jibran, I'm not sure I got the relevance of #45 for this issue. Could you, please, elaborate?
Comment #47
claudiu.cristeaForgot to add the new param in create() static method.
Comment #49
claudiu.cristeaFixing broken existing tests. Still needs tests for the issue scope.
Comment #50
claudiu.cristeaNow, I think I like more the idea from #3034919-5: Explore making views routes add parameter options for named entity-type arguments. Avoids using the argument validator plugin ID but also avoids injecting the argument validator plugin manager. However, the test is coupled with the comment & content moderation modules.
Comment #54
claudiu.cristeaApplying the solution from #3034919-5: Explore making views routes add parameter options for named entity-type arguments. Adding credits. Still needs test.
Comment #55
claudiu.cristeaAdding tests. There's also a "test only" patch that acts here also as interdiff. Fixing IS. And i think this is a "Feature request".
Comment #56
claudiu.cristeaClosed #3034919: Explore making views routes add parameter options for named entity-type arguments as duplicate of this.
Comment #59
johan.s commentedFix tests
Comment #60
johan.s commentedComment #61
claudiu.cristea9.3.x is the development branch and this is a feature request.
Comment #62
claudiu.cristeaYep, needs a change note.
Comment #63
claudiu.cristeaLet's see a test only run.
Comment #65
claudiu.cristeaFix coding standards for "test only" patch. The main work has been moved to MR.
Comment #66
claudiu.cristeaComment #68
claudiu.cristeaComment #69
claudiu.cristeaAdded draft CR https://www.drupal.org/node/3244549
Comment #70
claudiu.cristeaFixing IS.
Comment #72
kingdutchI ran into this issue when trying to figure out why adding a
_entity_accessto a views route failed, it was because parameters were not upcast.Although the test and fix look good to me I'm hesitant to put this to RTBC. Primarily I'm worried that this may not be a backwards compatible change. Contrib modules may currently have named route parameters that expect to receive the entity ID rather than an upcast entity. Specifically anyone who wrote a views access handler and looks at the route parameter and then naïvely loads an entity based on it would find their code broken now that they receive an entity instead.
The group module currently manually alters the route to enable upcasting in the GroupPermission access handler. In Open Social we also have access checks that deal with views routes although I believe most of these are written to handle both the entity ID and loaded entity case. An example is access to a user event view.
Comment #74
johan.s commentedFix for version 9.3.x
Comment #75
johan.s commentedFix test pipeline
Comment #77
andypostComment #78
kevinquillen commentedI just ran into this myself.
https://drupal.stackexchange.com/questions/311028/view-with-a-path-of-ap...
It makes it hard to build Views with routes like this without upcasting to take advantage of other chained arguments. All that argument will receive is an ID.
Comment #82
claudiu.cristeaOpened a new MR !2979 against
10.1.x.Comment #83
claudiu.cristea@Kingdutch, I understand your point but we already did this for node revisions in #2730631: Upcast node and node_revision parameters of node revision routes. How to move on wit this?
Comment #84
kingdutchI think this is mostly up to core maintainers, going to move this to RTBC to get their visibility.
I've slightly changed my point of view since my last message in that I think currently a lot of code dealing with routes already needs to handle both cases to be resilient (I found this after trying to simplify some code after my last message and all of my assertions failing).
For example
/user/:idis currently upcast but/user/%user/custom-viewis not. So a block that wants to work on both pages will need to take both instances into account.With that in mind I think a move towards standardisation is much more likely to allow people to simplify their code base in the future than it is to break code that currently works sometimes, but is silently broken other times. So I for one would be very happy if we can get this in.
Comment #85
xjmTests for this issue are currently fataling:
https://www.drupal.org/pift-ci-job/2524962
Meanwhile, re:
Could we add a BC layer with a
__toString()method or the equivalent so that the caller would get the deprecation?Could we add a test for the current behavior with the entity ID as the parameter so that we can analyze the BC break?
I think it's a good point to explore, and we might need to handle it with a deprecation process for D11 otherwise.
Thank you @Kingdutch for your feedback on this point; I think it's important to understand the potential disruption of this issue.
Comment #87
candelas commentedAny news on this? Thanks
Comment #91
claudiu.cristeaFixed the tests but nothing has changed in substance, only adapted to new PHPCS, PHPStan, Drupal core changes. This was once RTBCed by @kingdutch, in #84
Comment #92
smustgrave commentedThanks for reviving this one!
Seems this feedback from @xjm is still needed.
Comment #94
alorencThe latest changes from the main branch have been merged.