Symfony2 中多个文件上传的问题

Posted

技术标签:

【中文标题】Symfony2 中多个文件上传的问题【英文标题】:Problems With Multiple File Upload In Symfony2 【发布时间】:2012-05-13 19:06:29 【问题描述】:

我正在制作一个 Symfony2 应用程序,它需要有多个图像上传选项。我已经使用说明书条目上传了单个文件:How to handle File Uploads with Doctrine,效果很好。我已经为上传和删除实现了生命周期回调

现在我需要把它变成一个多重上传系统。我也从 Stack Overflow 阅读了一些答案,但似乎没有任何效果。

堆栈溢出问题:

    Multiple file upload with Symfony2 multiple file upload symfony 2

我现在有以下代码:

文件实体:

<?php
namespace Webmuch\ProductBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;


/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class File

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $path;

    /**
     * @Assert\File(maxSize="6000000")
     */
    public $file = array();

    public function __construct()
    

    

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    
        return $this->id;
    

    /**
     * Set path
     *
     * @param string $path
     */
    public function setPath($path)
    
        $this->path = $path;
    

    /**
     * Get path
     *
     * @return string 
     */
    public function getPath()
    
        return $this->path;
    


    public function getAbsolutePath()
    
        return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
    

    public function getWebPath()
    
        return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
    

    protected function getUploadRootDir()
    
        // the absolute directory path where uploaded documents should be saved
        return __DIR__.'/../../../../web/'.$this->getUploadDir();
    

    protected function getUploadDir()
    
        // get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
        return 'uploads';
    

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    
        if (null !== $this->file) 
            // do whatever you want to generate a unique name
            $this->path[] = uniqid().'.'.$this->file->guessExtension();
        
    

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    
        if (null === $this->file) 
            return;
        

        // if there is an error when moving the file, an exception will
        // be automatically thrown by move(). This will properly prevent
        // the entity from being persisted to the database on error
        $this->file->move($this->getUploadRootDir(), $this->path);

        unset($this->file);
    

    /**
     * @ORM\PostRemove()
     */
    public function removeUpload()
    
        if ($file = $this->getAbsolutePath()) 
            unlink($file);
        
    

文件控制器

<?php

namespace Webmuch\ProductBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

use Webmuch\ProductBundle\Entity\File;


/**
 * File controller.
 *
 * @Route("/files")
 */
class FileController extends Controller

    /**
     * Lists all File entities.
     *
     * @Route("/", name="file_upload")
     * @Template()
     */
    public function uploadAction()
    
        $file = new File();
        $form = $this->createFormBuilder($file)
            ->add('file','file',array(
                    "attr" => array(
                        "accept" => "image/*",
                        "multiple" => "multiple",
                    )
                ))
            ->getForm()
        ;

        if ($this->getRequest()->getMethod() === 'POST') 
            $form->bindRequest($this->getRequest());
                $em = $this->getDoctrine()->getEntityManager();

                $em->persist($file);
                $em->flush();

                $this->redirect($this->generateUrl('file_upload'));
        

        return array('form' => $form->createView());
    

upload.html.twig

% extends '::base.html.twig' %

% block body %
<h1>Upload File</h1>

<form action="#" method="post"  form_enctype(form) >

     form_widget(form.file)  

    <input type="submit" value="Upload" />
</form>
% endblock %

我不知道该怎么做才能使它作为一个多文件上传系统工作。我保留了我遵循的教程中的 cmets,以便我可以记住正在做什么。

更新:

新表单代码:

$images_form = $this->createFormBuilder($file)
    ->add('file', 'file', array(
            "attr" => array(
                "multiple" => "multiple",
                "name" => "files[]",
            )
        ))
    ->getForm()
;

新表单树枝代码:

<form action=" path('file_upload') " method="post"  form_enctype(images_form) >

     form_label(images_form.file) 
     form_errors(images_form.file) 
     form_widget(images_form.file,  'attr': 'name': 'files[]' ) 

     form_rest(images_form) 
    <input type="submit" />
</form>

【问题讨论】:

目前这有什么问题? 感谢您的回复。如果我选择例如 5 个文件,则只上传最后一个文件。 啊,是的 - 您的输入控件需要有一个单独的名称 - 因为它目前没有名称,它为所有控件使用默认名称。 我无法为其添加名称。请查看我的表单代码我已经更新了问题。我尝试更改名称,但默认表单 [file] 即将到来。我尝试从 formBuilder 添加的任何内容都会添加到标签中。奇怪! 我无法为 [表单元素] 添加名称 - 在什么意义上?你的意思是因为技术原因你不能,或者你试图这样做但它不起作用?如果是后者,您是否检查了 HTML 以查看 Twig 模板生成了什么?此外,如果 files[] 的名称不起作用,请在循环中尝试单个名称(file_0file_1 等)。 【参考方案1】:

这是一个已知问题as referenced on GitHub。

正如他们所说,您应该将[] 附加到模板中的full_name 属性:

 form_widget(images_form.file,  'full_name': images_form.file.get('full_name') ~ '[]' ) 

【讨论】:

在 symfony 2.5 中你可以使用: form_widget(images_form.file, 'full_name': images_form.file.vars.full_name ~ '[]' ) 太棒了!这是正确答案,应标记为有效。 感谢 github 问题链接。它确实帮助我解决了验证问题。我还添加了另一个解决方案作为答案,它也很有效。【参考方案2】:

我不知道注释语法是否可行。所以我将在控制器中用普通的 PHP 编写它

$images_form = $this->createFormBuilder($file)
    ->add('file', 'file', array(
        'constraints' => array(
            new NotBlank(), // Makes sure it is filled at all.
            new All(array( // Validates each an every entry in the array that is uploaded with the given constraints.
                'constraints' => array(
                    new File(array(
                        'maxSize' => 6000000
                    )),
                ),
            )),
        ),
        'multiple' => TRUE,
    ))
    ->getForm();

这应该从 Symfony 2.4 开始完美运行。在此之前,您必须像之前那样将 multiple 属性放在 attr 键中。

正如我所说,您必须使用注释来完成这项工作。如果您必须将所有内容放在一行中,它可能会起作用,但可读性可能会降低。

玩得开心;)

【讨论】:

关于注释:这是在 symfony 网站上作为示例给出的。 symfony.com/doc/current/reference/constraints/All.htmlclass User /** * @Assert\All( * @Assert\NotBlank, * @Assert\Length(min = 5) * ) */ protected $favoriteColors = array(); 【参考方案3】:

我最近遇到了同样的问题,按照这里的建议进行操作,但出现错误,因为验证器“文件”无法处理数组。

所以我不得不编写自己的验证器,它可以处理多个文件。为此,我关注this tutorial from Symfony.com,将验证器“文件”中的代码复制/粘贴到其中,用foreach 循环对其进行封装,并根据需要更改变量。

如果您这样做,您可以在您的实体中将其用于$file

【讨论】:

以上是关于Symfony2 中多个文件上传的问题的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2 限制最终用户仅上传 csv 文件

使用 ajax 和 Symfony2 上传文件

Symfony2文件上传获取原始文件名

Symfony2 文件管理器 [关闭]

Symfony2 Sonata Media Bundle -- 上传图片时出错

上传图片时如何在 symfony2 奏鸣曲媒体中设置最大上传大小