VichUploaderBundle
VichUploaderBundle copied to clipboard
Upload is not performed if there is no change in the entity
When using doctrine, event listeners are not called if there have been no column changed. It's a problem because we precisely depend on these events to be fired to handle the uploads.
Right now, we use some boilerplate code to artificially trigger a change in the entity whenever a file is uploaded (by updating the created_at
column for instance).
I'd like to find an other way to fix this issue.
I personnaly use FormEvents to achieve this change automatically.
Example:
class ApplicationType extends AbstractType
{
...
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('icon', 'file', array(
'required' => false,
));
$builder->get('icon')->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $e){
if(!empty($e->getData())){
/** @var Application $app */
$app = $e->getForm()->getParent()->getData();
$app->setUpdateAt(new \DateTime());
}
});
}
...
}
This code simply checks if the icon
field has data. Then, updates the target entity if needed.
I guess it will be possible to consider the creation of a dedicated form type vich_file
or else, which would be responsible for update a user configurable entity field via the field options form. These option could be named update_property
for instance.
Another and complementary form type could also check if the form entity implements a given interface, in charge to update the updatedAt
field when the interface method is called. Therefore, no more configuration is needed from user.
The thing is I don't want to rely on this kind of "hack". We should not have to ask the user to write boilerplate code/implement an interface/add a "updated at" field.
if we use update date in entity setter as in example
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTime('now');
}
}
this is execute in each time where entity is loaded. if after call $em->flush() updatedAt field will be updated in db - one query for each entity. it generate 1000+ queries in my db in some controllers where many entities loaded and call "flush".
@rik43 you must check if File is an UploadedFile. See https://github.com/dustin10/VichUploaderBundle/issues/8#issuecomment-3780172
good idea, thanks
Is there a chance you fix this issue one day ?
Reproduced using :
- vich/uploader-bundle : 1.16.0
- symfony : 5.0.11
- php : 7.4.13
Is there a chance you fix this issue one day ?
This is the wrong question. The right question is: is there a chance we fix this issue one day?
Ok, but this issue was opened 5 years ago...
I you (we) don't manage to fix it, maybe you (we) should change this part of documentation :
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile|null $imageFile
*/
@acantepie it's already documented just 4 lines after
just ran into this issue.
bundle version: 1.19.1 symfony version: 5.4.8
wanting to add in that if the update/created blamable/timestampable values are managed by something like doctrine extensions, that is not enough to trigger the uploader/clean-listener.
ended up making a "dummy" column in the table to just always update as part of the request processing
$formAttachment->setMetadata(uniqid('kittens', true));
wanting to add in that if the update/created blamable/timestampable values are managed by something like doctrine extensions, that is not enough to trigger the uploader/clean-listener.
That's probably a matter of priority in Doctrine listeners
Hi, I want to add a comment after having been through the issue of file not uploaded for new entity. It may affect you if you're using translatable in any of the field on the entity. After further checking it seems that translatable will trigger a persist early on the form lifecycle (the $form->handleRequest()
call) with the uploaded file not being set on the entity yet. And when I call $entityManager->persist($object)
the prePersist
code from this bundle will not be called (I assume because it have been called in the handleRequest()
call. So what I do is I add the code $uploadHandler->upload($object, 'file')
before $entityManager->persist($object) to trigger it manually. Of course these only works if you're in the same situation like me. Just for reference for others. Thanks!