Свой модуль для Drupal: рабочие приёмы на практике
Небольшой модуль в Drupal быстро превращается в набор условий, если маршруты, бизнес-логику и интеграции складывать в один файл. Показываем, как разделить ответственность и выбрать между хуком, сервисом и плагином.

Не превращайте модуль в один большой файл
В Drupal 10 и 11 собственный модуль легко начать с одного хука, а закончить контроллером, который сам проверяет права, собирает данные и пишет в базу. Такой код трудно тестировать и опасно менять: правка страницы может случайно затронуть другую часть сайта. Практичнее сначала определить, что именно добавляет модуль, а затем разнести входные точки и логику по подходящим механизмам Drupal.
Ниже — приёмы для разработчика, который уже знаком с PHP и структурой проекта Drupal. Пример совместим с Drupal 10 и 11; перед установкой проверьте версию PHP и требования конкретной сборки сайта. Мы разберём модуль, который добавляет отдельную страницу, и покажем, когда вместо контроллера нужны сервис, хук или плагин.
Сначала решите, чем именно является ваша функция
Drupal предлагает несколько способов подключить поведение. Выбор зависит не от размера файла, а от того, кто должен запускать логику и сможет ли сайт расширять её без изменения вашего модуля.
| Механизм | Когда подходит | Цена решения |
|---|---|---|
| Контроллер | Обслуживает маршрут: страницу или ответ по URL | Сам по себе не должен становиться местом для всей бизнес-логики |
| Сервис | Содержит повторно используемую логику, которую вызывают контроллеры и другие компоненты | Нужно объявить сервис и передать ему зависимости |
| Хук | Подключается к предусмотренной Drupal точке расширения, например для изменения поведения системы | Привязан к конкретному событию или механизму; не годится как универсальная шина вызовов |
| Плагин | Нужны взаимозаменяемые реализации, которые Drupal обнаруживает и управляет ими | Потребуется соблюдать контракт плагинной системы |
Если функция отвечает на URL — начните с маршрута и контроллера. Если ту же операцию должны выполнять разные части сайта, вынесите её в сервис. Не заводите плагин только потому, что он выглядит архитектурно солиднее: если реализация одна и заменять её не планируют, лишний слой усложнит поддержку.
Хороший модуль не тот, где использованы все механизмы Drupal. Хороший — тот, где понятно, кто вызывает логику и где её менять.
Соберите маршрут и контроллер
Для отдельной страницы понадобятся машинное имя модуля, файл метаданных и описание маршрута. Назовём модуль site_report. Каталог разместите в web/modules/custom/site_report в типичной Composer-сборке; в проекте с другим document root используйте его фактическую папку модулей.
Файл site_report.info.yml:
name: Site report
type: module
description: Adds a report page.
core_version_requirement: ^10 || ^11
package: Custom
Здесь core_version_requirement заявляет совместимость с Drupal 10 и 11. Это не заменяет проверку зависимостей: модуль может требовать другую версию PHP или стороннего проекта.
Создайте site_report.routing.yml:
site_report.report:
path: '/admin/reports/site-report'
defaults:
_controller: '\Drupal\site_report\Controller\ReportController::build'
_title: 'Site report'
requirements:
_permission: 'access site reports'
Маршрут ограничен отдельным разрешением. Для него добавьте site_report.permissions.yml:
access site reports:
title: 'Access site reports'
description: 'View the site report.'
Такое разрешение можно назначить нужной роли через административный интерфейс. Не подменяйте его проверкой «пользователь вошёл в систему»: авторизованный пользователь и пользователь с правом смотреть отчёт — не одно и то же.
Контроллер разместите в src/Controller/ReportController.php:
<?php
namespace Drupal\site_report\Controller;
use Drupal\Core\Controller\ControllerBase;
final class ReportController extends ControllerBase {
public function build(): array {
return [
'#markup' => $this->t('The report is ready.'),
];
}
}
Контроллер возвращает render array — структуру, которую Drupal может обработать при отображении. Для демонстрации достаточно текста; в рабочем отчёте данные следует получать отдельной логикой, а пользовательский ввод — корректно проверять и выводить через систему рендеринга.
Выносите повторяемую работу в сервис
Если отчёт должен появиться ещё в блоке, команде или другом контроллере, не копируйте туда вычисления. Создайте сервис с одной понятной ответственностью и обращайтесь к нему через внедрение зависимостей. Так компонент можно заменить или тестировать отдельно от страницы.
Плохо, когда контроллер сам находит глобальные сервисы, читает сущности, применяет бизнес-правила и собирает вывод. Это связывает HTTP-маршрут с предметной логикой. Внедрение зависимостей — способ передать компоненту то, что ему нужно, вместо поиска зависимостей внутри него.
Не пытайтесь заранее построить универсальную систему отчётов, если пока есть один экран. Сначала выделите только повторяющуюся операцию. Сервис, которому нужны десятки параметров и который знает о маршрутах, отображении и хранении данных одновременно, обычно сигнализирует, что границы ответственности выбраны неудачно.
Три ошибки, которые дорого обходятся при поддержке
- Разрешение шире задачи. Маршрут доступен всем вошедшим пользователям, хотя содержит данные для администраторов. Задайте отдельное разрешение и проверьте доступ под ролью без него.
- Логика размазана по хукам. Один хук меняет данные, другой исправляет результат. Сначала выясните, существует ли подходящий API расширения, а общую операцию держите в сервисе.
- Изменения не видны сайту. Drupal может хранить конфигурацию и маршруты в кеше. После добавления файлов очистите кеш штатными средствами проекта, например командой Drush
drush cr, если Drush установлен. Убедитесь, что команда завершилась без ошибки, затем откройте страницу. - Модуль включён, но страница недоступна. Проверьте машинное имя в файле, маршрут, синтаксис YAML и назначение разрешения роли. Ошибка «Access denied» обычно указывает на доступ, а не на то, что контроллер не найден.
Хук — именованная точка расширения, через которую модуль может участвовать в предусмотренном Drupal процессе. Он не является произвольным обработчиком любого действия: сначала проверьте документацию для нужной версии и конкретного хука.
Как проверить модуль до выкладки
Проверяйте не только главную страницу. Для примера выше важны три сценария: у пользователя с разрешением страница открывается; у пользователя без него доступ закрыт; при отключённом модуле маршрут больше не работает. В дополнение проверьте логи Drupal и тесты проекта, если в нём уже настроен PHPUnit.
Перед коммитом просмотрите, какие файлы вы добавили и изменили. Файлы YAML должны корректно разбираться, а машинное имя модуля — совпадать в именах файлов, маршрутах и пространстве имён PHP. После изменения маршрутов или разрешений очистите кеш и повторите проверку от имени разных ролей.
Что делать дальше
Сначала доведите маршрут до рабочего состояния и проверьте его доступ под нужной ролью. Затем вынесите из контроллера повторяемую бизнес-логику в сервис, если появился второй потребитель. Для более сложного модуля добавьте автоматические тесты и отдельно изучите официальную документацию Drupal по маршрутизации, сервисам и расширению системы. Инвалидация кеша и миграции конфигурации — отдельные темы: не смешивайте их с первой версией функции.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: Drupal documentation: Routing system, Drupal documentation: Services and dependency injection
Частые вопросы
Подойдёт ли этот пример для Drupal 9?
Почему после добавления маршрута Drupal его не находит?
Нужно ли создавать сервис для любой новой функции?
Можно ли вместо отдельного разрешения проверить, что пользователь вошёл в систему?
Как понять, нужен хук или плагин?
Безопасно ли сразу ставить модуль на рабочий сайт?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.