You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 6:嵌入集合表单中子表单的文件上传问题

问题背景

我有一个ClientFileAction实体,和Attachment实体是**一对多(OneToMany)**关系。Attachment实体存储文件路径、标题、上传日期等信息,实体代码如下:

#[ORM\Column(type: 'string', length: 255)]
private $title;
#[ORM\Column(type: 'datetime')]
private $uploaded;
#[ORM\Column(type: 'string', length: 255)]
private $filePath;

单独使用AttachmentType表单进行单文件上传时一切正常,表单代码:

$builder
    ->add('title', null, ['label' => 'Title', 'required' => true])
    ->add('attachmentFile', FileType::class, [
        'label' => 'File',
        'mapped' => false,
        'required' => true,
        'constraints' => [
            new File([
                'maxSize' => '1024k',
            ])
        ],
    ]);

控制器中通过$attachmentFile = $form->get('attachmentFile')->getData();就能获取上传文件,再执行UploadedFile::move()完成存储。

但将AttachmentType作为CollectionType嵌入父表单ClientFileActionType后,无法获取到未映射的attachmentFile字段。父表单代码:

$builder
    ->add('description', null, ['label' => 'Description', 'required' => true])
    ->add('attachments', CollectionType::class, [
        'label' => false,
        'allow_add' => true,
        'by_reference' => false,
        'entry_type' => AttachmentType::class,
        'entry_options' => ['label' => false],
    ]);

执行$attachments = $form->get('attachments')->getData();得到的是Attachment对象数组,attachmentFile字段在$form->handleRequest($request);后消失;尝试$form->get('attachments.attachmentFile')->getData()直接报错,请问正确的获取方式是什么?

解决方案

要获取集合中每个子表单的未映射字段,需要遍历父表单的attachments子表单集合,逐个获取每个AttachmentType表单实例中的attachmentFile字段:

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
    // 获取attachments对应的表单集合
    $attachmentForms = $form->get('attachments');
    
    foreach ($attachmentForms as $attachmentForm) {
        // 从每个子表单中获取未映射的attachmentFile字段
        $uploadedFile = $attachmentForm->get('attachmentFile')->getData();
        
        if ($uploadedFile instanceof UploadedFile) {
            // 执行文件移动操作
            $fileName = uniqid().'.'.$uploadedFile->guessExtension();
            $uploadedFile->move(
                $this->getParameter('uploads_directory'), // 替换为你的存储目录参数
                $fileName
            );
            
            // 关联到对应的Attachment实体
            $attachment = $attachmentForm->getData();
            $attachment->setFilePath($fileName);
            $attachment->setUploaded(new \DateTime());
        }
    }
    
    // 后续保存ClientFileAction实体逻辑
    $entityManager = $this->getDoctrine()->getManager();
    $entityManager->persist($clientFileAction);
    $entityManager->flush();
    
    // 跳转或返回响应
}

关键说明

  • 不能直接从getData()返回的Attachment实体中获取未映射字段,因为未映射字段不会被映射到实体属性,只会保留在表单实例中。
  • 必须遍历父表单中attachments对应的表单实例集合,而不是getData()返回的实体数组,这样才能访问到每个子表单的未映射字段。
  • 处理完文件后,记得把生成的文件路径赋值给Attachment实体的filePath属性,并设置上传日期,最后一起持久化保存。

内容的提问来源于stack exchange,提问作者K. Weber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:25:19