Symfony2: File Upload via Doctrine does not fire the PrePersist/PreUpdate lifecycle-event

StackOverflow https://stackoverflow.com/questions/7307823

  •  26-10-2019
  •  | 
  •  

Question

i tried to implement the file upload via doctrine/lifecycle callbacks as described here:

http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html#using-lifecycle-callbacks

So far it works, but the PrePersist/PreUpdate Event is not fired, the function "preUpload" is not called. Functions like "upload" and "removeUpload" triggered by other lifecycle events are called correctly.

Does anyone have an idea why the event is not fired or a solution for this problem?

Thanks

Was it helpful?

OTHER TIPS

I have another solution to this problem:

My entity has a field "updatedAt" which is a timestamp of the last update. Since this field gets set anyway (by the timestampable extension of Gedmo) I just use this field to trick doctrine into believing that the entitiy was updated. Before I persist the entity I set this field manually doing

if( $editForm['file']->getData() )
    $entity->setUpdateAt(new \DateTime());

This way the entity gets persisted (because it has changed) and the preUpdate and postUpdate functions are called properly. Of course this only works if your entity has a field that you can exploit like that.

there's a much simpler solution compared with changing tracking policies and other solutions:

in controller:

if ($form->isValid()) {
    ...
    if ($form->get('file')->getData() != NULL) {//user have uploaded a new file
        $file = $form->get('file')->getData();//get 'UploadedFile' object
        $news->setPath($file->getClientOriginalName());//change field that holds file's path in db to a temporary value,i.e original file name uploaded by user
    }
    ...
}

this way you have changed a persisted field (here it is path field), so PreUpdate() & PostUpdate() are triggered then you should change path field value to any thing you like (i.e timestamp) in PreUpdate() function so in the end correct value is persisted to DB.

A trick could be to modify the entity no matter what..on postLoad.


1 Create an updatedAt field.

/**
 * Date/Time of the update
 *
 * @var \Datetime
 * @ORM\Column(name="updated_at", type="datetime")
 */
private $updatedAt;

2 Create a postLoad() function that will modify your entity anyway:

/**
 * @ORM\PostLoad()
 */
public function postLoad()
{
    $this->updatedAt = new \DateTime();
}

3 Just update that field correctly on prePersist:

/**
 * @ORM\PrePersist()
 * @ORM\PreUpdate()
 */
public function preUpload()
{
    $this->updatedAt = new \DateTime();
    //...update your picture
}

This is basically a slight variation of @philipphoffmann's answer: What i do is that i modify an attribute before persisting to trigger the preUpdate event, then i undo this modification in the listener:

$entity->setToken($entity->getToken()."_tmp");
$em->flush();

In my listener:

public function preUpdate(LifecycleEventArgs $args)
{
    $entity = $args->getEntity();

    if ($entity instanceof MyEntity) {
      $entity->setToken(str_replace('_tmp', '', $entity->getToken()));
      //...
    }
}

Another option is to display the database field where the filename is stored as a hidden input field and when the file upload input changes set that to empty so it ends up triggering doctrine's update events. So in the form builder you could have something like this:

->add('path', 'text', array('required' => false,'label' => 'Photo file name', 'attr' => array('class' => 'invisible')))
 ->add('file', 'file', array('label' => 'Photo', 'attr' => array('class' => 'uploader','data-target' => 'iddp_rorschachbundle_institutiontype_path')))

Path is a property managed by doctrine (equal to the field name in the db table) and file is the virtual property to handle uploads (not managed by doctrine). The css class simply sets the display to none. And then a simple js to change the value of the hidden input field

$('.uploader').change(function(){
        var t = $(this).attr('data-target');
        //clear input value
        $("#"+t).val('');
 });

For me, it worked good when I just manually called these methods in the controller.

Do you have checked your metadata cache driver option in your config.yml file?
If it exists, just try to comment this line:

metadata_cache_driver: whateverTheStorage

Like this:

#metadata_cache_driver: whateverTheStorage
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top