Symfony Валидация модели в Symfony

Enxiro

Новичок
Привет.
Я новичек в Симфони. Судя по руководствам можно описать правила валидации для Entity и проверять в контроллере вот так:
Код:
    $validator = $this->get('validator');
    $errors = $validator->validate($job);

    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);
    }
Но если сущность создается при помощи формы, то предлагают описать валидаторы непосредственно для формы и проверять ее в контроллере так:

Код:
        $entity  = new Job();
        $request = $this->getRequest();
        $form = $this->createForm(new JobType(), $entity);
        $form->submit($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();

            $em->persist($entity);
            $em->flush();
       }
Вопросы:
Почему при вызове persist не вызываются валидаторы для Entity? ведь во втором примере может сложиться ситуация что скажем я неправильно описал валидаторы для формы, или забыл какое-то поле в форме вывести, а оно у меня по логике приложения обязательное.
Да и вообще зачем мне 2 раза описывать одни и те же правила валидации сперва для Entity а потом для Формы?
Нашел кстати пример где можно навешать на события PrePersist и PreUpdate вызов валидации и в случае ошибки выкидывать исключение. Но правильно ли внедрить такую логику или где-то встречусь с подводными камнями?
 

keltanas

marty cats
Почему при вызове persist не вызываются валидаторы для Entity?
Потому что ORM - это ORM, а валидатор - это валидатор. Ты же не удивляешься, почему дворники не моют припаркованые во дворе автомобили, даже если они грязные?
ведь во втором примере может сложиться ситуация что скажем я неправильно
А тесты тебе для чего?
Да и вообще зачем мне 2 раза описывать одни и те же правила валидации
Хороший вопрос! Кто тебе сказал, что их нужно 2 раза описывать?
Нашел кстати пример где можно навешать на события PrePersist и PreUpdate вызов валидации и в случае ошибки выкидывать исключение.
Что ты будешь делать с этими правилами, если тебе надо сохранить объект с неполными данными, например, через крон?
 

AmdY

Пью пиво
Команда форума
если нужно частично валидировать, для этого есть validation_groups

Вроде валидация модельки должна подхватиться, а покажи свой JobType
 

Вурдалак

Продвинутый новичок
Бизнес-логика всякая бывает. Что разрешено системе, не всегда разрешено пользователю.
Значит, с точки зрения бизнес-логики такая модель всё-таки валидная.

Двойная валидация — это нормально. Одна валидация должна быть на уровне самой модели, вторая — проверяет пользовательские запросы. И эти две валидации потому разные, что они независимы друг от друга, что-то, что не дозволено пользователю, может быть в принципе дозволено моделью, как ты сам и заметил.

Другое дело, что использовать тот же Symfony Validator, да ещё и навешивать на PrePersist/PreUpdate я бы не стал, лучше заюзать что-то типа https://github.com/beberlei/assert
PHP:
final class Job
{
    public function rename(string $newName)
    {
        Assert::betweenLength($newName, 1, 100);

        // ...
    }
}
Но это ведёт к другому стилю разработки, что существенно отличается от мануала.
 

AmdY

Пью пиво
Команда форума
В symfony всё точно также, только ассерты записываются через аннотацию, а вместо функций указывается groups
PHP:
class User implements UserInterface
{
    /**
     * @Assert\NotBlank
     */
    private $username;

    /**
     * @Assert\NotBlank
     */
    private $password;

    /**
     * @Assert\IsTrue(message="The password cannot match your username", groups={"Strict"})
     */
    public function isPasswordLegal()
    {
        return ($this->username !== $this->password);
    }
}
 

keltanas

marty cats
Другое дело, что использовать тот же Symfony Validator, да ещё и навешивать на PrePersist/PreUpdate я бы не стал, лучше заюзать что-то типа https://github.com/beberlei/assert
Конечно, программист должен знать, что он пишет в модель :)

@AmdY, такая валидация скорее, чтобы было проще показывать юзеру, где он не прав. Если модель сохраняется не через веб, ошибки показывать будет некому, а логировать это как критикал - тоже вопрос спорный.
А если валидация зафейлилась в PrePersist.. я уже не знаю, что в этом случае делать. Тут мы совершенно не знаем, в каком окружении находимся. Кидать экзепшен тоже странно. Вызывали мы UoW, а экзепшен получили от какого-то лисенера при обработке какой-то сущности. И каждый раз вызывая $uow->persist() придется ловить в нем ошибки, никак не связанные с персистенцией.
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
@keltanas,
Так что-то типа berberlei/assist зафейлится намного раньше.

А вообще...
Имел немного дело с проектом на sf2, написанном вот прямо по мануалам на симфони.
Не понимаю, чем это лучше laravel с AR. Те же анемики, никакого ООП по сути, модели - "структуры", сервисы - "процедуры", только с умным видом. На ларавеле хоть вид не надо умный делать, пишем ХХП - сразу видно.
 

keltanas

marty cats
@fixxxer, судя по впоросам про симфони, которые задают на тостере, да и здесь тоже, я не удивлен. При чем пишут на симфони, а делают по мануалам от йии или ларавеля, ага.
Про berberlei/assist - я не писал, что надо делать именно так ))
 

keltanas

marty cats
@fixxxer, уел. Давай откроем тред: "5 лучших способов загружать файлы на Symfony" и напишем там свою документацию с трамбоном и скрипками.
 

keltanas

marty cats
@fixxxer, но ее можно сделать по разному в зависимости от того, что за проект, какие к нему требования, как будет организовано взаимодействие с пользователем, какая посещалка, в каком количестве объектов планируется использовать загруженный файл, какую пост-обработку планируется над ним совершить, где планируется его хранить, как быстро надо сделать, как долго его планируется поддерживать и какой бюджет на все это имеется ))
Понимая что ты это понимаешь я не могу воспринимать твой вопрос иначе, чем сарказм ))
 

fixxxer

К.О.
Партнер клуба
Так вообще можно про всё сказать :)
Я вот ровно про ту задачу, которая в этом древнем кукбуке.
 

keltanas

marty cats
@fixxxer, я бы вообще не стал загружать файлы через доктрину, или обрабатывать их по событиям доктрины ))
Загрузка и обработка файлов - это вообще никак не связано с ORM.
Мухи отдельно, котлеты отдельно.
 

fixxxer

К.О.
Партнер клуба
Загрузка файлов с ORM не связана, это я полностью согласен.
Вопрос в том, как будет организован код, если у нас вот тот самый Document entity и
1) нужно хранить оригинальное имя файла
2) для генерации "внутреннего" имени файла надо знать document.id
 
Сверху