Як послідовно застосовувати групи валідації

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

Як послідовно застосовувати групи валідації

У деяких випадках, вам буде потрібно валідувати ваші групи покроково. Щоб зробити це, ви можете використати функцію GroupSequence. У цьому випадку, обʼєкт визначає групову послідовність, яка визначає порядок, в якому потрібно валідувати групи.

Наприклад, уявіть, що у вас є клас User, і ви хочете валідувати, чи відрізняються імʼя користувача та пароль лише у випадку, якщо решта валідації пройде успішно (щоб уникнути багатьох повідомлень про помилку).

  • Attributes
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/Entity/User.php
namespace App\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;

#[Assert\GroupSequence(['User', 'Strict'])]
class User implements UserInterface
{
    #[Assert\NotBlank]
    private $username;

    #[Assert\NotBlank]
    private $password;

    #[Assert\IsTrue(
        message: 'Пароль не може співпадати з вашим іменем користувача',
        groups: ['Strict'],
    )]
    public function isPasswordSafe()
    {
        return ($this->username !== $this->password);
    }
}

У цьому прикладі, спочатку будуть валідовані всі обмеження в групі User (що те ж саме, що і група Default). Лише якщо всі обмеження у цій групі будуть валідні, буде валідована друга група Strict.

Caution

Як ви вже бачили в Як застосувати лише підмножину усіх ваших обмежень валідації (групи валідації), група Default і група, що містить імʼя класу (наприклад, User) були ідентичні. Однак, при використанні групової послідовності, вони більше не будуть ідентичними. Група Default тепер посилатиметься на групову послідовність замість всіх обмежень, які не належать жодній групі.

Це означає, що вам потрібно використати групу {ClassName} (наприклад, User) при вказанні групової послідовності. При використанні Default ви отримаєте нескінченну рекурсію (так як група Default посилається на групову послідовність, яка містить групу Default, яка посилається на ту ж групову послідовність...).

Caution

Виклик validate() з групою у послідовності (Strict у попередньому прикаді) призведе до валідації лише з цією групою, а не з усіма групами у послідовності. Тому що послідовність тепер спрямована до групової валідації Default.

Ви також можете визначити групову послідовність в опції форми validation_groups:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Form/MyType.php
namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\GroupSequence;
// ...

class MyType extends AbstractType
{
    // ...
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'validation_groups' => new GroupSequence(['First', 'Second']),
        ]);
    }
}

Постачальники групової послідовності

Уявіть сутність User, яка може бути нормальним або преміум користувачем. Якщо це преміум користувач, необхідно додати деякі додаткові обмеження до сутності користувача (наприклад, інформацію про кредитну картку). Щоб динамічно визначити, які групи варто активувати, ви можете створити постачальника групової послідовності. Спочатку створіть сутність та нову групу обмежень під назвою Premium:

  • Attributes
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Entity/User.php
namespace App\Entity;

use Symfony\Component\Validator\Constraints as Assert;

class User
{
    #[Assert\NotBlank]
    private $name;

    #[Assert\CardScheme(
        schemes: [Assert\CardScheme::VISA],
        groups: ['Premium'],
    )]
    private $creditCard;

    // ...
}

Тепер змініть клас User, щоб реалізувати GroupSequenceProviderInterface та додайте метод getGroupSequence(), який має повернути масив груп для використання:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/Entity/User.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\GroupSequenceProviderInterface;

class User implements GroupSequenceProviderInterface
{
    // ...

    public function getGroupSequence(): array|GroupSequence
    {
        // при поверненні простого масиву, якщо в будь-якій групі є порушення,
        // решта груп не валідується. Наприклад, якщо 'User' зазнає невдачі,
        // 'Premium' та 'Api' не валідуються:
        return ['User', 'Premium', 'Api'];

        // при поверненні вкладеного масиву, всі групи, включені у кожний масив,
        // валідуються. Наприклад, якщо 'User' зазнає невдачі, 'Premium' також валідується
        // (і ви отримаєте і його порушення), але 'Api' не буде валідовано:
        return [['User', 'Premium'], 'Api'];
    }
}

Нарешті, вам потрібно повідомити компонент Validator про те, що ваш клас User нада послідовність груп для валідації:

  • Attributes
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
// src/Entity/User.php
namespace App\Entity;

// ...

#[Assert\GroupSequenceProvider]
class User implements GroupSequenceProviderInterface
{
    // ...
}

Як послідовно застосовувати обмеження в одній властивості

Індові вам може захотітися застосувати обмеження послідовно в одній властивості. Обмеження Sequentially може вирішити це за вас простішим способом, ніж використання GroupSequence.