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

Doctrine orm Symfony2:通过条令上传文件不会触发PrePersist/PreUpdate生命周期事件,doctrine-orm,symfony,Doctrine Orm,Symfony,我尝试通过条令/生命周期回调实现文件上传,如下所述: 到目前为止,它还可以工作,但是没有触发PrePersist/PreUpdate事件,也没有调用函数“preUpload”。 由其他生命周期事件触发的“upload”和“removeUpload”等函数被正确调用 是否有人知道事件为何未被触发或此问题的解决方案 谢谢你需要 另一个选项是显示数据库字段,其中文件名存储为隐藏输入字段,当文件上载输入更改时,将其设置为空,以触发doctrine的更新事件。因此,在form builder中,您可以有

我尝试通过条令/生命周期回调实现文件上传,如下所述:

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

是否有人知道事件为何未被触发或此问题的解决方案

谢谢

你需要


另一个选项是显示数据库字段,其中文件名存储为隐藏输入字段,当文件上载输入更改时,将其设置为空,以触发doctrine的更新事件。因此,在form builder中,您可以有如下内容:

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

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

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

我的实体有一个字段“updatedAt”,它是上次更新的时间戳。因为这个字段无论如何都会被设置(通过Gedmo的timestable扩展),所以我只是使用这个字段来欺骗条令,使其相信实体已经更新。 在持久化实体之前,我手动设置此字段

if( $editForm['file']->getData() )
    $entity->setUpdateAt(new \DateTime());
通过这种方式,实体被持久化(因为它已经更改),并且preUpdate和postUpdate函数被正确调用。
当然,这只有在您的实体有一个可以利用的字段时才有效。

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

在控制器中:

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()&postpdate(),然后您应该在PreUpdate()中将路径字段值更改为您喜欢的任何内容(即时间戳)函数,以便最终将正确的值保留到DB。

一个技巧可能是在
postLoad
上修改实体


1创建一个
updatedAt
字段

/**
*更新的日期/时间
*
*@var\Datetime
*@ORM\Column(name=“updated_at”,type=“datetime”)
*/
私人$updatedAt;
2创建一个将修改实体的
postLoad()
函数:

/**
*@ORM\PostLoad()
*/
公共函数postLoad()
{
$this->updatedAt=new\DateTime();
}
3只需在prePersist上正确更新该字段:

/**
*@ORM\PrePersist()
*@ORM\PreUpdate()
*/
公共函数预上载()
{
$this->updatedAt=new\DateTime();
//…更新您的图片
}

对我来说,当我在控制器中手动调用这些方法时,效果很好。

您是否在config.yml文件中检查了元数据缓存驱动程序选项?
如果它存在,请尝试注释这一行:

metadata_cache_driver: whateverTheStorage
像这样:

#metadata_cache_driver: whateverTheStorage

这基本上是@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()));
      //...
    }
}
在我的听众中:

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

我已经用实体中的逻辑提出了类似的解决方案。谢谢你的主意@philipphoffmann