Symfony2中多文件上载的问题

时间:2012-05-04 08:33:14

标签: php file-upload symfony doctrine-orm symfony-forms

我正在制作一个需要多个图片上传选项的Symfony2应用程序。我使用cookbook条目上传了单个文件: How to handle File Uploads with Doctrine ,它可以正常工作。我已经实施了 lifecyclecallbacks 来上传和删除。

现在我需要将其转换为多重上传系统。我也从Stack Overflow中读到了一些答案,但似乎没什么用。

Stack Overflow问题:

  1. Multiple file upload with Symfony2
  2. multiple file upload symfony 2
  3. 目前我有以下代码:

    文件实体:

    <?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);
            }
        }
    }
    

    FileController

    <?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 %}
    

    我不知道如何使其作为多文件上传系统工作。我保留了我所遵循的教程中的评论,因此我记得在做什么。

    更新

    新表格代码:

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

    新表格Twig代码:

    <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>
    

3 个答案:

答案 0 :(得分:15)

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

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

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

答案 1 :(得分:4)

我不知道注释语法是否可行。所以我将在控制器中的普通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开始,这应该是完美的。在此之前,您必须像{Q}}那样将multiple属性放在attr键中。

正如我所说,你必须使用注释来完成这项工作。如果你必须把它全部放在一行,它可能会起作用,但可能性较差。

玩得开心;)

答案 2 :(得分:3)

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

所以我必须编写自己的验证器,它可以处理多个文件。为此,我跟着this tutorial from Symfony.com,从其中的验证器'file'复制/粘贴代码,用foreach循环封装它并根据需要更改变量。

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