12.3. Создаем кастомный Drupal 8 модуль. Вывод страницы программно.
Начнем создание нашего модуля с небольшого упорядочивания. Давайте впредь будем разделять модули кастомные и контрибные. В 8ом друпале модули лежат в папке /modules. Теперь нам не нужно класть их вглубь /sites/all/modules, хотя в readme написано, что это должно работать используйте все-таки папку /modules. Внутри папки /modules мы создадим две папки custom и contrib. В папке contrib будут храниться дополнительные модули с drupal.org, а в папке custom будут храниться наши кастомные модули.
Примеры кода можно посмотреть на github:
https://github.com/levmyshkin/drupalbook8
Такая мелочь как разделение модулей на папки contrib, custom кажется таким не нужным, но поверьте, когда ваш сайт обрастет 200 контрибными и 30 кастомными модулями вы поймете как сложно найти все кастномные модули и весь кастомный код на сайте. Также если вы изменяете какой-то код в контрибном модулей (что делайте только при крайней необходимости), то его тоже бы неплохо переместить в папку custom, чтобы случайно не затереть изменения при обновление (или другой программист затрет ваши изменения или даже вы затрете, ничего не подозревая, изменения другого программиста.
Итак, давайте создадим наш кастомный модуль. Создадим папку /modules/custom/drupalbook. В этой папке нам нужно будет создать файл drupalbook.info.yml:
name: DrupalBook
description: Custom module for learning Drupal 8
type: module
core: 8.x
package: DrupalBook
*.info.yml файл отвечает за описание модуля. Информация которая в нем указана будет выводиться на странице управления модулями. Само название файла состоит из названия модуля + .info.yml.
YML-файлы в друпале это стандартный формат конфигураций и настроек. Поля и значения в YML-файлах разделяются двоеточием, новая строка идет с отступов в два пробела. Форматирование очень важно для YML-файла, если в формотирование допущена ошибка, лишний пробел или не хватает двоеточия, то друпал может выдать ошибку или не правильно прочитать YML-файл.
Зайдите на страницу Extend (Модули) и включите ваш модуль:
Теперь когда модуль включен мы можем добавлять функционал и он будет работать на нашем сайте. Для начала мы выведем простой текст на странице. Для этого нам потребуется создать еще один YML-файл drupalbook.routing.yml:
drupalbook.first_page:
path: '/first-page'
defaults:
_controller: '\Drupal\drupalbook\Controller\FirstPageController::content'
_title: 'Hello World!'
requirements:
_permission: 'access content'
Давайте разберем подробно, что находится в этом YML-файле.
drupalbook.first_page: - здесь имя нашего роута, пути, по которому друпал будет собирать список всех роутов, путей. Это имя должно быть уникально, лучше всего использовать имя_модуля.имя_роута, потому что у вас может быть несолько роутов в одном модуле: drupalbook.first_page, drupalbook.second_page и так далее.
path: '/first-page' - путь к вашему роуту. Обратите внимание на отступ в два пробела, он обязателей, поэтому если вы пользуетесь тестовым редактором, который выставляет табаляцию на кнопке табуляции, то лучше изменить эту настройку и сделать выставление двух пробелов вместо табуляции.
defaults: - определяет настройки роута по умолчанию и каким образом нужно создавать route. Дело в том что есть несколько способов создания роута, один из них через класс Контроллер, но можно и через другие классы динамического создания роутов. Возможно позже мы разберем все возможности по работе с роутингом, а пока рассмотрим простой пример через класс Контроллер. Роутинг в Drupal 8 перешел из Symfony и использует библиотеки Symfony. Symfony - это MVC фреймворк, он очень попурялный и используется также в других проектах, например в Laravel, который тоже очень популярный MVC фреймворк. MVC предполагает использование Model, View, Controller (здесь View имеется в виду не модуль Views, а просто шаблон для вывода информации, Model - классы сущностей с помощью которых можно добавлять информацию в базу данных, примерно как в друпале это делает Entity API). Controller из MVC нужен как раз для routing'а, что мы сейчас и делаем в этом уроке.
_controller: '\Drupal\drupalbook\Controller\FirstPageController::content' - В этом параметре мы определяем какой PHP Class будет выводить нашу страницу. После имени класса :: мы указываем какой конкретно метод класса будет выводить страницу. Такое большое количество косых черт, нужно чтобы друпал понял в какой папке лежит ваш PHP class.
_title: 'Hello World!' - Заголовок нашей страницы
_permission: 'access content' - Права на просмотр этой страницы, пользотель должен иметь роль с этими правами, чтобы открыть эту страницу.
После того как мы добавить YML-файл для роутинга, мы должны добавить PHP class для отображения нашей страницы. Для этого нам нужно сначала разобраться в автоподключение файлов классов из наших модулей. Дело в том, что в Drupal очень много классов и не все из них нужны для загрузки определенной страницы, поэтому мы подгружаем только необходимые классы и работаем с ним. Drupal использует автоподключение PHP классов PSR-4:
https://www.php-fig.org/psr/psr-4/
Давайте посмотрим на строку в роуте, где мы указывали PHP class:
\Drupal\drupalbook\Controller\FirstPageController
\Drupal - означает что класс подключается с помощью библиотеки Drupal. Drupal теперь тоже отдельная библиотека, правда довольно-таки большая, которую можно подключать через packagist:
https://packagist.org/packages/drupal/drupal
Дальше мы указываем какой модуль мы хотим использовать:
\drupalbook
После этого мы указываем или сразу имя класса в папке нашего модуля или указываем дальнейшую вложенность. Но дальше все папки уже будут находиться внутри папки src, то есть если мы указали Controller папку, то она будет лежать здесь:
/modules/custom/drupalbook/src/Controller
Обратите внимание на регистр, PHP чувствителен к регистру поэтому controller и Controller это разные папки.
И в конце мы указали имя файла, к нему нужно добавить .php:
/modules/custom/drupalbook/src/Controller/FirstPageController.php
Давайте создадим этот файл:
/**
* @return
* Contains \Drupal\drupalbook\Controller\FirstPageController.
*/
namespace Drupal\drupalbook\Controller;
/**
* Provides route responses for the DrupalBook module.
*/
class FirstPageController {
/**
* Returns a simple page.
*
* @return array
* A simple renderable array.
*/
public function content() {
$element = array(
'#markup' => 'Hello World!',
);
return $element;
}
}
Должна получится вот такая структура файлов:
Теперь нужно почистить кэш, чтобы наш новый route подключился. И страница должна заработать http://drupalbook/first-page :
Теперь давайте разберемся с PHP классом, который выводит эту страницу.
/**
* @return
* Contains \Drupal\drupalbook\Controller\FirstPageController.
*/
Здесь мы указываем путь такой же как в YML-файле роутинга, он показывает откуда Drupal должен подключать этот класс.
namespace Drupal\drupalbook\Controller;
namespace указывает путь к вашему файлу с классом. Будьте внимательны при копирование кода с других сайтов, когда вы копируете namespace, имя модуля нужно менять на свое, у меня оно drupalbook, у вас может быть другое.
class FirstPageController {
/**
* Returns a simple page.
*
* @return array
* A simple renderable array.
*/
public function content() {
$element = array(
'#markup' => 'Hello World!',
);
return $element;
}
}
И собственно наш класс, который выводить страницу. В нем есть метод content(), который мы указали в drupalbook.routing.yml. В этом методе мы возвращаем массив с элементом #markup в котором мы кладем HTML на вывод. Мы возвращаем массив, а не строку, потому что через обычный роут можно вывести не только HTML, но и JSON endpoint для API, XML или CSV файл.
Код модуля можно посмотреть на github:
https://github.com/levmyshkin/drupalbook8
На этом все в следующем уроке мы продолжим расширять возможности нашего модуля.