2

I've created a view with a page display, filtering on a specific node type. The view's URL is /admin/poi.

Now I want to create a local task, linking to this view, for all nodes of type poi. The local task is showing, but it is visible when viewing/editing any node type, not just my POIs.

wt_poi.routing.yml

wt_poi.admin_list:
  path: '/admin/poi'
  requirements:
    _permission: 'access administration pages'
    _custom_access: '\Drupal\wt_poi\Controller\WtPoiController::isAllowedPoiAdminList'
  options:
    _admin_route: true

wt_poi.links.task.yml

wt_poi.list_overview:
  route_name: wt_poi.admin_list
  base_route: entity.node.canonical
  title: 'List all POIs'
  weight: -9999

src/Controller/WtPoiController.php

<?php

namespace Drupal\wt_poi\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Access\AccessResult;

/**
 * Controller for the POI node type tasks.
 *
 */
class WtPoiController extends ControllerBase {

  /**
   * Used to limit visibility of local task "List" to POI node type
   */
  public function isAllowedPoiAdminList() {
    $bundle = false;
    $node = \Drupal::routeMatch()->getParameter('node');
    if ($node instanceof \Drupal\node\NodeInterface) {
      $bundle = $node->bundle();
    }
    return AccessResult::forbiddenIf($bundle !== 'poi');
  }
}

Why is my _custom_access check not hiding the local task on other node types?

UPDATE: There seems to be an access check, but it is coming from "Access" in views module "Page settings" and my own access check is completly ignored. Best case would be my access check in addition to the view's access check, in a pinch I would prefer my own custom check replacing the view's access check.

1

I've found a workaround. When I add the view's URL as path in routing.yml, Drupal always used the view's access check. So instead of directly using the view's path, I wrote a simple redirect controller in order to get an alternative path.

wt_poi.routing.yml

wt_poi.admin_list:
  path: '/admin/poi-redirect'
  defaults:
    _controller: '\Drupal\wt_poi\Controller\WtPoiController::redirectToPoiAdminList'
  requirements:
    _permission: 'administer nodes'
    _custom_access: '\Drupal\wt_poi\Controller\WtPoiController::isAllowedPoiAdminList'
  options:
    _admin_route: true

wt_poi.links.task.yml remains unchanged

src/Controller/WtPoiController.php

<?php

namespace Drupal\wt_poi\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Access\AccessResult;

/**
 * Controller for the POI node type tasks.
 *
 */
class WtPoiController extends ControllerBase {

  /**
   * The only purpose of this controller is to provide an
   * alternative path to the POI view, so we can attach an
   * _custom_access check to it.
   */
  public function redirectToPoiAdminList() {
    // redirecting to a view: view.VIEW_MACHINE_NAME.DISPLAY_MACHINE_NAME
    return $this->redirect('view.poi.admin_list');
  }

  /**
   * Used to limit visibility of local Task "List" to POI node types
   */
  public function isAllowedPoiAdminList() {
    $bundle = false;
    $route = \Drupal::routeMatch();
    $routeName = $route->getRouteName();
    $node = $route->getParameter('node');
    if ($node instanceof \Drupal\node\NodeInterface) {
      $bundle = $node->bundle();
    }
    // the first part ensures the local task is shown on node pages,
    // the second part makes sure it also works during the redirection itself
    return AccessResult::allowedIf($bundle === 'poi' || $routeName === 'wt_poi.admin_list');
  }
}

Two remarks:

A) Remember that the user still has to pass the view's own permission check after the redirection (and this is a good thing, otherwise anybody knowing the alternative URL could bypass the access check).

B) The access check must use an allowedIf($positiveCondition). Do not use an forbiddenIf($negativeCondition), because it only returns forbidden or neutral, which always hides the local task.

My solution still feels a bit hacky, and I still would be open for a cleaner solution, but at least it does everything I need.

  • Instead of a redirect you could override the Views permission/route? – johndevman Feb 6 '18 at 10:36
  • I guess this would not work: Initially my access check was a simple AccessResult::allowedIf($bundle === 'poi'). This did work as a filter for the local task, but the redirecting itself stopped working (the link was there, but after clicking I got a "permission denied" because I no longer was in a POI-node route). So I always allowed the redirection route itself. I fear I would run into the same problem if I add this check to the view, but I can't use the "always allow self route" trick for this restricted administrative view. – Hudri Feb 6 '18 at 10:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.