mystack
mystack

Reputation: 75

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

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

Upvotes: 2

Views: 7110

Answers (8)

Youssef
Youssef

Reputation: 1043

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()));
      //...
    }
}

Upvotes: 1

Pierre Marichez
Pierre Marichez

Reputation: 218

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

Upvotes: 0

Esenbek Kydyr uulu
Esenbek Kydyr uulu

Reputation: 1623

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

Upvotes: 0

Mick
Mick

Reputation: 31949

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
}

Upvotes: 4

sepehr
sepehr

Reputation: 5749

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.

Upvotes: 4

philipphoffmann
philipphoffmann

Reputation: 785

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.

Upvotes: 10

scc
scc

Reputation: 10706

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('');
 });

Upvotes: 0

Inoryy
Inoryy

Reputation: 8425

You need to change tracking policies.

Full explanation.

Upvotes: 6

Related Questions