7

我正在构建一个复杂的文件上传表单。这种形式存在普通数据和一组 4 种文件类型,每种类型可以上传多个文件。

  • 报告表
    • 附件
      • 报告(UploadedFile 实体的集合)
      • 照片(UploadedFile 实体的集合)

UploadedFile 实体具有文件名、描述等。

用例:现在,我正在提交带有 4 张照片和 2 个报告的表单,所有 6 个文件都可以。但是表格中还有其他一些错误。我想再次显示上传的文件,以便用户不必再次重新上传它们。这些文件已经被持久化,所以当我使用 GET 回到同一页面时,文件会正确显示。

我已经做过/尝试过的事情:

  • 在我绑定请求之前,我克隆了现有的上传文件
  • 绑定表单后,我上传所有新文件(如果有)并保存它们
  • 之后,我重新添加现有的上传文件(来自克隆对象)。我使用现有文件 ID 创建了表单输入,因此我可以识别现有项目。

这一切都很好,但是因为我在绑定后更改了我的报告和附件,所以无法更改帖子后显示的数据。我不能对提交的表单执行 setData($report)。

因此,现有文件不再显示,因为表单数据仍然是旧的报告对象(来自帖子)。

当我对页面进行正常 GET 时,会从数据库中检索 $report 并正确显示。但是在已经上传文件的 POST 之后,数据库数据是正确的,但表单视图对更改的数据一无所知(在绑定之后)。

有任何想法吗?或者更好的方法来做到这一点?

4

2 回答 2

3

我在下面提出了解决方案。您可以根据自己的需要对其进行调整。但是您需要额外的命令来清理 uploads/tmp 目录中的旧文件。您需要在配置中的参数部分下有两个参数:

parameters:
    uploads_dir: %kernel.root_dir%/../web/uploads
    uploads_tmp_dir: %uploads_dir%/tmp

表格:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('file',ImageFileType::TYPE_NAME,array(
            'fileField' => 'file',
            'pathField' => 'path',
            'required' => false,
            'label' => 'makeswapping.form.single_image',
            'imgclass' => 'tumbnail imgbox full-width',
            'constraints' => array(
                new Assert\Image(array(
                    'minWidth' => '440'
                    ))
            )
        ));

    $container = $this->container;

    $builder->addEventListener(
        FormEvents::PRE_SUBMIT,
        function (FormEvent $event) use ($container) {

            $form = $event->getForm();
            $data = $event->getData();

            $uploadsTmpDir = $container->getParameter('uploads_tmp_dir');
            if (isset($data['file'])) {
                $filename = sprintf('%s.%s', uniqid('tmp_'), $data['file']->getClientOriginalExtension());
                if (!file_exists($uploadsTmpDir)) {
                    mkdir($uploadsTmpDir, 0755, true);
                }
                copy($data['file']->getRealPath(), $uploadsTmpDir . '/' . $filename);
                $form->add('file_hidden', 'hidden', array(
                    'mapped' => false,
                    'required' => false,
                    'empty_data' => $filename,
                ));
            } else if (!isset($data['file']) && isset($data['file_hidden'])) {
                $fileInfo = new \SplFileInfo($uploadsTmpDir . '/' . $data['file_hidden']);

                $mimeTypeGuesser = MimeTypeGuesser::getInstance();
                $uploadedFile = new UploadedFile(
                    $fileInfo->getRealPath(),
                    $fileInfo->getBasename(),
                    $mimeTypeGuesser->guess($fileInfo->getRealPath()),
                    $fileInfo->getSize(),
                    null,
                    true
                );

                $form->add('file_hidden', 'hidden', array(
                    'mapped' => false,
                    'required' => false,
                    'empty_data' => $data['file_hidden'],
                ));

                $form->get('file')->setData($uploadedFile);
                $data['file'] = $uploadedFile;
                $event->setData($data);
            }
        }
    );
}
于 2015-03-17T11:28:48.680 回答
3

好的,经过几天的跟踪和错误,我找到了匹配的解决方案。

简而言之,这就是我所做的。

在 UploadedFile 实体中,我添加了 2 个新字段:fileuniqueId。这些字段没有映射到 ORM 中,因为我只需要它们在表单中。

提交表单时,我在特定会话变量中添加新上传的文件,并为它们分配一个唯一的 ID(因为我需要能够删除它们并且我需要一个标识符)。我还将文件上传到他们的新位置。

如果表单有效,我将保存在会话中的这个集合添加到持有这个集合的实体中。

如果表单无效,则显示文件,因为我从会话中检索此特定集合。即使我使用 GET 重新访问该页面,也会显示所有上传的文件。

如果我在视图中删除一个文件,我会将已删除的唯一 ID 列表放在输入字段中。所以在提交后我检查我应该从数组中删除哪些文件。

我认为我的答案和我的问题一样不清楚:)

于 2013-10-23T12:26:09.383 回答