Валідація

Дата оновлення перекладу 2022-12-23

Валідація

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

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 $name;
}

Поки це звичайний клас, який служить якійсь цілі всередині вашого додатку. Задача валідації полягає в тому, щоб повідомити вам - чи є дані об'єкта коректними (валідними). Для цього вам потрібно налаштувати перелік правил (які називаються обмеження ), яким об'єкт має відповідати, щоб бути валідним. Ці правила зазвичай визначаються з використанням PHP-коду, але також можуть бути визначені як файли .yaml або .xml всередині каталогу config/validator/:

Наприклад, для того, щоб гарантувати, що властивість $name не порожня, додайте наступний код:

  • Attributes
  • YAML
  • XML
  • PHP
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 $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)
{
    $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.

Викличні валідації

Validation також дозволяє вам створювати замикання, щоб валідувати значення у відповідності до набору обмежень (корисно, наприклад, при валідації відповідей команд Консолі або при валідації значень OptionsResolver ):

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

Обмеження

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

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

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

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

Дата оновлення перекладу 2022-12-20

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

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

Інші обмеження

Ви також можете створювати власні обмеження. Ця тема охоплена у статті Як створити користувацьке обмеження валідації.

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

Деякі обмеження, як наприклад, NotBlank, прості, у той час як інші, наприклад, Choice, мають декілька опцій конфігурації. Припустимо, що клас Author має властивість genre (жанр), яка визначає жанр літератури, який в основному асоціюється з автором, і яку можна встановити у значення "художня" або "нон-фікшн" ("fiction" або "non-fiction"):

  • Attributes
  • YAML
  • XML
  • PHP
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 $genre;

    // ...
}

Опції обмеження завжди можуть бути передані у вигляді масиву. Однак, деякі обмеження також дозволяють вам передавати значення однієї опції «за замовчуванням» замість масиву. У випадку з обмеженням Choice, опції choices можна вказати таким чином.

  • Attributes
  • YAML
  • XML
  • PHP
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 $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 символи.

  • Attributes
  • YAML
  • XML
  • PHP
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 $firstName;
}

Caution

Валідатор використовуватиме значення null якщо ініціалізація типізованої властивості була відмінена. Це може викликати неочікувану поведінку, якщо властивість містить значення при ініціалізації. Щоб уникнути цього, переконайтеся, що всі властивості ініціалізовані до їхньої валідації.

Гетери

Обмеження також можуть застосовуватися для того, щоб повернути значення методу. Symfony дозволяє вам додавати обмеження до будь-якого публічного методу, ім'я якого починається з «get», «is» або «has». У цій книзі подібні методи називаються загальним словом «гетери».

Перевагою цієї техніке є те, що вона дозволяє вам валідувати ваш об'єкт динамічно. Наприклад, уявіть, що вам потрібно переконатися, що поле пароля не співпадає з іменем користувача (з міркувань безпеки). Ви можете зробити це, створивши метод isPasswordLegal() та вказавши, що цей метод має повернутися як true:

  • Attributes
  • YAML
  • XML
  • PHP
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()
    {
        // ... return true or false
    }
}

Тепер створіть метод isPasswordLegal() та додайте його у потрібну вам логіку:

1
2
3
4
public function isPasswordLegal()
{
    return $this->firstName !== $this->password;
}

Note

Найуважніші з вас помітили, що префікс геттера («get», «is» або «has») опущено при відображенні. Це дозволить вам застосувати обмеження до властивості з таким же ім'ям пізніше (або навпаки), не змінюючи логіку валідації.

Класи

Деякі обмеження застосовуються до цілого валідованого класу. Наприклад, обмеження Callback (зворотний виклик) - це універсальне обмеження, яке застосовується до самого класу. Коли цей клас валідується, методи, вказані обмеженням, просто виконуються, що дозволяє проводити більш вибіркову валідацію.

Налагодження обмежень

Використайте команду 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 - це потужний інструмент, який використовується для отримання гарантій, що дані деякого об'єкта "валідні". Сила валідації - в обмеженнях, які є правилами, які ви можете застосувати до властивостей або геттер-методів вашого об'єкта. І незважаючи на те, що ви більшою мірою використовуватимете фреймворк валідації опосередковано при використанні форм, пам'ятайте, що він може бути використаний де завгодно для валідації будь-якого об'єкта.