For the complete documentation index, see llms.txt. This page is also available as Markdown.

Валидация

Зачем нужен валидатор

Почти в каждой форме есть поля, обязательные для заполнения, значения, которые нужно проверить по базе данных, адреса электронной почты, длину текста и списки допустимых значений. Валидатор избавляет от рутины: вы описываете правила, а он проверяет данные и возвращает сообщения о том, что именно не так.

Внутри работает symfony/validator, но в коде модуля вы его не видите: правила — это объекты JohnCMS, а движок скрыт за интерфейсом. Это позволяет заменить движок, не переписывая формы.

Быстрый старт

Валидатор внедряется через интерфейс Johncms\Validator\ValidatorInterface, создавать его вручную не нужно.

<?php

declare(strict_types=1);

namespace Johncms\Modules\MyModule\Application\Controllers;

use Johncms\Http\Request;
use Johncms\Http\View\ViewResponse;
use Johncms\Validator\Rules\EmailAddress;
use Johncms\Validator\Rules\StringLength;
use Johncms\Validator\ValidatorInterface;

final readonly class FeedbackController
{
    public function __construct(private ValidatorInterface $validator)
    {
    }

    public function __invoke(Request $request): ViewResponse
    {
        $formData = [
            'name'    => $request->body('name', ''),
            'email'   => $request->body('email', ''),
            'message' => $request->body('message', ''),
        ];

        $result = $this->validator->validate($formData, [
            'name'    => [new StringLength(min: 2, max: 50)],
            'email'   => [new EmailAddress()],
            'message' => [new StringLength(min: 10, max: 5000)],
        ]);

        if ($result->isValid()) {
            // Сохраняем данные
        }

        return new ViewResponse('@my-module/public/form.twig', [
            'errors' => $result->getErrors(),
        ]);
    }
}

Первый аргумент validate() — массив данных, обычно собранный из запроса. Второй — массив правил: ключ совпадает с именем поля, значение — список правил, которые к этому полю применяются.

Данные могут содержать больше полей, чем описано правил: лишние валидатор не трогает. Поле, для которого правила описаны, но которого нет в данных, проверяется как пустое значение.

Результат проверки

validate() возвращает объект Johncms\Validator\ValidationResult. Он неизменяемый: методы, меняющие состав ошибок, возвращают новый объект.

Метод
Что делает

isValid()

true, если ошибок нет

getErrors()

массив имя поля => список сообщений

hasError('email')

есть ли ошибки у поля

getFirstError('email')

первое сообщение поля или null

withError('field', 'текст')

новый результат с добавленной ошибкой

merge($otherResult)

объединяет два результата

throwIfInvalid($factory)

бросает исключение, если результат невалиден

Массив из getErrors() передаётся в шаблон как есть — компонент @theme/components/field-errors.twig и остальная вёрстка ожидают именно такую форму:

Ошибки, которые находятся после валидации

Иногда причина отказа известна только после проверки правил — например, раздел нельзя сделать родителем самого себя. Такую ошибку добавляют в результат, а не разворачивают его в массив:

Исключение вместо проверки

Если ошибки формы обрабатывает не контроллер, а вызывающий код, удобнее сразу бросить доменное исключение:

Обязательные и необязательные поля

Поле, у которого есть правила, обязательно, если явно не указано обратное.

Пустыми считаются null, пустая строка и строка из одних пробелов, пустой массив и false. Ноль в любом виде (0, 0.0, '0') пустым не считается — это значение.

Параметр allowEmpty есть у всех правил, для которых он имеет смысл. Указывайте его осознанно: это единственное место, где записана разница между полем, которое посетитель может не заполнять, и полем, которое заполнить обязан.

Ошибки формы целиком

Некоторые правила проверяют не значение поля, а обстоятельства отправки: не флудит ли посетитель, нет ли у него бана. Такие правила помещают под зарезервированный ключ ValidationResult::FORM_KEY (_form):

В шаблоне такие сообщения выводятся над формой:

Порядок правил

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

Свои сообщения

У каждого правила есть параметр message — он заменяет стандартный текст:

Сообщение принадлежит одному правилу и не влияет на остальные поля формы.

Что дальше

Что изменилось в 10.0

Было
Стало

new \Johncms\Validator\Validator($data, $rules)

внедрение ValidatorInterface, метод validate()

'name' => ['NotEmpty', 'StringLength' => ['min' => 2]]

'name' => [new StringLength(min: 2)]

$validator->isValid() / getErrors()

$result->isValid() / $result->getErrors()

третий аргумент конструктора — сообщения для всей формы

параметр message у конкретного правила

правило Csrf

проверку выполняет middleware, правила больше нет

Flood и Ban на поле csrf_token

ключ ValidationResult::FORM_KEY

обязательность поля зависела от правила

правило требует значение, пока не указан allowEmpty: true

Правила прежнего движка, которые нигде в JohnCMS не используются (файловые, Date, Ip, Uri, Regex, Hostname и другие), не переносились. Если такое правило нужно вашему модулю — опишите его как своё правило.

Последнее обновление

Это было полезно?