Problem/Motivation

Steps to reproduce:

- setup a view with a path like node/%node/foo
- use a conditional argument
- add validation on node type to the conditioanl argument
- add a local task entry for the view via the views UI

Expected result: the local task doesn't show up for invalid node types
Actual result: it does

Proposed resolution

Somehow translate the argument validation to access checking - we'd want to keep the behaviour of not loading the view though, and might not be possible to do this generically - i.e. we might have to create access checks 1-1 with validator plugins?

Remaining tasks

User interface changes

API changes

Data model changes

Issue fork drupal-2778345

Command icon 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

catch created an issue. See original summary.

dawehner’s picture

Yeah I think argument validators should be able to allow something similar to what \Drupal\views\Plugin\views\access\AccessPluginBase is doing.

larowlan’s picture

Yeah, I just debugged a similar issue on a project, we ended up going with a route subscriber to add additional access checks. This would be a great addition.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

sukanya.ramakrishnan’s picture

This would be a very important addition for us too. Looking fwd to this !

tetranz’s picture

Assigned: Unassigned » tetranz

I'm taking a stab at this.

tetranz’s picture

Status: Active » Needs review
StatusFileSize
new5.49 KB

I think this is close to what we need. Unless I'm missing something, a generic solution fell into place quite nicely once I figured out how.

A few notes and things that might require some discussion or confirmation.
I made it only apply when the fail validation behavior is set to "page not found" or "access denied". If someone really wants to display one of the others, i.e., all results a "no results" message or a summary then the menu should probably still appear.

This applies to page and feed displays because Drupal\views\Plugin\views\display\PathPluginBase::getRoute was a good place to put this. If feeds is considered inappropriate then I can move some code to Drupal\views\Plugin\views\display\Page although I'd have to refactor a little to make $argument_map available.

I'm still a little uncertain about what AccessResult is the correct one in the various situations although I think I have it correct mostly by studying what happens on a view with an access restriction. AccessResult::neutral() makes the menu link disappear.

I think AccessResult::allowed() is the appropriate result when we're trying to access the view itself although intuitively AccessResult::neutral() would seem more likely. AccessResult::allowed() appears to work correctly. If the view has a failed access restriction and a validation, it still fails with access denied as intended despite my code returning a AccessResult::allowed();

I will look into writing some tests. I think I need to import a new view configuration to test this or at least add a display to one of the existing test views.

Status: Needs review » Needs work

The last submitted patch, 8: views-args-access-2778345-8.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tetranz’s picture

StatusFileSize
new5.53 KB
new876 bytes
tetranz’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 10: views-args-access-2778345-10.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tetranz’s picture

Status: Needs work » Needs review
StatusFileSize
new5.68 KB
new1.07 KB
tetranz’s picture

StatusFileSize
new13.47 KB
new7.79 KB

Added a test.

tetranz’s picture

Assigned: tetranz » Unassigned

I was feeling my way a little with the test. I'm not sure if it's in the most appropriate place or should / could do something different.

pritishkumar’s picture

StatusFileSize
new13.44 KB

Fixed Some Coding Standards which was in the previous patch.

Interdiff was not created due to an error.

tetranz’s picture

StatusFileSize
new1.13 KB

Thanks. Here's an interdiff.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tetranz’s picture

StatusFileSize
new7.79 KB

Trying to bring this back to life.

Patch #16 fails to apply to 8.7.x.

I'm starting again with the patches since I didn't do it in the right order a year ago.

This one is the test only which should fail.

tetranz’s picture

StatusFileSize
new7.81 KB
new669 bytes

Submitting this again with the updated traits.

The last submitted patch, 21: views-args-access-2778345-21.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 22: views-args-access-2778345-22.patch, failed testing. View results

tetranz’s picture

Status: Needs work » Needs review
StatusFileSize
new13.51 KB
new5.7 KB

This should pass.

catch’s picture

This looks in the right direction, couple of nits, one thing looks a bit odd, notes below:

  1. +++ b/core/modules/views/src/Access/ArgumentValidatorAccessCheck.php
    @@ -0,0 +1,83 @@
    +/**
    + * Access check views with page or feed display and argument validation.
    + * This is primarily used to avoid displaying menu links for views that will
    + * fail validation.
    + */
    

    This could do with a new line.

  2. +++ b/core/modules/views/src/Access/ArgumentValidatorAccessCheck.php
    @@ -0,0 +1,83 @@
    +  private $views_plugin_manager;
    

    We have a general guideline against using private properties (i.e. allows people to subclass if they really want to) so both of these should be protected. Should also be camelCase.

  3. +++ b/core/modules/views/src/Access/ArgumentValidatorAccessCheck.php
    @@ -0,0 +1,83 @@
    +      $parameter_value = $route_match->getRawParameter($argument['parameter_name']);
    +      $allowed = $allowed && $plugin->validateArgument($parameter_value);
    +      if (!$allowed) {
    +        break;
    +      }
    

    Since we never get to the next step of the foreach, couldn't this be
    <?php
    if (!$plugin->validateArgument($parameter_value)) {
    return AccessResult::neutral();
    }

    Then just return AccessResult::allowed() at the end of the method.

  4. +++ b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
    @@ -198,6 +197,39 @@ protected function getRoute($view_id, $display_id) {
    +      $route->addRequirements([
    +        '_argument_validator_access' => serialize([
    +          'arguments' => $validate_arguments,
    +        ]),
    

    Couldn't this just be an array without the manual serialize/unserialize?

tetranz’s picture

StatusFileSize
new13.41 KB
new3.85 KB

Thanks @catch. I've addressed all those except the last one.

The route requirement can only be a string so we need the serialization. It looks like Symfony really intends it to be a regex (See Symfony\Component\Routing\Route::sanitizeRequirement) so I am kind of hijacking it for a different reason. But there are other places where it's pipe delimited "serialized" such as in Drupal\rest\Plugin\views\display\collectRoutes::RestExport. I'm not sure if there is an alternative. This is deeper than one dimension so a pipe delimited won't work.

I have changed to using ->setRequirement rather than ->addRequirements which eliminates one array.

tetranz’s picture

StatusFileSize
new13.41 KB
new619 bytes

Removed an unnecessary comma.

twod’s picture

Priority: Normal » Major
Issue tags: +Barcelona 2015, +Triaged core major
jeffam’s picture

Status: Needs review » Needs work

I just tested this today and it worked well. However, I can consistently get a PHP notice under certain circumstances, and I'm pretty sure it's related to the patch in #28.

I wish I had more time to dig a little deeper, but here's what I have so far.

I'm using two views with argument validation criteria. Both are listing custom entities.

The first one has a path of `/node/%node/slots`, uses a menu tab, and uses the 'Content' validator with a single content type selected. With the patch, everything works as expected. The tab appears on the nodes of the content type chosen in the validator and not on other node types.

The other view has a path of `/user/%user/reservations`, also uses a menu tab, and uses the 'User ID' validator. With the patch, the tab still appears on user pages (e.g. `/user/2`), but on every visit to the account page (`/user/%user`) after a cache rebuild, I see the following PHP notice:

Notice: Undefined index: bundles in Drupal\views\Plugin\views\argument_validator\Entity->validateEntity() (line 202 of core/modules/views/src/Plugin/views/argument_validator/Entity.php).
Drupal\views\Plugin\views\argument_validator\Entity->validateEntity(Object) (Line: 96)
Drupal\user\Plugin\views\argument_validator\User->validateEntity(Object) (Line: 180)
Drupal\views\Plugin\views\argument_validator\Entity->validateArgument('1') (Line: 73)
Drupal\views\Access\ArgumentValidatorAccessCheck->access(Object, Object)
call_user_func_array(Array, Array) (Line: 159)
Drupal\Core\Access\AccessManager->performCheck('access_check.views.argument_validator', Object) (Line: 135)
Drupal\Core\Access\AccessManager->check(Object, Object, NULL, 1) (Line: 92)
Drupal\Core\Access\AccessManager->checkNamedRoute('view.reservations_for_user.page_1', Array, Object, 1) (Line: 327)
Drupal\Core\Menu\LocalTaskManager->getTasksBuild('entity.user.canonical', Object) (Line: 358)
Drupal\Core\Menu\LocalTaskManager->getLocalTasks('entity.user.canonical', 0) (Line: 94)
Drupal\Core\Menu\Plugin\Block\LocalTasksBlock->build() (Line: 203)
Drupal\block\BlockViewBuilder::preRender(Array)
call_user_func('Drupal\block\BlockViewBuilder::preRender', Array) (Line: 378)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 450)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195)
Drupal\Core\Render\Renderer->render(Array) (Line: 490)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 83)
__TwigTemplate_491d354868c23a7cdc36790829dd9700797f10bbfee01afc733f74972d1a5ac2->doDisplay(Array, Array) (Line: 432)
Twig_Template->displayWithErrorHandling(Array, Array) (Line: 403)
Twig_Template->display(Array) (Line: 411)
Twig_Template->render(Array) (Line: 64)
twig_render_template('core/modules/system/templates/page.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('page', Array) (Line: 437)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195)
Drupal\Core\Render\Renderer->render(Array) (Line: 490)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 84)
__TwigTemplate_4a0387b265d067bab2d2de06a8ead777749d03cb5cf7ba23df40bc8d00a80437->doDisplay(Array, Array) (Line: 432)
Twig_Template->displayWithErrorHandling(Array, Array) (Line: 403)
Twig_Template->display(Array) (Line: 411)
Twig_Template->render(Array) (Line: 64)
twig_render_template('core/modules/system/templates/html.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('html', Array) (Line: 437)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195)
Drupal\Core\Render\Renderer->render(Array) (Line: 147)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 148)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.view', Object) (Line: 156)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 666)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

