Symfony2:通过Doctrine上传文件不会触发PrePersist / PreUpdate生命周期事件

时间:2011-09-05 12:06:09

标签: doctrine-orm symfony

我尝试通过doctrine / lifecycle回调实现文件上传,如下所述:

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

到目前为止它可以工作,但PrePersist / PreUpdate事件没有被触发,函数“preUpload”没有被调用。 正确调用由其他生命周期事件触发的“upload”和“removeUpload”等函数。

有没有人知道为什么没有触发事件或解决这个问题?

由于

8 个答案:

答案 0 :(得分:10)

我有另一个解决这个问题的方法:

我的实体有一个字段“updatedAt”,它是上次更新的时间戳。由于这个字段无论如何都被设置(通过Gedmo的时间戳扩展)我只是使用这个字段来欺骗教义,使其相信权利被更新了。 在我坚持实体之前,我手动设置此字段

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

这样实体就会被持久化(因为它已经改变了),并且正确调用了preUpdate和postUpdate函数。 当然,这仅适用于您的实体具有可以像这样利用的字段。

答案 1 :(得分:6)

答案 2 :(得分:4)

与更改跟踪政策和其他解决方案相比,这是一个更简单的解决方案:

控制器中的

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
    }
    ...
}

这样你就改变了一个持久化字段(这里是路径字段),所以PreUpdate()&触发PostUpdate()然后您应该在PreUpdate()函数中将路径字段值更改为您喜欢的任何内容(即时间戳),以便最终将正确的值保存到DB。

答案 3 :(得分:4)

一个技巧可能是修改实体,无论是什么...... postLoad


1 创建一个updatedAt字段。

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

2 创建一个postLoad()函数,无论如何都会修改你的实体:

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

3 只需在prePersist上正确更新该字段:

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

答案 4 :(得分:1)

这基本上是@ philipphoffmann回答的一个小变化: 我所做的是在持久触发preUpdate事件之前修改属性,然后在侦听器中撤消此修改:

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

在我的听众中:

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

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

答案 5 :(得分:0)

另一个选项是显示数据库字段,其中文件名存储为隐藏输入字段,当文件上载输入更改设置为空时,它最终触发doctrine的更新事件。所以在表单构建器中你可以有这样的东西:

->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是由doctrine管理的属性(等于db表中的字段名称),file是处理上载的虚拟属性(不是由doctrine管理)。 css类只是将显示设置为none。然后是一个简单的js来改变隐藏输入字段的值

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

答案 6 :(得分:0)

对我来说,当我在控制器中手动调用这些方法时,它工作得很好。

答案 7 :(得分:0)

您是否在config.yml文件中检查了元数据缓存驱动程序选项?
如果存在,只需尝试对此行进行注释:

metadata_cache_driver: whateverTheStorage

像这样:

#metadata_cache_driver: whateverTheStorage