在EasyAdmin 4.24.5(Symfony 7.1环境)的编辑页面以表格形式展示已有文件的功能实现咨询
在EasyAdmin 4.24.5(Symfony 7.1环境)的编辑页面以表格形式展示已有文件的功能实现咨询
嘿,我完全懂你的需求——就是不想在编辑页把已上传的发票文件变成重复的上传表单,而是像详情页那样用清爽的表格展示,还得带查看、下载、删除按钮,同时单独留个上传框用来加新文件对吧?这事儿其实不难,我给你捋捋具体怎么落地:
核心思路
本质就是把编辑页里原来对应文件字段的表单组件,替换成详情页风格的表格展示模块,同时保留一个独立的新文件上传字段,另外还要单独处理文件的删除逻辑(毕竟默认编辑页没这个功能)。
具体实现步骤
1. 配置CrudController的编辑页面字段
在你的InvoiceCrudController里,重写configureFields方法,针对编辑页面做特殊配置:
- 把原来关联文件的字段从编辑表单里移除,换成自定义模板来渲染表格;
- 新增一个单独的文件上传字段,用来添加新文件。
代码示例:
use EasyAdminBundle\Config\Crud; use EasyAdminBundle\Field\FileField; use EasyAdminBundle\Field\TemplateField; public function configureFields(string $pageName): iterable { // 先放发票的基础字段,比如编号、日期这些 yield TextField::new('invoiceNumber')->setLabel('发票编号'); yield DateField::new('invoiceDate')->setLabel('发票日期'); if ($pageName === Crud::PAGE_EDIT) { // 用自定义模板渲染已有文件表格 yield TemplateField::new('existingFiles', '已上传文件') ->setTemplatePath('admin/invoice_existing_files.html.twig'); // 单独的新文件上传字段,支持多文件的话加multiple配置 yield FileField::new('newFiles') ->setLabel('添加新文件') ->setFormTypeOption('multiple', true) ->setUploadDir('public/uploads/invoices') ->setUploadedFileNamePattern('[randomhash].[extension]'); } else { // 列表页、详情页用原来的关联字段配置就行 yield AssociationField::new('files')->setLabel('附件'); } }
2. 编写自定义模板渲染文件表格
创建templates/admin/invoice_existing_files.html.twig,模仿EasyAdmin自带的表格样式,展示文件信息和操作按钮:
{% if entity.files is not empty %} <div class="card"> <div class="card-header"> <h5 class="card-title">{{ label }}</h5> </div> <div class="card-body p-0"> <table class="table table-striped table-hover"> <thead> <tr> <th>文件名</th> <th>文件大小</th> <th>操作</th> </tr> </thead> <tbody> {% for file in entity.files %} <tr> <td>{{ file.name }}</td> <td>{{ file.size|format_filesize }}</td> <td> {# 查看按钮,新开页展示文件 #} <a href="{{ asset('uploads/invoices/' ~ file.path) }}" target="_blank" class="btn btn-sm btn-outline-primary"> <i class="fa fa-eye"></i> 查看 </a> {# 下载按钮,跳转到自定义下载路由 #} <a href="{{ path('invoice_download', {'id': file.id}) }}" class="btn btn-sm btn-outline-success"> <i class="fa fa-download"></i> 下载 </a> {# 删除按钮,带确认提示 #} <a href="{{ path('invoice_file_delete', {'invoiceId': entity.id, 'fileId': file.id}) }}" class="btn btn-sm btn-outline-danger" data-confirm="确定要删除这个文件吗?删除后无法恢复哦"> <i class="fa fa-trash"></i> 删除 </a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> {% else %} <p class="text-muted mt-3">暂无已上传文件</p> {% endif %}
3. 处理文件的删除与新文件保存
(1)删除文件的逻辑
创建自定义控制器动作处理文件删除,比如在InvoiceController里:
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; /** * @Route("/admin/invoice/{invoiceId}/file/{fileId}/delete", name="invoice_file_delete") * @IsGranted("ROLE_ADMIN") */ public function deleteFile(int $invoiceId, int $fileId, EntityManagerInterface $em): RedirectResponse { $invoice = $em->getRepository(Invoice::class)->find($invoiceId); $file = $em->getRepository(InvoiceFile::class)->find($fileId); if (!$invoice || !$file || !$invoice->getFiles()->contains($file)) { throw $this->createNotFoundException('指定文件不存在'); } // 物理删除服务器上的文件(可选,根据需求决定是否保留) $filePath = $this->getParameter('kernel.project_dir') . '/public/uploads/invoices/' . $file->getPath(); if (file_exists($filePath)) { unlink($filePath); } // 从数据库移除关联并删除文件记录 $invoice->removeFile($file); $em->remove($file); $em->flush(); $this->addFlash('success', '文件已成功删除'); return $this->redirectToRoute('admin', [ 'crudAction' => 'edit', 'entityId' => $invoiceId, 'crudControllerFqcn' => InvoiceCrudController::class, ]); }
(2)保存新上传文件的逻辑
先在Invoice实体里加一个临时属性接收上传的文件:
use Symfony\Component\HttpFoundation\File\File; // 临时存储上传的新文件,不需要映射到数据库 private ?array $newFiles = null; public function getNewFiles(): ?array { return $this->newFiles; } public function setNewFiles(?array $newFiles): self { $this->newFiles = $newFiles; return $this; }
然后在InvoiceCrudController里重写persistEntity方法处理文件保存:
use Symfony\Component\HttpFoundation\File\UploadedFile; public function persistEntity(EntityManagerInterface $em, $entity): void { if ($entity instanceof Invoice && $entity->getNewFiles()) { foreach ($entity->getNewFiles() as $uploadedFile) { /** @var UploadedFile $uploadedFile */ // 生成唯一文件名避免冲突 $fileName = uniqid() . '.' . $uploadedFile->guessExtension(); // 移动文件到指定目录 $uploadedFile->move( $this->getParameter('kernel.project_dir') . '/public/uploads/invoices', $fileName ); // 创建文件实体并关联到发票 $file = new InvoiceFile(); $file->setName($uploadedFile->getClientOriginalName()); $file->setPath($fileName); $file->setSize($uploadedFile->getSize()); $entity->addFile($file); } // 清空临时属性 $entity->setNewFiles(null); } parent::persistEntity($em, $entity); }
4. 体验优化小细节
- 确保项目引入了Font Awesome图标库,让按钮更直观;
- 可以给上传字段加文件类型限制,比如只允许PDF、图片:
setFormTypeOption('mimetypes', ['application/pdf', 'image/jpeg', 'image/png']); - 测试时注意检查文件上传大小限制,在
php.ini和config/packages/framework.yaml里配置合适的数值。
备注:内容来源于stack exchange,提问作者Tavodar
相关产品推荐
相关产品推荐

