Мы можем использовать параметры в URL для роутов. Они работают также как contextual filters во Views. Мы можем например передавать в URL ID различных сущностей, текстовые строки или последовательной ID разделенных запятой или плюсами. В этом уроке мы будем передавать ID ноды и выводить title и body этой ноды в контенте.
Примеры кода можно посмотреть на github:
https://github.com/levmyshkin/drupalbook8
Давайте добавим route в файл нашего модуля drupalbook.routing.yml:
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
Здесь в path мы передаем во втором аргументе {node}, в урле мы будем писать обычный ID: /display-node/101, но в наш контроллер будет приходить уже готовый объект ноды. Для этого мы указываем в options параметры, что в эти параметры должно передаваться и что будет на выходе
options: parameters: node: #имя аргумента, то что находится между {}, это может быть node1, node2, если мы будем передавать два разных аргумента. type: entity:node # то что будет на выходе, мы можем использовать объект этой сущности внутри контроллера.
Также я определил в каком методе мы будем выводить заголовок с помощью параметра _title_callback. И мы будем ограничивать вывод статей для анонимных пользователей, для этого мы используем _custom_access параметр в котором указываем в каком методе мы будем накладывать различные ограничения.
Тепреь когда мы разобрались с описанием роута, давайте перейдем к написанию класса для этого роута.
modules/custom/drupalbook/src/Controller/DisplayNode.php:
<?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(); } }
Я создал отдельный класс для нешего роута, чтобы не мешать все в один класс контроллер. Давайте разберемся, что значит каждая из этих строк.
namespace Drupal\drupalbook\Controller;
Указываем где лежит наш файл контроллера.
use Drupal\Core\Access\AccessResult; use Drupal\node\NodeInterface;
Подключаем файлы классов AccessResult - мы будем использовать его для вывода ошибки 403 и NodeInterface - мы будем использовать его для получения объекта ноды в параметр методов нашего контроллера.
public function content(NodeInterface $node) { $element = array( '#markup' => $node->body->value, ); return $element; }
Здесь обратите внимание на параметр, мы получаем здесь объект ноды, друпал сам преобразуем ID из URL и передает нам объект, так чтобы мы лишний раз не подгружали объект нода, а получали готовый там где нам нужно. $node->body->value так мы получаем значение поля из ноды, но о работе с объектами мы разберемся подробно в следующим уроке, когда будем разбирать Entity API. И в конце мы возвращаем массив с #markup для вывода на страницу текста наше ноды.
public function access(NodeInterface $node) { $user = \Drupal::currentUser(); if ($node->getType() == 'article' && !in_array('authenticated', $user->getRoles())) { return AccessResult::forbidden(); } return AccessResult::allowed(); }
Сначала мы используем метод друпала currentUser(), чтобы получить объект текущего пользователя, дальше мы будем использовать этот объект, чтобы получить роли текущего пользователя. В проверке if, проверяем контент тип нашей ноды и роли пользователя, для анонимных пользователей будет выдаваться 403 ошибка, если все хорошо, то мы идем дальше и возвращаем allowed(), то есть просто одобряем нашу проверку. Давайте откроем класс AccessResult и посмотрим какие еще методы есть у этого класса. Для этого в PhpStorm нужно дважды нажать shift и ввести названия класса:
Здесь можно найти следующие методы для проверки прав доступа:
neutral allowed forbidden allowedIf forbiddenIf allowedIfHasPermission allowedIfHasPermissions isAllowed isForbidden isNeutral orIf andIf
Вы можете поэксперментировать например с allowedIfHasPermission() и по задавать различные права доступа для разных ролей для вашего роута. Например, создать новый permission в своем модуле и использовать его в контроллере. Хотя проще, конечно, использовать permission в yml файле роута. Но через AccessResult класс можно гибко описать логику для доступу к контенту, например "доступ к контенту разрешен авторизированным пользователям с 12 до 16 часов, а пользователям с ролью premium аккаунт круглосуточно". Поэксперментируйте и реализуйте такое разграничение прав доступа к нодам статей.
Как видите друпал предоставляет сразу несколько путей для реализации доступа к контенту, что удобно, потому что 99% процентов кейсов используют один permission и этого вполне хватает для разграничений прав доступа.
public function getTitle(NodeInterface $node) { return $node->getTitle(); }
Здесь мы просто возвращаем название ноды как title, но можно и расширить возможности нашего callback'а. Например так:
public 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(); } }
Или вывести дату публикации в title:
public function getTitle(NodeInterface $node) { return $node->getTitle() . ' from ' . date('d.m.Y', $node->getCreatedTime()); }
Как видите Drupal предоставляет возможность гибко настроить ваш роут и контроллер. Так что когда у вашего клиента возникнут самые безумные идеи по выводу материалов на сайт, вы всегда сможете это сделать с помощью Drupal API и немного PHP кода.
Примеры кода можно посмотреть на github:
https://github.com/levmyshkin/drupalbook8
Добавить комментарий