Валидация полей на примере параграфа в Drupal 11 с использованием @Constraint

При разработке на Drupal рутинная необходимость это — добавление кастомной валидации для полей внутри сущностей. Стандартные средства Drupal (например, валидация через hook_form_alter) не всегда подходят, особенно когда нужно, чтобы валидация работала при любом способе сохранения сущности — через форму, REST API, JSON:API или миграции. Кроме того, в hook_form_alter сложно добраться до полей вложенных сущностей, как например, параграфы, чтобы подсветить ошибку именно там, где она произошла.

В этой статье мы рассмотрим, как добавить валидацию к полю внутри параграфа с использованием системы Constraints (ограничений) Drupal 11, например, чтобы она работала при редактировании node, в которой есть поле с параграфами.

В качестве примера мы проверим, что поле field_ticketland в параграфе типа afisha содержит корректный URL на сайт ticketland.ru.

Почему Constraints?

Constraints (ограничения) — это стандартный механизм валидации в Drupal, основанный на Symfony Validation Component. Его ключевые преимущества:

  • Универсальность — работает при любом способе сохранения сущности
  • Переиспользуемость — одно правило можно применить к разным полям
  • Интеграция с формами — ошибки отображаются рядом с проблемным полем
  • Расширяемость — легко создавать свои правила валидации

Архитектура Constraints в Drupal

Система Constraints состоит из двух ключевых компонентов:

  1. Constraint (Ограничение) — описывает правило, хранит метаданные (ID, сообщение об ошибке, параметры)
  2. ConstraintValidator (Валидатор) — содержит логику проверки значения

Такое разделение позволяет:

  • Использовать одно правило с разными валидаторами
  • Кешировать метаданные и валидаторы как сервисы
  • Внедрять зависимости в валидаторы через Dependency Injection

Пошаговая реализация

Шаг 1: Создание структуры файлов

В вашем модуле (в примере — cmb_tweaks) создайте следующую структуру:

У вас может быть уже существующий модуль, тогда cmb_tweaks.module не понадобится, разместите srс файлы в вашем модуле, но учтите пространство имен (namespace).

Шаг 2: Создание класса ограничения (Constraint)

Файл: src/Plugin/Validation/Constraint/TicketLandConstraint.php

Что здесь происходит:

  • Аннотация @Constraint регистрирует наш класс как плагин
  • id — уникальный идентификатор, по которому мы будем ссылаться на правило
  • label — человекочитаемое название для интерфейса
  • Свойство $message — сообщение об ошибке, которое увидит пользователь

Шаг 3: Создание валидатора

Файл: src/Plugin/Validation/Constraint/TicketLandConstraintValidator.php

Важные моменты:

  • В метод validate() приходит FieldItemList (объект поля), а не просто значение
  • Используем getString() для получения текстового значения
  • addViolation() добавляет ошибку, которая будет отображена в форме

Шаг 4: Прикрепление констрейнта к полю

Файл: src/Hook/TicketLandHooks.php

Здесь мы объявили хук через аннотацию Hook. Такой подход работает не для всех хуков. И для такой реализации entity_bundle_field_info_alter требуется Drupal 11.1. Если у вас 10я версия, то просто реализуйте функциональное объявление этого хука.

Шаг 5: Очистка кеша

После создания всех файлов выполните очистку кеша:

Теперь валидация будет работать при сохранении любого параграфа типа afisha с полем field_ticketland.

Альтернативный подход: Callback валидация

Нельзя не упомянуть об альтернативе. Создавать два класса для небольшой скромной проверки поля — это всегда мне казалось каким то экстремальным программированием, есть альтернативный способ.

Мы также создаём хук hook_entity_bundle_field_info_alter, но ограничение (валидацию) реализуем через callback.

Плюсы очевидны:

  • Всё в одном месте — логика хука и валидации находится в одном классе
  • Легко найти — разработчики знают, где искать валидацию
  • Поддержка IDE — автодополнение, рефакторинг, навигация

Метод обязательно должен быть статическим (public static). Drupal вызывает callback через вызов функции, и статический метод — это единственный способ обратиться к классу без создания экземпляра.

Мало букафф? Читайте есчо !

Unit-тесты в Drupal 11: настройка PHPUnit и примеры запуска

Июнь 30, 2025 г.

Если вы только начинаете писать тесты в Drupal, то официальная документация — первое место, куда стоит заглянуть. Однако она не всегда отвечает на все вопросы новичков. В этой статье разберём несколько моментов, которые часто вызывают недоумение. ...

Читать

Preprocess Media Устарел В Drupal 11.3

Декабрь 15, 2025 г.

В Drupal 11.3 произошла важная, но не сразу заметная смена подхода к theming‑слою: классические процедурные preprocess‑функции вида template_preprocess_* были помечены как устаревшие. Это касается и template_preprocess_media(), который многие годы использовался ...

Читать

Генерируем UUID прямо в шаблоне

Ноябрь 6, 2025 г.

Понадобилось мне сгенерировать уникальный код, чтобы привязать уникальные стили к конкретному контейнеру. Функция random в twig чаще всего достаточна для этой цели. Но хотелось пойти немного дальше, и вытащить сервис генерации UUID. Это нам приводит ...

Читать
 

Комментарии к «Валидация полей на примере параграфа в Drupal 11 с использованием @Constraint»

Понравилась статья? Есть вопросы? - пишите в комментариях.



Комментарий: