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