Проверка данных
Данные формы нельзя сохранять не глядя: заголовок может оказаться пустым, а почта — набором букв. CakePHP проверяет данные в два этапа. Валидация смотрит на формат присланных значений. Правила приложения проверяют то, для чего нужна база: не занято ли значение, существует ли связанная запись.
Где лежат правила
Оба набора находятся в классе таблицы — src/Model/Table/ArticlesTable.php. Команда bake model создаёт их заготовки по столбцам таблицы, дальше их правят вручную.
Валидация
// src/Model/Table/ArticlesTable.php
use Cake\Validation\Validator;
public function validationDefault(Validator $validator): Validator
{
$validator
->notEmptyString('title', 'Введите заголовок.');
return $validator;
}Правило одно: заголовок не должен быть пустым. Второй аргумент — сообщение об ошибке.
Когда она срабатывает
Валидация выполняется внутри patchEntity() и newEntity():
$article = $this->Articles->newEntity(['title' => '']);
debug($article->getErrors());debug() покажет массив с ключом title и текстом «Введите заголовок.». Ошибки хранятся в самой записи, а save() такую запись не сохранит и вернёт false.
Несколько правил
$validator
->requirePresence('title', 'create')
->notEmptyString('title', 'Введите заголовок.')
->minLength('title', 5, 'Заголовок должен быть не короче 5 символов.')
->maxLength('title', 255);
$validator
->notEmptyString('body', 'Введите текст.')
->boolean('published');Правила одного поля записывают цепочкой. requirePresence('title', 'create') требует, чтобы при создании записи поле вообще было в данных.
Частые правила
| Метод | Что проверяет |
|---|---|
notEmptyString('field') | Значение не пустое |
allowEmptyString('field') | Значение может быть пустым |
minLength(), maxLength() | Длина строки |
email('field') | Адрес почты |
integer('field'), decimal('field') | Число |
inList('field', ['a', 'b']) | Одно из значений |
date('field') | Дата |
sameAs('password_confirm', 'password') | Совпадение с другим полем |
Правила приложения
use Cake\ORM\RulesChecker;
public function buildRules(RulesChecker $rules): RulesChecker
{
$rules->add($rules->isUnique(['title'], 'Статья с таким заголовком уже есть.'));
return $rules;
}isUnique() заглядывает в базу и не даёт сохранить вторую статью с тем же заголовком. Правила приложения выполняются позже валидации — при вызове save(). Ещё одно готовое правило — existsIn(['article_id'], 'Articles'): связанная запись должна существовать.
Своё правило
$validator->add('title', 'noShouting', [
'rule' => fn (string $value) => $value !== mb_strtoupper($value),
'message' => 'Не пишите заголовок одними заглавными буквами.',
]);Функция получает значение поля и возвращает true, если оно подходит. noShouting — произвольное имя правила.
Частая ошибка
Валидация проверяет только данные, пришедшие через patchEntity() или newEntity(). Значение, заданное в коде, — $article->title = '' — пройдёт мимо неё. Правила, от которых зависит целостность данных, — уникальность, существование связанной записи — пишите в buildRules(): они проверяют запись при каждом сохранении.