Проверка данных
Правила проверки в Symfony записывают атрибутами прямо над свойствами сущности. Форма применяет их сама: метод isValid() вернёт false, а рядом с полями появятся сообщения об ошибках.
Ограничения
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Post
{
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[Assert\Length(min: 5, max: 255)]
private ?string $title = null;
#[ORM\Column(type: Types::TEXT)]
#[Assert\NotBlank]
private ?string $body = null;
}Больше ничего не нужно: форма из прошлого урока начнёт отклонять пустой или слишком короткий заголовок.
Частые ограничения
| Ограничение | Что проверяет |
|---|---|
NotBlank | Значение не пустое |
Length(min: 3, max: 50) | Длина строки |
Email | Адрес почты |
Url | Адрес сайта |
Positive, PositiveOrZero | Знак числа |
Range(min: 1, max: 100) | Число в границах |
Choice(['draft', 'published']) | Одно из значений |
Regex('/^[a-z0-9-]+$/') | Соответствие шаблону |
Image(maxSize: '2M') | Файл — картинка не больше 2 МБ |
Свои сообщения
#[Assert\NotBlank(message: 'Введите заголовок')]
#[Assert\Length(
min: 5,
minMessage: 'Заголовок должен быть не короче {{ limit }} символов',
)]
private ?string $title = null;Уникальность
Проверка по базе данных — ограничение над классом:
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[ORM\Entity]
#[UniqueEntity('email', message: 'Этот адрес уже занят')]
class User
{
#[ORM\Column(unique: true)]
#[Assert\Email]
private ?string $email = null;
}Проверка вручную
Без формы объект проверяет сервис ValidatorInterface:
use Symfony\Component\Validator\Validator\ValidatorInterface;
public function import(ValidatorInterface $validator): Response
{
$post = new Post();
$post->setTitle('');
$errors = $validator->validate($post);
if (count($errors) > 0) {
foreach ($errors as $error) {
echo $error->getPropertyPath() . ': ' . $error->getMessage();
}
}
// …
}Правило, зависящее от нескольких полей
use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[Assert\Callback]
public function validateDates(ExecutionContextInterface $context): void
{
if ($this->endsAt < $this->startsAt) {
$context->buildViolation('Окончание раньше начала')
->atPath('endsAt')
->addViolation();
}
}Частая ошибка
Большинство ограничений пропускают пустое значение: #[Assert\Email] считает пустую строку и null допустимыми. Если поле обязательное, добавляйте #[Assert\NotBlank] рядом. И помните: атрибут required в разметке проверяет только браузер, а его легко обойти — настоящая проверка всегда на сервере.