logo
Submitted by Mikhail Ismajlov on Wed, 09/25/2019 - 12:56

We can use the parameters in the URL for routes. They work just like contextual filters in Views. We can for example pass in the URL the ID of various entities, text strings or sequential ID separated by comma or pluses. In this lesson, we will pass the ID of the node and display the title and body of this node in the content.

Code examples can be viewed on github:
https://github.com/levmyshkin/drupalbook8

Let's add route to our drupalbook.routing.yml module file:

drupalbook.display_node:
  path: '/display-node/{node}'
  defaults:
    _controller: '\Drupal\drupalbook\Controller\DisplayNode::content'
    _title_callback: '\Drupal\drupalbook\Controller\DisplayNode::getTitle'
  requirements:
    _custom_access: '\Drupal\drupalbook\Controller\DisplayNode::access'
  options:
    parameters:
      node:
        type: entity:node

Here in path we pass in the second argument {node}, in url we will write the usual ID: /display-node/101, but a ready-made node object will come to our controller. To do this, we indicate in options the parameters what should be passed to these parameters and what will be the output

options:
    parameters:
      node: # the name of the argument, what is between {}, it can be node1, node2, if we pass two different arguments.
        type: entity: node # what will be the output, we can use the object of this entity inside the controller.

I also determined in which method we will display the header using the _title_callback parameter. And we will limit the output of articles to anonymous users, for this we use the _custom_access parameter in which we indicate in which method we will impose various restrictions.

Now when we figured out the description of the route, let's move on to writing a class for this route.

modules/custom/drupalbook/src/Controller/DisplayNode.php:

/**
 * @file
 * Contains \Drupal\drupalbook\Controller\DisplayNode.
 */
 
namespace Drupal\drupalbook\Controller;
 
use Drupal\Core\Access\AccessResult;
use Drupal\node\NodeInterface;
 
/**
 * Provides route responses for the DrupalBook module.
 */
class DisplayNode {
 
  /**
   * Returns a simple page.
   *
   * @return array
   *   A simple renderable array.
   */
  public function content(NodeInterface $node) {
    $element = array(
      '#markup' => $node->body->value,
    );
    return $element;
  }
 
  /**
   * Checks access for this controller.
   */
  public function access(NodeInterface $node) {
    $user = \Drupal::currentUser();
    if ($node->getType() == 'article' && !in_array('authenticated', $user->getRoles())) {
      return AccessResult::forbidden();
    }
    return AccessResult::allowed();
  }
 
  /**
   * Returns a page title.
   */
  public function getTitle(NodeInterface $node) {
    return $node->getTitle();
  }
 
}?>

I created a separate class for my route, so as not to interfere with everything in one controller class. Let's see what each of these lines means.

\drupalbook\Controller;
?>

We indicate where our controller file is located.

\Core\Access\AccessResult;
use Drupal\node\NodeInterface;
?>

We include the AccessResult class files - we will use it to output the 403 error and NodeInterface - we will use it to get the node object in the parameter method of our controller.

function content(NodeInterface $node) {
  $element = array(
    '#markup' => $node->body->value,
  );
  return $element;
}?>

Here, pay attention to the parameter, we get the node object, the Drupal itself converts the ID from the URL and passes the object to us, so that we do not load the node object again, but get it ready where we need it. $ node-> body-> value, this is how we get the field value from the node, but we will deal with the work with objects in detail in the next lesson when we analyze the Entity API. And at the end, we return an array with #markup to output our node to the text page.

function access(NodeInterface $node) {
  $user = \Drupal::currentUser();
  if ($node->getType() == 'article' && !in_array('authenticated', $user->getRoles())) {
    return AccessResult::forbidden();
  }
  return AccessResult::allowed();
}?>

First we use the Drupal method currentUser () to get the current user object, then we will use this object to get the roles of the current user. In the if check, we check the content type of our node and user role, anonymous users will receive a 403 error, if everything is fine, then we go ahead and return allowed (), that is, we simply approve our check. Let's open the AccessResult class and see what other methods this class has. To do this, in PhpStorm you need to press shift twice and enter the class name:

Access Result

Here you can find the following methods for checking permissions:

neutral
allowed
forbidden
allowedIf
forbiddenIf
allowedIfHasPermission
allowedIfHasPermissions
isAllowed
isForbidden
isNeutral
orIf
andIf

You can experiment with allowedIfHasPermission (), for example, and set different permissions for different roles for your route. For example, create a new permission in your module and use it in the controller. Although it is easier, of course, to use permission in the yml file of the route. But through the AccessResult class, you can flexibly describe the logic for accessing content, for example, "access to content is allowed to authorized users from 12 to 16 hours, and for users with the premium account role around the clock." Experiment and implement this differentiation of access rights to article nodes.

As you can see, Drupal provides several ways to implement access to content, which is convenient because 99% of cases use one permission and this is enough to differentiate access rights.

function getTitle(NodeInterface $node) {
  return $node->getTitle();
}?>

Here we simply return the name of the node as title, but we can expand the capabilities of our callback. For example, like this:

function getTitle(NodeInterface $node) {
    $user = \Drupal::currentUser();
    if ($node->getType() == 'article' && !in_array('authenticated', $user->getRoles())) {
     return 'Premium content:  ' . $node->getTitle();
   }
   else {
     return 'Free access content:  ' . $node->getTitle();
   }
 
}
?>

Or display the publication date in title:

As you can see, Drupal provides the ability to flexibly configure your route and controller. So when your client has ideas on the output of materials to the site, you can always do it using the Drupal API and a little PHP code.

Code examples can be viewed on github:
https://github.com/levmyshkin/drupalbook8