Хуки
Хук — место в ядре или чужом модуле, куда ваш модуль может добавить свой код. Drupal в определённый момент — перед сохранением материала, перед выводом формы — спрашивает все включённые модули, хотят ли они вмешаться. Так поведение сайта меняют, не правя чужие файлы.
Где пишут хуки
Хук — обычная функция в файле blog.module в корне папки модуля. Файл появился в уроке о шаблонах: функция blog_theme() в нём — тоже хук. Имя функции строится по правилу «имя модуля, подчёркивание, имя хука».
Первый хук
Хук hook_entity_presave вызывается перед сохранением любой сущности. Уберём лишние пробелы в заголовках статей:
// web/modules/custom/blog/blog.module
use Drupal\Core\Entity\EntityInterface;
use Drupal\node\NodeInterface;
/**
* Implements hook_entity_presave().
*/
function blog_entity_presave(EntityInterface $entity): void
{
if ($entity instanceof NodeInterface && $entity->bundle() === 'article') {
$entity->setTitle(trim($entity->getTitle()));
}
}Слово hook в названии заменено именем модуля: hook_entity_presave стал blog_entity_presave. Выполните drush cr, создайте статью с пробелами в начале заголовка — после сохранения их не будет. Комментарий Implements hook_… — принятое соглашение, оно помогает искать хуки в коде.
Изменение чужой формы
Хук hook_form_alter вызывается перед выводом каждой формы сайта:
// web/modules/custom/blog/blog.module
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_form_alter().
*/
function blog_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void
{
if ($form_id === 'node_article_form') {
$form['title']['widget'][0]['value']['#description'] = t('Не длиннее 60 знаков.');
}
}Под полем заголовка на форме создания статьи /node/add/article появится подсказка. Массив формы приходит по ссылке — знак & перед $form, — поэтому хук меняет его на месте и ничего не возвращает. Идентификатор формы виден в её HTML-коде, в атрибуте id тега form, только с дефисами вместо подчёркиваний.
Частые хуки
| Хук | Когда вызывается |
|---|---|
hook_theme() | Объявление своих шаблонов |
hook_form_alter() | Перед выводом любой формы |
hook_form_FORM_ID_alter() | Перед выводом одной конкретной формы |
hook_entity_presave() | Перед сохранением сущности |
hook_entity_insert(), hook_entity_update() | После создания и после изменения |
hook_entity_delete() | После удаления |
hook_preprocess_HOOK() | Перед выводом шаблона: подготовка переменных |
hook_page_attachments() | Подключение библиотек ко всем страницам |
hook_cron() | При запуске планировщика |
Заглавные буквы в названии заменяют конкретным значением: hook_form_FORM_ID_alter для формы статьи — это blog_form_node_article_form_alter.
Где искать хуки
Все хуки ядра описаны в файлах с окончанием .api.php, например web/core/lib/Drupal/Core/Entity/entity.api.php. В них перечислены аргументы и приведён пример. Эти файлы не выполняются, они служат документацией.
Хуки в классах
Начиная с Drupal 11.1 хук можно написать методом класса с атрибутом — без файла blog.module:
// web/modules/custom/blog/src/Hook/BlogHooks.php
namespace Drupal\blog\Hook;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Hook\Attribute\Hook;
class BlogHooks
{
#[Hook('entity_presave')]
public function entityPresave(EntityInterface $entity): void
{
// тот же код, что в функции
}
}Класс лежит в папке src/Hook, а имя хука указано в атрибуте без слова hook_. В Drupal 10 этот способ не работает, поэтому в курсе используются функции — они работают в обеих версиях.
Частая ошибка
Опечатка в имени функции не вызывает ошибки: blog_from_alter вместо blog_form_alter — допустимая функция PHP, которую просто никто не вызовет. Если хук «не срабатывает», сверьте имя по буквам и выполните drush cr: список хуков каждого модуля хранится в кеше, и новую функцию Drupal увидит только после его очистки.