Валидация
Дата обновления перевода 2024-08-01
Валидация
Валидация - это очень распространенная задача для веб-приложения. Данные, вводимые в формы, должны быть валидированы. В то же время, данные должны быть валидированы до того, как они будут записаны в базу данных или же будут переданы веб-сервису.
Symfony содержит компонент Validator, который упрощает эту задачу. Этот компонент основан на документе спецификация валидации JSR303 Bean.
Установка
В приложениях, использующих Symfony Flex , выполните эту команду, чтобы установить валидатор перед его использованием:
1
$ composer require symfony/validator
Note
Если ваше приложение не использует Symfony Flex, вам может понадобиться проделать некоторую конфигурацию вручную, чтобы подключить валидацию. Посмотрите справочник конфигурации Валидации .
Основы валидации
Самый лучший способ понять валидацию - это увидеть её в действии. Для начала, предположим, что вы создали обычный PHP-объект, который вам нужно использовать в вашем приложении:
1 2 3 4 5 6 7
// src/Entity/Author.php
namespace App\Entity;
class Author
{
private $name;
}
Пока это обычный класс, который служит какой-то цели внутри вашего приложения.
Задача валидации заключается в том, чтобы сообщить вам - являются ли данные
объекта корректными (валидными). Для этого, вам нужно настроить перечень правил
(называемых ограничениями (constraints)), которым
объект должен соответствовать, чтобы быть валидным. Эти правила обычно определяются
с использованием PHP-кода, но также могут быть определены, как файлы .yaml
или
.xml
внутри каталога config/validator/
:
Например, для того, чтобы гарантировать, что свойство $name
не пустое,
добавьте следующий код:
1 2 3 4 5 6 7 8 9 10 11
// src/Entity/Author.php
namespace App\Entity;
// ...
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
#[Assert\NotBlank]
private string $name;
}
Добавление этой конфигурации самой по себе еще не гарантирует, что значение не будет пустым; вы все еще можете установить его как пустое значение, если вы этого хотите. Чтобы действительно гарантировать, что значение примкнет к ограничнению, объект должен быть переда сервису влаидатора на проверку.
Tip
Валидатор Symfony использует рефлексию PHP, а также методы "геттера", чтобы получить значение любого свойства; они могут быть публичными, частными или защищенными (см. ).
Использование сервиса валидатора
Далее, чтобы проверить объект Author
, используйте метод validate()
сервиса
validator
(который реализует ValidatorInterface).
Обязанности у validator
простые: прочитать ограничения (т.е. правила) для класса,
и определить, соответствуют ли данные из объекта этим ограничениям. Если валидация
проходит с ошибкой, возвращается список ошибок (класс
ConstraintViolationList).
Давайте рассмотрим этот простой пример изнутри контроллера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// ...
use App\Entity\Author;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
// ...
public function author(ValidatorInterface $validator): Response
{
$author = new Author();
// ... do something to the $author object
$errors = $validator->validate($author);
if (count($errors) > 0) {
/*
* Использует метод __toString в переменной $errors, которая является объектом
* ConstraintViolationList. Это дает хорошую строку для отладки.
*/
$errorsString = (string) $errors;
return new Response($errorsString);
}
return new Response('The author is valid! Yes!');
}
Если свойство $name
пустое, вы увидите следующее сообщение об ошибке:
1 2
Object(App\Entity\Author).name:
Это значение не должно быть пустым.
Если же вы укажете значение для свойства name
, появится сообщение об
успешной валидации.
Tip
В большинстве случаев, вы не будете напрямую взаимодействовать с
сервисом validator
и вам не нужно будет беспокоиться об отображении
ошибок. Зачастую вы будете использовать валидацию косвенно при обработке
данных из отправленных приложению форм. Подробнее об этом смотрите тут:
как валидировать формы Symfony .
Вы также можете передать коллекцию ошибок в шаблон:
1 2 3 4 5
if (count($errors) > 0) {
return $this->render('author/validation.html.twig', [
'errors' => $errors,
]);
}
Внутри шаблона вы можете вывести список ошибок так, как вам нужно:
1 2 3 4 5 6 7
{# templates/author/validation.html.twig #}
<h3>Автор имеет следующие ошибки</h3>
<ul>
{% for error in errors %}
<li>{{ error.message }}</li>
{% endfor %}
</ul>
Note
Каждая ошибка валидации (называемая «нарушение ограничения»),
представлена объектом ConstraintViolation.
Этот объект позволяет вам, кроме прочего, получать ограничение, которое
привело к данному нарушению, благодаря методу ConstraintViolation::getConstraint()
.
Вызываемые валидации
Validation
также позволяет вам создавать замыкание, чтобы валидировать
значения в соотношении с набором ограничений (полезно, к примеру, при
валидации ответов команд Console или
при валидации значений OptionsResolver ):
- createCallable()
-
Возвращает замыкание, которое вызывает
ValidationFailedException
когда ограничения не совпадают. - createIsValidCallable()
-
Возвращает замыкание, которое возвращает
false
когда ограничения не совпадают.
Ограничения
Validator
создан для того, чтобы проверять объекты на соответствие ограничениям
(т.е. правилам). Для того чтобы валидировать объект, просто укажите для его класса
одно или несколько ограничений, и передайте его сервису валидации (validator
).
За кулисами, ограничение - это просто PHP-объект, который выполняет утвердительное выражение.
В настоящей жизни, ограничение может выглядеть так: "пирог не должен подгореть"
. В
Symfony ограничения выглядят похожим образом: это утверждения, что некоторое условие
истинно. Учитывая значение, ограничение скажет вам, соответствует ли это значение
правилам ограничения.
Поддерживаемые ограничения
Symfony содержит большое количество самых необходимых ограничений:
Дата обновления перевода 2024-07-25
Основные ограничения
Вот основные ограничения: используйте их, чтобы утверждать очень базовые вещи о значении свойств или возвратном значении методов вашего объекта.
Другие ограничения
- AtLeastOneOf
- Sequentially
- Compound
- Callback
- Expression
- When
- All
- Valid
- Cascade
- Traverse
- Collection
- Count
- UniqueEntity
- EnableAutoMapping
- DisableAutoMapping
Вы также можете создавать свои собственные ограничения. Эта тема раскрыта в статье Как создать пользовательское ограничение валидации.
Конфигурация ограничений
Некоторые ограничения, как например NotBlank просты,
в то время как другие, например Choice - имеют несколько
опций конфигурации. Предположим, что класс Author
имеет свойство genre
(жанр), которое
определяет жанр литературы, который в основном ассоциируется с автором, и которое можно установить
в значение "беллетристика" или "не беллетристика" ("fiction" или "non-fiction"):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// src/Entity/Author.php
namespace App\Entity;
// ...
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
#[Assert\Choice(
choices: ['fiction', 'non-fiction'],
message: 'Choose a valid genre.',
)]
private string $genre;
// ...
}
Опции ограничения всегда могут быть переданы в виде массива. Однако, некоторые
ограничения также позволяют вам передать значение одной опции «по умолчанию»
вместо массива. В случае с ограничением Choice
, опции choices
можно
указать таким образом.
1 2 3 4 5 6 7 8 9 10 11 12 13
// src/Entity/Author.php
namespace App\Entity;
// ...
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
#[Assert\Choice(['fiction', 'non-fiction'])]
private string $genre;
// ...
}
Такая возможность позволяет сделать настройку самых распространенных опций ограничения короче и быстрее.
Если вы не уверены, как нужно указывать опцию, сверьтесь с пространством имен
Symfony\Component\Validator\Constraints
касательно ограничения или же поступайте
безопасно - всегда передавая массив опций (как показано в первом методе выше).
Ограничения в классах формы
Ограничения могут быть обозначены во время построения форм с помощью опции
constraints
полей формы:
1 2 3 4 5 6 7 8 9
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('myField', TextType::class, [
'required' => true,
'constraints' => [new Length(['min' => 3])],
])
;
}
Цели ограничения
Ограничения могут быть применены к свойству класса (например, name
),
публичному геттер-методу (например, getFullName()
) или целому классу.
Первый вариант наиболее распространенный и легкий. Однако ограничения геттера
позволяют вам указывать более сложные правила валидации. И, наконец, ограничения
класса предназначены для случаев, когда вы хотите валидировать класс в качестве
единого целого.
Свойства
Валидация свойств класса - самая простая техника валидации. Symfony позволяет
вам проверять приватные, защищенные или публичные свойства. Ниже вы увидите,
как сделать так, чтобы свойство $firstName
класса Author
имело как минимум
3 символа.
1 2 3 4 5 6 7 8 9 10 11
// src/Entity/Author.php
// ...
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
#[Assert\NotBlank]
#[Assert\Length(min: 3)]
private string $firstName;
}
Caution
Валидатор будет использовать значение null
если инициализация типизированного
свойства была отменена. Это может вызвать неожиданое поведение, если свойство содержит
значение при инициализации. Чтобы избежать этого, убедитесь, что все свойства инициалищированы
до их валидации.
Геттеры
Ограничения также могут применяться для того, чтобы вернуть значение метода. Symfony позволяет вам добавлять ограничение к любому публичному методу, имя которого начинается с «get», «is» или «has». В этой книге, подобные методы называются общим словом «геттеры».
Преимуществом этой техники является то, что она позволяет вам валидировать ваш
объект динамично. Например, представьте, что вам нужно убедиться, что поле пароля
не совпадает с именем пользователя (из соображений безопасности). Вы можете
сделать это создав метод isPasswordLegal()
и указав, что этот метод должен
вернуться как true
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// src/Entity/Author.php
namespace App\Entity;
// ...
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
#[Assert\IsTrue(message: 'The password cannot match your first name')]
public function isPasswordSafe(): bool
{
// ... return true or false
}
}
Теперь создайте метод isPasswordLegal()
и добавьте его в нужную вам логику:
1 2 3 4
public function isPasswordSafe(): bool
{
return $this->firstName !== $this->password;
}
Note
Самые внимательные из вас заметили, что префикс геттера («get», «is» или «has») опущен при отображении. Это позволит вам применить ограничение к свойству с таким же именем позже ( или наоборот), не изменяя логики валидации.
Классы
Некоторые ограничения применяются к целому валидируемому классу. Например ограничение Callback (обратный вызов) - это универсальное ограничение, которое применяется к самому классу. Когда этот класс валидируется, методы, указанные ограничением, просто выполняются, что позволяет проводить более избирательную валидацию.
Валидация объекта с наследованием
При валидации объекта, который расширяет другой класс, валидатор автоматически валидирует ограничения, определенные в родительском классе.
Ограничения, определенные в родительских свойствах, будут применяться к дочерним, даже если дочерние свойства переопределяют эти ограничения. Symfony всегда будет объединять родительские ограничения для каждого свойства.
Вы не можете изменить это поведение, но вы можете преодолеть его, определив родительские и дочерние ограничения в разных группах валидации. и затем выбирать соответствующую группу при валидации каждого объекта.
Отладка ограничений
Используйте команду debug:validator
, чтобы перечислить ограничения валидации
данного класса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
$ php bin/console debug:validator 'App\Entity\SomeClass'
App\Entity\SomeClass
-----------------------------------------------------
+---------------+--------------------------------------------------+-----------+------------------------------------------------------------+
| Свойство | Имя | Группы | Опции |
+---------------+--------------------------------------------------+-----------+------------------------------------------------------------+
| firstArgument | Symfony\Component\Validator\Constraints\NotBlank | по | [ |
| | | умолчанию | "message" => "This value should not be blank.", |
| | | | "allowNull" => false, |
| | | | "normalizer" => null, |
| | | | "payload" => null |
| | | | ] |
| firstArgument | Symfony\Component\Validator\Constraints\Email | по | [ |
| | | умолчанию | "message" => "This value is not a valid email address.", |
| | | | "mode" => null, |
| | | | "normalizer" => null, |
| | | | "payload" => null |
| | | | ] |
+---------------+--------------------------------------------------+---------+------------------------------------------------------------+
Вы также можете валидировать все классы, хранящиеся в данном каталоге:
1
$ php bin/console debug:validator src/Entity
Заключение
Validator
Symfony - это мощный инструмент, который используется для получения
гарантий, что данные некоторого объекта "валидные". Сила валидации - в ограничениях,
которые являются правилами, которые вы можете применить к свойствам или геттер-методам
вашего объекта. И несмотря на то, что вы большей частью будете использовать фреймворк
валидации косвенно при использовании форм, помните, что он может быть использован
где угодно для валидации любого объекта.
Узнайте больше
- Как создать пользовательское ограничение валидации
- Как применить только подмножество всех ваших ограничений валидации (группы валидации)
- Как валидировать необработанные значения (скалярные значения и массивы)
- Как применять группы валидации последовательно
- Как справляться с разными уровнями ошибок
- Как переводить сообщения ограничений валидации