I don't see the error when I revert the patch, which is why I'm guessing it's related. It's interesting that the error is about an undefined index `bundles` and that user entities don't have bundles.

I'll dig around some more, but I'm hoping that this info will help.

tetranz’s picture

Thanks for testing. I've tried to reproduce the error but have not been able to.

Can you describe your second view in detail please.

tetranz’s picture

@jeffam I took another look trying to reproduce your error but was unsuccessful.

I created a custom entity with Drupal Console I think similar to your Reservation. It just has a name and a user reference. I created a view at /user/%user/foo to show the reservations for that user. Then I used the contextual filter validator to validate by role. "Restrict user based on role" is the only validator available when you validate by User ID. The tab appears as expected at /user/2 but not at /user/1.

It that similar to what you were doing?

It seems like somewhere in your view you're validating something by bundle, but what? Does Reservation have bundles? Mine doesn't. It would be nice to see the yml for the view or just a description of it.

I'm at a dead end with this now without more details on how to reproduce the error.

jeffam’s picture

StatusFileSize
new13.37 KB

@tetranz - Thanks for looking at this, and sorry for my delayed response. Attached is the view I'm using, although it has some extra stuff that probably isn't relevant. You'll be able to see the `reservee_uid` argument and its validation settings, though.

tetranz’s picture

Thanks @jeffam, I can reproduce the error. I should have a fix in few days.

tetranz’s picture

Status: Needs work » Needs review
StatusFileSize
new14 KB
new2.29 KB

Unfortunately, this is not quite as simple as I thought it was.

This patch fixes the problem but it is probably not the final solution.

The problem was caused by me not initializing the plugin properly. I was just setting the options which means that it wasn't getting the defaults which include that 'bundles' value.

The proper way to initialize the plugin is to call its ->init() method. That works fine except that it needs the view executable and the display handler. We really don't want to load the view as @catch said in the proposed solution.

I'm not sure what to do. I think we really only need the default options for the plugin but any way of getting at them directly is protected.

Anyway, I'm going to flip this to needs review. Perhaps someone will have a suggestion.

mirom’s picture

Status: Needs review » Needs work

