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
相关产品推荐
相关产品推荐

