Долго мы мудохались (по другому не скажу) с парой-тройкой багов, которые полезли в результате использования VichUploaderBundle. И главное мы к ним возвращались по 2-3 раза на разных проектах за последние полгода :).
Symfony’s form component cleanup
Наименее костыльное решение предложили здесь. Чтобы постоянно не прописывать data_class в формах я добавил его в DefaultOptions для FileType и отправил PR в Symfony2. Чуть позже доделаем тесты и думаю PR примут.
The file is not updated if there are not other changes in the entity
Это хитрый баг, который возникает когда в форме меняется только файл. Словили его когда решили обновить логотип для спонсора на http://fwdays.com. Сегодня я выделил время на дебаг и понял, что нормальным путем проблему не решить. Смотрите сами:
... // биндим данные на форму // - запускаем дата трансформеры // - дергаем сеттеры сущности (setFile и др.) $form->bind($request); // валидируем форму // в $file должен быть объект загружаемого файла (UploadableField), чтобы пройти валидацию if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); // готовим сущность к сохранению в БД // вычисляется хеш объекта и определяется его состояние (новый, обновленный и т.д.) // здесь дергается хук preUpdate (обновление) или prePersist (новая сущность) и файл физически перемещается в место назначения, но // !! если нужно просто обновить файл, то проблема т.к. имя файла (которое хранится в БД) ещё не изменилось, а preUpdate запускается только если в сущности есть изменения !! $em->persist($entity); // сохранение данных $em->flush(); ... |
Получается, что нужно зааплоадить новый файл и засетить его имя в сущность до того как отправить сущность в persist() менеджера сущностей. Иначе Doctrine не видит изменений в сущности, не дергает хук preUpdate и аплоад средствами VichUploaderBundle не происходит :(.
Спасает костыль от автора бандла, который предлагает делать в сущности поле updatetAt и обновлять его если в сеттер файла приходит что-то новенькое:
public function setFile($file) { $this->file = $file; if ($file instanceof UploadedFile) { $this->setUpdatedAt(new \DateTime()); } } |
Как-то так 🙂