This patch prevents showing taxonomy terms in menu. Steps to reproduce:
1. apply patch
2. create taxonomy term
3. add link to taxonomy term to menu
4. see nothing.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dflitner’s picture

RE: #36. Because this patch triggers on views with 404 or 403 results, a workaround is to change the contextual filter on your taxonomy term view to display contents of "no results found" or any other setting besides "page not found" or "access denied".

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

lunk rat’s picture

Views menu tabs are a key strategy in producing usable UI/UX workflows for complex Drupal architectures with lots of entities referencing each other. This regression from D7 is detrimental to that strategy because the views tabs appear on content types where they should not appear.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

kerasai’s picture

StatusFileSize
new0 bytes

The patch in #35 stops applying w/9.3.

Attached is a re-roll that applies for 9.4.x and 9.3.x.

Note: No changes to functionality or a review, just a re-roll.

kerasai’s picture

StatusFileSize
new14.05 KB

Somehow uploaded an empty patch in #45.

Here's the proper version.

jonathanshaw’s picture

Great work @tetranz.

The problem described in #35 is tricky. Here's a possible solution:

1. Create an ArgumentValidatorPluginInterface that extends ViewsPluginInterface and contains a method initOptions($options = NULL).
2. Have ArgumentValidatorPluginBase implement that interface, with initOptions simply being a version of init that sets up the options without needing the view and display.
3. When checking access ignore validator plugins that do not implement ArgumentValidatorPluginInterface
4. In ArgumentValidatorPluginBase::construct trigger a deprecation warning if the plugin does not implement ArgumentValidatorPluginInterface

jonathanshaw’s picture

This is a tricky architectural issue that may have relevance beyond this issue; maintainer guidance would be helpful.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

jonasanne’s picture

Status: Needs work » Needs review
StatusFileSize
new14.05 KB

Reroll patch #46 for 10.2.x

smustgrave’s picture

Status: Needs review » Needs work

Also recommend converting to MRs as easier reviews.

Still needs sub-maintainer review but NW for the CC failures.

dww made their first commit to this issue’s fork.

dww’s picture

Status: Needs work » Needs review
Issue tags: +Bug Smash Initiative

I just ran into this bug on a new project. I was amazed this was broken. I dug deep into the views code, only to find:

// @todo How do we apply argument validation?

buried in core/modules/views/src/Plugin/views/display/PathPluginBase.php.

Searched the d.o queue and landed here. Thankfully, patch #52 applies cleanly both to 11.x HEAD and my 10.2.5 site. Converted to an MR. Fixed the phpcs and phpstan errors. I haven't addressed #35 / #47, but wanted to get this back into a reviewable state.

Let's smash this bug!

Thanks,
-Derek

dww’s picture

Hiding all attached files and starting to save credits.

dww’s picture

Status: Needs review » Needs work

Well, drat. There are legit test failures in both of these:

core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php
core/modules/taxonomy/tests/src/Functional/TermTest.php

I'm out of time for today, but I hope to get back to this soon. 😅 If anyone else wants to run with it in the meanwhile, please do. 🙏

Thanks,
-Derek

jonathanshaw’s picture

@dww you may be encountering #35 / #47

rachel_norfolk’s picture

Issue tags: -Barcelona 2015 +Barcelona2015

Just tidying tags

mikell’s picture

StatusFileSize
new3.23 KB

Reroll patch #52 for 11.2.2
Edit: My bad, uploaded wrong file. See comment below.

mikell’s picture

StatusFileSize
new14.07 KB

Something went wrong with previous comment.
This is the correct reroll patch #52 for 11.2.2

fskreuz made their first commit to this issue’s fork.

fskreuz’s picture

Status: Needs work » Needs review
jonathanshaw’s picture

Status: Needs review » Needs work

#63 seems to be rerolling #58, which is NR not NR.

cslevy’s picture

StatusFileSize
new14.01 KB

The MR doesn't apply anymore on D10.6. I created a patch which will apply on D10.6

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

mortona2k made their first commit to this issue’s fork.