Валідація

Дата оновлення перекладу 2024-06-10

Валідація

Валідація - це дуже розповсюджена задача для веб-додатку. Дані, які вводяться у форми, мають бути валідовані (перевірені). У той же час, дані мають бути валідовані до того, як вони будуть записані в базу даних або ж передані веб-сервісу.

Symfony містить компонент Validator, який спрощує цю задачу. Цей компонент заснований на документі специфікація валідації JSR303 Bean.

Установка

В додатках, які використовують Symfony Flex , виконайте цю команду, щоб встановити валідатор перед його використанням:

1
$ composer require symfony/validator doctrine/annotations

Note

Якщо ваш застосунок не використовує Symfony Flex, вам може знадобитися створити деяку конфігурацію вручну, щоб підключити валідацію. Перегляньте довідник конфігурації Валідації .

Основи валідації

Найкращий спосіб зрозуміти валідацію - це побачити її в дії. Спочатку, припустимо, що ви створили звичайний PHP об'єкт, який вам потрібно використати у вашому додатку:

1
2
3
4
5
6
7
// src/Entity/Author.php
namespace App\Entity;

class Author
{
    private string $name;
}

Поки це звичайний клас, який служить якійсь цілі всередині вашого додатку. Задача валідації полягає в тому, щоб повідомити вам - чи є дані об'єкта коректними (валідними). Для цього вам потрібно налаштувати перелік правил (які називаються обмеження ), яким об'єкт має відповідати, щоб бути валідним. Ці правила зазвичай визначаються з використанням 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, а такод методи "геттера", щоб отримати значення будь-якої властивості; вони можуть бути публичними, приватними або захищеними (див. ).

Використання сервісу валідаторa

Далі, щоб перевірити об'єкт 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();

    // ... зрробити щось з обʼєктом $author
    
    $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 також дозволяє вам створювати замикання, щоб валідувати значення у відповідності до набору обмежень (корисно, наприклад, при валідації відповідей команд Консолі або при валідації значень OptionsResolver ):

createCallable()
Повертає замикання, яке викликає ValidationFailedException, коли обмеження не співпадають.
createIsValidCallable()
Викликає замикання, яке повертає false, коли обмеження не співпадають.

Обмеження

Validator створений для того, щоб перевіряти об'єкти на відповідність обмеженням (тобто правилам). Для того щоб валідувати об'єкт, просто вкажіть для його класу одне або декілька обмежень та передайте його сервісу валідації (validator).

За лаштунками, обмеження - це просто PHP-об'єкт, який виконує ствердний вираз. У реальному житті, обмеження може виглядати так: "пиріг не має згоріти". У Symfony обмеження виглядають схоже: це твердження, що деяка умова є істиною. Враховуючи значення, обмеження скаже вам, чи відповідає це значення правилам обмеження.

Підтримувані обмеження

Symfony містить велику кількість найнеобхідніших обмежень:

Дата оновлення перекладу 2024-05-29

Базові обмеження

Це базові обмеження: використовуйте їх, щоб ствердити дуже базові речі про значення властивостей, або повернути значення методів у вашому обʼєкті.

Конфігурація обмежень

Деякі обмеження, як наприклад, 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): void
{
    $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" => "Це значення не має бути порожнім.",          |
    |               |                                                  |               |   "allowNull" => false,                                    |
    |               |                                                  |               |   "normalizer" => null,                                    |
    |               |                                                  |               |   "payload" => null                                        |
    |               |                                                  |               | ]                                                          |
    | firstArgument | Symfony\Component\Validator\Constraints\Email    | за            | [                                                          |
    |               |                                                  | замовчуванням |   "message" => "Це значення не валідна адреса email.", |
    |               |                                                  |               |   "mode" => null,                                          |
    |               |                                                  |               |   "normalizer" => null,                                    |
    |               |                                                  |               |   "payload" => null                                        |
    |               |                                                  |               | ]                                                          |
    +---------------+--------------------------------------------------+---------------+------------------------------------------------------------+

Ви також можете валідувати всі класи, що зберігаються у даному каталозі:

1
$ php bin/console debug:validator src/Entity

Висновки

Validator Symfony - це потужний інструмент, який використовується для отримання гарантій, що дані деякого об'єкта "валідні". Сила валідації - в обмеженнях, які є правилами, які ви можете застосувати до властивостей або геттер-методів вашого об'єкта. І незважаючи на те, що ви більшою мірою використовуватимете фреймворк валідації опосередковано при використанні форм, пам'ятайте, що він може бути використаний де завгодно для валідації будь-якого об'єкта.