 

Drupal・3 min read・Last update on May 10, 2023

# Porting access callbacks to Drupal 8

 

 

 

 ![Porting access callbacks to Drupal 8](/sites/default/files/remediation-media/64e5ddecd8b51449bff05add_blog-featured-image.webp) 

 



 

   Table of contents  - [What are access Callbacks?](#what-are-access-callbacks)
- [How do we create access Callbacks in Drupal 7](#how-do-we-create-access-callbacks-in-drupal-7)
- [How to port it to Drupal 8](#how-to-port-it-to-drupal-8)
- [Conclusion ](#conclusion)
 
  

 

Menu system in Drupal 8 has been changed completely. One of the biggest changes being removal of [hook\_menu()](https://www.drupal.org/list-changes/published?keywords_description=hook_menu&to_branch=&version=&created_op=%3E%3D&created%5Bvalue%5D=&created%5Bmin%5D=&created%5Bmax%5D=). Now the menu items, its page callbacks/access callbacks... are all defined in yml files(\*.routing.yml). There has been a shift in terminology as well from **path** -&gt; **routes**.

### What are access Callbacks?

**‍**  
Access callbacks are functions returning TRUE if the user has access rights to this menu item, and FALSE if not. Most of the access control can be achieved using Drupal permission system itself, but cases wherein we need to control the access to a menu link dynamically, access callbacks come into play.

e.g., Consider a case where in we need to allow the access to a menu only if it has a CSRF token attached with it.

### How do we create access Callbacks in Drupal 7

**‍**  
The example below will validate for CSRF token in the url attached as **?token=&lt;token\_value&gt;**. If the token is valid, the requesting user will be granted access else not.

 ```

d7_demo.module

/**
 * Implements hook_menu()
 */

function d7_demo_menu() {
  $items['d7-demo/access-check'] = array(
    'title' => t('Demo path for access check'),
    'page callback' => 'd7_demo_callback',
    'access callback' => d7_demo_csrf_token_check,
    'type' => MENU_LOCAL_TASK,
    );
  return $items;
}

/**
 * Access callback for demo path
 */
function d7_demo_csrf_token_check() {
  return drupal_valid_token($_GET['token']);
}

```

### How to port it to Drupal 8

- Convert menu into routes
- Create a service for custom access check
- Create access callback class defined in the service.

#### Covert menu into routes

The menu definition goes completely into **d8\_demo.routing.yml** as shown below.

 ```

d8_demo.routing.yml

d8_demo.d8_demo_access_check:

  path: 'd8-demo/access-check'

  defaults:

    _controller: '\Drupal\d8_demo\Controller\d8DemoController::d8DemoRenderContent'

  requirements:

    _access_check_token: 'TRUE'

```

#### What is \_access\_check\_token here?

We will take a look at it in the next step.

Details on the attributes used above:

***path*:** Drupal 8 has replaced the use of path over route names. So, wherever in a module a path was being used, it has been replaced with route names. The index for the items array in **hook\_menu()** moves under path attribute. Dynamic paths like **d8-demo/%** get replaced as **d8-demo/{arg}**. For entity paths like **node/%node**which covert the entity id into the object before passing it to the page callback, it becomes **node/{node}**.

***defaults*:** Page callbacks are converted into controllers now. These controllers could be of type *\_content, \_controller, \_form, \_entity\_view, \_entity\_list or \_entity\_form*. For more details on which type of controller should be used where check the documentation [here](https://www.drupal.org/node/2092643).

***requirements*:** Determines what conditions must be met in order to grant access to the route. For more details, check the documentation [here](https://www.drupal.org/node/2092643). We will be talking about**\_access** here.

***options (optional)***: Additional options on how the route should interact. For more details, check the documentation [here](https://www.drupal.org/node/2092643).

#### Create a service for custom access check

 ```

services:

  d8_demo.d8_demo_token:

    class: Drupal\d8_demo\Access\d8DemoCsrfCheck

    tags:

      - {name: access_check, applies_to: _access_check_token}

    arguments: ['@csrf_token']

```

‍**arguments:** injects other services that this custom service requires. In our case, since we need to validate CSRF token in the path, we need to use**csrf\_token** service.

For details on rest of these attributes mean here, read my previous blog post on [porting hook\_init()](/insights/porting-hook-init-to-drupal8).

**Adding access callback**  
The access callback class declared above in services.yml, needs to be implement[AccessInterface](https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Routing!Access!AccessInterface.php/interface/AccessInterface/8).

 ```

namespace Drupal\d8_demo\Access;

use Drupal\Core\Routing\Access\AccessInterface;

use Drupal\Core\Session\AccountInterface;

use Symfony\Component\Routing\Route;

use Symfony\Component\HttpFoundation\Request;

use Drupal\Core\Access\CsrfTokenGenerator;

/**

 * Determines access to routes based on login status of current user.

 */

class d8DemoCsrfCheck implements AccessInterface {

  /**

   * Constructs a d8DemoCsrfCheck object.

   *

   * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token

   *   The CSRF token generator.

   */

  function __construct(CsrfTokenGenerator $csrf_token) {

    $this->csrfToken = $csrf_token;

  }

  /**

   * {@inheritdoc}

   */

  public function access(Route $route, Request $request, AccountInterface $account) {

    return $this->csrfToken->validate($request->query->get('token')) ? AccessInterface::ALLOW : AccessInterface::DENY;

  }

}


```

[AccessInterface](https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Routing!Access!AccessInterface.php/interface/AccessInterface/8) requires us to define our logic into **access(Route $route, Request $request, AccountInterface $account)**. In our case since we need to validate the csrf\_token, we injected **csrf\_token** service into our custom access check. Hence, its available in the constructor for the class. For those who are not familiar with the term dependency injection, watch [this excellent video](https://www.youtube.com/watch?v=kocJ6pn9kEc) on how its done in Drupal8.

### Conclusion 

In this post, we touchbased on how to replace hook\_menu() with a \*.routing.yml file. We also learned on how to declare access callbacks in Drupal8 and then moving the code for access callback into access Controllers.

Next article, we’ll have a look at [How to port Blocks to Drupal 8](/insights/porting-blocks-to-drupal-8-plugins).

 



Written by

Piyuesh Kumar

Director of Technology

 

 

 

 

 

 

 ## We'd love to talk about your business objectives

 [ Contact Us  ](/contact)