Symfony -- Валидация данных. Способы

Синтаксис для любых способов валидации и всевозможные правила (размер данных, их наличие, соответствие регулярному выражению, формат данных и др.) можно найти в официальной документации Symfony, здесь.

Основная статья по валидации здесь.

Способы валидации данных в Symfony:

  1. Валидация с помощью аннотаций в Entity.

    • Выглядит так:
      // src/AppBundle/Entity/Author.php
      use Symfony\Component\Validator\Constraints as Assert;
      
      class Author
      {
          /**
           * @Assert\NotBlank()
           * @Assert\Length(
           *      min = 2,
           *      max = 50,
           *      minMessage = "Your first name must be at least {{ limit }} characters long",
           *      maxMessage = "Your first name cannot be longer than {{ limit }} characters"
           * )
           */
          public $name;
      }
    • Чтобы заработало, необходимо скорректировать способ валидации в config.yml:
      # app/config/config.yml
      framework:
          validation: { enable_annotations: true }
    • Так вывод ошибок может выглядеть в шаблоне Twig:
      <ul>
      {% for error in errors %}
          <li>{{ error.message }}</li>
      {% endfor %}
      </ul>
  2. Валидация при создании формы (добавляем атрибут 'constraints')

    • public function buildForm(FormBuilderInterface $builder, array $options)
      {
          $builder
              ->add('myField', TextType::class, [
                  'required' => true,
                  'constraints' =>[
                        new Length([
                             'min' => 3,
                        ]),
                        new Regex([
                              'pattern'=> "/^0[0-9]{8}$/x"
                        ]),
                   ],
              ]);
      }
    • Не забудьте объявить использование классов констрантов в файле создания формы:
      use Symfony\Component\Validator\Constraints\Length;
      use Symfony\Component\Validator\Constraints\Regex;
  3. Валидация в конфигурационных файлах и валидационные группы.

  4. Создание собственного класса - валидатора.

    • Создаём диркторию AppBundle/Validation и в ней абстрактный класс AbstractValidator(), который подключает стандартный ValidatorInterface и будет служить основой для валидации любых форм проекта:
      <?php
      
      namespace AppBundle\Validation;
      
      use Symfony\Component\Validator\Constraints\Collection;
      use Symfony\Component\Validator\Validation;
      use Symfony\Component\Validator\Validator\ValidatorInterface;
      
      abstract class AbstractValidator
      {
          /**
           * 
           * @var ValidatorInterface
           */
          private $validator;
      
          /**
           *
           */
          public function __construct()
          {
              $this->validator = Validation::createValidator();
          }
      
          /**
           * Возвращает правила валидации
           *
           * @return Collection
           */
          abstract protected function getConstraint(): Collection;
      
          /**
           * Валидирует данные и возвращает массив с ошибками (или пустой массив, если ошибок нет)
           *
           * @param array $requestFields
           *
           * @return array
           */
          public function validate(array $requestFields): array
          {
              $errors = [];
      
              foreach ($this->validator->validate($requestFields, $this->getConstraint()) as $violation){
                  $field = preg_replace(['/\]\[/', '/\[|\]/'], ['.', ''], $violation->getPropertyPath());
                  $errors[$field] = $violation->getMessage();
              }
      
              return $errors;
          }
      }
    • Для любой формы проекта создаём новый класс, расширяющий AbstractValidator(), переопределяем getConstraint():
      <?php
      
      namespace AppBundle\Validation;
      
      use Symfony\Component\Validator\Constraints as Assert;
      use Symfony\Component\Validator\Constraints\Collection;
      
      class AuthorizationValidator  extends AbstractValidator
      {
          /**
           * Возвращает список полей с правилами валидации
           *
           * @return Collection
           */
          protected function getConstraint(): Collection
          {
              return new Collection([
                  // здесь перечисляем имена полей, которые ожидаем для валидации
                  'phone' => $this->getPhoneRules(),
                  'code' => $this->getCodeRules(),
              ]);
          }
          
          /**
           * Возвращает текст сообщения об ошибке не заполненого поля
           *
           * @return string
           */
          private function getMessageForNotBlank(): string 
          {
              return 'Поле обязательно к заполнению';
          }
      
          /**
           * Возвращает правила валидации для данных введённых в строку поиска
           *
           * @return array
           */
          private function getPhoneRules(): array 
          {
              return [
                  new Assert\NotBlank([
                      'message' => $this->getMessageForNotBlank(),
                  ]),
                  new Assert\Regex([
                      'pattern' => "/^\+79\d{9}$/",
                      'message' => 'Вы пытаетесь ввести недопустимые символы. Введите номер телефона в формате +7**********',
                  ]),
              ];
          }
          
          /**
           * Возвращает правила валидации для данных введённых в строку поиска
           *
           * @return array
           */
          private function getCodeRules(): array
          {
              return [
                  new Assert\Regex([
                      'pattern' => "/^[0-9]{4}*$/u",
                      'message' => 'Вы пытаетесь ввести недопустимые символы. Введите четырёхзначный код.',
                  ]),
              ];
          }
      }
    • В контроллере валидация выглядит так:
       // Валидируем данные, введённые пользователем
          $errors = (new AuthorizationValidator())->validate($request->request->all());
              
          if (!empty($errors)) {
              throw new ValidatorException('Введённые данные некорректны: ' . implode('; ', $errors));
          }
  5. Источники