Служба валидатора Symfony и ошибки ввода в установщиках

#php #symfony #validation #error-handling

Вопрос:

В настоящее время я сбит с толку тем, как работает служба валидатора Symfony. Насколько я понимаю в настоящее время, он может полностью выйти из строя и не сообщать об ошибках даже до того, как сможет проверить сущность, если при установке значений произойдет ошибка типа.

Документация Symfony использует ограничения в таких сущностях, как эта:

 namespace AppEntity;

// ...
use SymfonyComponentValidatorConstraints as Assert;

class Author
{
    /**
     * @AssertNotBlank
     */
    private $name;
}
 

Которые затем используются подобным образом в контроллерах:

 public function author(ValidatorInterface $validator)
{
    $author = new Author();
    
    // ... do something to the $author object

    $author->setBirthDate('this will fail and not report'); // I added this line in myself, see rest of question.
  

    $errors = $validator->validate($author);

    if (count($errors) > 0) {
        /*
         * Uses a __toString method on the $errors variable which is a
         * ConstraintViolationList object. This gives us a nice string
         * for debugging.
         */
        $errorsString = (string) $errors;

        return new Response($errorsString);
    }

    return new Response('The author is valid! Yes!');
}
 

Однако это не будет хорошо улавливать исключения, которые будут возникать, когда аргументы неправильного типа передаются установщикам переменных сущности. Например, сущность может иметь поле «Дата рождения», которое является датой и временем, и у которого есть задатчик setBirthDate(дата и время $foo). При создании объекта перед вызовом функции validate() можно передать аргумент неправильного типа — скажем, пользователь отправил строку или вообще ничего — что, очевидно, вызовет исключение.

Предполагая, что служба валидатора должна использоваться таким образом, мой вопрос заключается в следующем: как мне аккуратно обрабатывать данные, которые могут вызвать ошибки ввода в установщиках?

Разве я не делаю никаких намеков на тип в своих установщиках (принимая все), а затем подтверждаю, что это дата-время с помощью валидатора позже? Использую ли я блок try/catch при настройке сущности? Должен ли я вручную проверять тип пользовательского ввода перед вызовом сеттера? И если какой-либо из последних двух, как бы я четко сообщил об ошибках пользователю? И даже тогда, я думаю, было бы неправильно также выполнять ручную проверку там, когда вы также делаете это в службе валидатора.

Я знаю о формах и предполагаю, что это не проблема при их использовании, но я все равно нахожу валидатор сбивающим с толку в любом случае.

Ответ №1:

Вы упускаете из виду, как должен работать код, если вы укажете, что установщик будет принимать объект DateTime, а объект DateTime только сам PHP гарантирует, что принятый аргумент является экземпляром объекта DateTime. Один из способов обойти это-создать DTO(объект передачи данных), например. Создайте запрос authorrequest и создайте тип формы symfony, в котором вы принимаете либо строку/время даты(предпочтительно строку, в которой будет регулярное выражение, гарантирующее, что строка является допустимой строкой времени даты). Затем, после вызова $form->isValid()> вы можете прочитать данные из DTO и убедиться, что они действительны. Если вы все еще будете бороться с тем, как это должно быть правильно реализовано, прокомментируйте ниже ответ, и я предоставлю примеры кода

Кроме того, я бы не рекомендовал помещать так много аннотаций в вашу сущность, это довольно быстро приведет к беспорядку, предпочитайте XML-конфигурацию аннотациям.

Комментарии:

1. «если вы укажете, что сеттер будет принимать объект DateTime и объект DateTime только сам PHP гарантирует, что принятый аргумент является экземпляром объекта DateTime». Я осознаю это, я не пытаюсь этого сделать. Проверка объекта DateTime будет выполняться с помощью ограничений Symfony (symfony.com/doc/current/reference/constraints/DateTime.html). Однако проблема заключается в том, что задатчик с намеком на тип вызывается до проверки ограничения. Я попробую использовать формы, но это все равно заставляет меня задуматься, зачем использовать службу валидатора и ограничения для сущностей.

2. Дело в том, что значение сначала устанавливается, а затем проверяется, у меня была аналогичная борьба, когда я впервые попробовал типизированные свойства и типизированные установщики. Лучший обходной путь-это DTO без намеков на тип, хотя такой отстой, вероятно, лучше всего было бы проверить, является ли строка допустимым форматом datetime, а затем сопоставить ее с объектом DateTime и установить в фактической сущности

3. Я чувствую, что вы бы проверяли в двух местах без DTO. Это не только время, но и сеттеры, которым требуются целые числа, а что нет. В основном в каждой области. Вы также потеряете удобные отчеты об ошибках форм/службы валидатора, и вам придется обрабатывать их отдельно, не так ли? Хотя формы также принимают массивы вместо сущностей, так что, возможно, вы могли бы пропустить DTO и просто добавить тело запроса? Разве это не практически одно и то же (в небольшом приложении)? Спасибо, что указали на это. Хотя я все еще не понимаю идею службы валидатора, она не выглядит практичной.