带有文件类型字段editAction的Symfony 3表单集合实体

Posted

技术标签:

【中文标题】带有文件类型字段editAction的Symfony 3表单集合实体【英文标题】:Symfony 3 form collection entity with filetype field editAction 【发布时间】:2017-08-17 08:23:00 【问题描述】:

当存在具有 fileType 字段的实体集合时,如何正确处理表单更新。我根据 Symfony upload docs。实体创建工作完美,但编辑操作失败,因为没有选择文件并且 symfony 尝试使用文件字段上的空值更新集合实体。

AppBundle\Entity\Product:
    type: entity
    # ...
    oneToMany:
        images:
            targetEntity: Image
            mappedBy: product

表格:

// AppBundle\Form\ProductType
public function buildForm(FormBuilderInterface $builder, array $options)

    $builder
        // ...
        ->add(
            'images',
            CollectionType::class,
            [
                'entry_type'    => ImageType::class,
                'allow_add'     => true,
                'allow_delete'  => true,
                'by_reference'  => false,
                'entry_options' => ['label' => false],
                'label_attr'    => [
                    'data-feature' => 'editable',
                ],
            ]
        );


// AppBundle\Form\ImageType   
public function buildForm(FormBuilderInterface $builder, array $options)

    $builder
        ->add('file', FileType::class, ['required' => false])
        // another fields...

行动:

// AppBundle\Controller\Backend\ProductController
// ...
public function editAction(Request $request, EntityManagerInterface $em, Product $product)

    $editForm = $this->createForm('AppBundle\Form\ProductType', $product);
    $editForm->handleRequest($request);

    $originalImages = new ArrayCollection();

    foreach ($product->getImages() as $image) 
        $originalImages->add($image);
    

    if ($editForm->isSubmitted()) 
        if ($editForm->isValid()) 
            foreach ($originalImages as $image) 
                if (false === $product->getImages()->contains($image)) 
                    $em->remove($image);
                
            

            $em->flush();

            $this->addFlash('success', 'Success');
         else 
            $this->addFlash('warning', 'Error saving');
        

        return $this->redirectToRoute('backend_product_edit', ['id' => $product->getId()]);
    

// ...

我认为我需要在某处取消设置空文件字段,但我不知道在哪里......(

附:我知道我可以使用像 VichUploaderBundle 这样的捆绑包,但我想了解它是如何工作的,以及我做错了什么! 附言对不起我的英语

【问题讨论】:

【参考方案1】:

修改 ImageType 表单完全解决了我的问题

// AppBundle\Form\ImageType   
public function buildForm(FormBuilderInterface $builder, array $options)

    $builder
        ->add('file', FileType::class, ['required' => false, 'data_class' => null]])
        // another fields...
    ;
    // adding this forces to use old file if there is no file uploaded
    $builder->get('file')->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) 
        if (null === $event->getData()) 
            $event->setData($event->getForm()->getData());
        
    );

【讨论】:

【参考方案2】:

一周前我遇到了同样的问题。在阅读了很多关于这个问题的帖子后,出于安全原因,您似乎无法预先填写表单的“文件字段”。

我已经实现的简单解决方案:

在您的“editAction 方法”中:在呈现表单之前“编辑”分配用户会话中当前文件字段的值。

然后,当用户提交“更新”表单时,您可以使用更新前事件(例如学说生命周期)在会话中查找这些文件名,并在持久化之前将它们重新分配给您的实体。

基本上你应该做这样的事情(我给你我的实体的代码,你需要让它适应你的逻辑)

在我的案例中,原则关系是 1 News has 1 Image file。

在您的编辑操作中:

protected function editNewsAction()

    //some code 

    if (!$response instanceof RedirectResponse)
    
        $entityId = $this->request->query->get('id'); //the id of my entity was in the query string in my logic

        $repo = $this->getDoctrine()->getManager()->getRepository('AppBundle:News');
        $oldEntity = $repo->findOneBy(['id' => $entityId]);
        $oldEntityImage = $oldEntity->getImage(); // I had oneToOne Relation so adapt it for your own logic

        $session = $this->get('session');
        $session->set('newsImage', $oldEntityImage);
    

    // some code

然后在更新前的事件中:

protected function preUpdateNewsEntity($entity)

    //some code

    if (!$entity->getImageFile())
    
        $session = $this->get('session');

        $entity->setImage($session->get('newsImage'));

        //don't forget to remove the value in session
        $session->remove('newsImage');
    

    //some code

希望对你有帮助。

【讨论】:

我想过这样的事情,但是使用FormEvents::PRE_SET_DATA 事件监听器。有可能获取原始对象并检查提交的字段,更多信息docs 感谢您的链接。我认为你是完全正确的。也可以使用 FormEvents。

以上是关于带有文件类型字段editAction的Symfony 3表单集合实体的主要内容,如果未能解决你的问题,请参考以下文章

python 接受带有字段名称,类型和分析器的YAML文件,并生成Elasticsearch JSON映射文件

Symfony2 生成带有选项的实体字段

带有图像字段的图片项目的单独表格

带有架构的 pyspark.sql SparkSession load() :架构中的非字符串类型字段使所有值都为空

什么是在 Access 2003 中将带有填充空格的文本字段导出到 txt 文件的解决方案或公式

带有官方 Graphql 教程的“无法在 CreateUser 类型上查询字段 'id'”