#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 и просто добавить тело запроса? Разве это не практически одно и то же (в небольшом приложении)? Спасибо, что указали на это. Хотя я все еще не понимаю идею службы валидатора, она не выглядит практичной.