Multiple file upload with Symfony2

后端 未结 11 821
温柔的废话
温柔的废话 2020-12-01 02:12

I\'m trying to upload multiple files via a form, but I can only upload one file at a time, the last one I mark in the browser. Is there a way to upload more images with Symf

相关标签:
11条回答
  • 2020-12-01 02:54

    Here is easy example to upload multiple files. I have similar problem with upload files.

    https://github.com/marekz/example_symfony_multiply_files_example

    For symfony 3.*

    First: Both form declatartion:

        <?php
    
    namespace AppBundle\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use AppBundle\Form\FilesType;
    use Symfony\Component\Form\Extension\Core\Type\CollectionType;
    
    class UserType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                    ->add('name')
                    ->add('lastName')
                    ->add('files', CollectionType::class,array(
                        'entry_type' => FilesType::class,
                        'allow_add' => true,
                        'by_reference' => false,
                    ))
                    ;
        }
    
        /**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'AppBundle\Entity\User'
            ));
        }
    
        /**
         * {@inheritdoc}
         */
        public function getBlockPrefix()
        {
            return 'appbundle_user';
        }
    
    
    }
    
    
        <?php
    
    namespace AppBundle\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    
    class FilesType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('file');
        }
    
        /**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'AppBundle\Entity\Files'
            ));
        }
    
        /**
         * {@inheritdoc}
         */
        public function getBlockPrefix()
        {
            return 'appbundle_files';
        }
    
    
    }
    

    Now, my entities:

    <?php
    
    namespace AppBundle\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use Doctrine\Common\Collections\ArrayCollection;
    
    /**
     * User
     *
     * @ORM\Table(name="user")
     * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
     */
    class User {
    
        /**
         * @var int
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
    
        /**
         * @var string
         *
         * @ORM\Column(name="name", type="string", length=255)
         */
        private $name;
    
        /**
         * @var string
         *
         * @ORM\Column(name="lastName", type="string", length=255)
         */
        private $lastName;
    
        /**
         * @ORM\ManyToMany(targetEntity="Files", cascade={"persist"})
         */
        private $files;
    
        function __construct() {
            $this->files = new ArrayCollection();
        }
    
        /**
         * Get id
         *
         * @return int
         */
        public function getId() {
            return $this->id;
        }
    
        /**
         * Set name
         *
         * @param string $name
         *
         * @return User
         */
        public function setName($name) {
            $this->name = $name;
    
            return $this;
        }
    
        /**
         * Get name
         *
         * @return string
         */
        public function getName() {
            return $this->name;
        }
    
        /**
         * Set lastName
         *
         * @param string $lastName
         *
         * @return User
         */
        public function setLastName($lastName) {
            $this->lastName = $lastName;
    
            return $this;
        }
    
        /**
         * Get lastName
         *
         * @return string
         */
        public function getLastName() {
            return $this->lastName;
        }
    
        /**
         * Get files
         * 
         * @return ArrayCollection
         */
        function getFiles() {
            return $this->files;
        }
    
        /**
         * Set files
         * @param type $files
         */
        function setFiles($files) {
            $this->files = $files;
        }
    }
    
        <?php
    
    namespace AppBundle\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
    
    /**
     * Files
     *
     * @ORM\Table(name="files")
     * @ORM\Entity(repositoryClass="AppBundle\Repository\FilesRepository")
     */
    class Files
    {
        /**
         * @var int
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
    
        /**
         * @var string
         *
         * @ORM\Column(name="file", type="string", length=255, unique=true)
         * @Assert\NotBlank(message="Please, upload the product brochure as a PDF file.")
         * @Assert\File(mimeTypes={ "application/pdf" })
         */
        private $file;
    
        /**
         *
         * @return Files
         */
        function getUser() {
            return $this->user;
        }
    
        /**
         * Get id
         *
         * @return int
         */
        public function getId()
        {
            return $this->id;
        }
    
        /**
         * Set file
         *
         * @param string $file
         *
         * @return Files
         */
        public function setFile($file)
        {
            $this->file = $file;
    
            return $this;
        }
    
        /**
         * Get file
         *
         * @return string
         */
        public function getFile()
        {
            return $this->file;
        }
        }
    

    Finaly, Symfony Controller:

    /**
     * Creates a new user entity.
     *
     * @Route("/new", name="user_new")
     * @Method({"GET", "POST"})
     */
    public function newAction(Request $request) {
        $user = new User();
        $form = $this->createForm('AppBundle\Form\UserType', $user);
        $form->handleRequest($request);
    
        if ($form->isSubmitted() && $form->isValid()) {
    
            $attachments = $user->getFiles();
    
            if ($attachments) {
                foreach($attachments as $attachment)
                {
                    $file = $attachment->getFile();
    
                    var_dump($attachment);
                    $filename = md5(uniqid()) . '.' .$file->guessExtension();
    
                    $file->move(
                            $this->getParameter('upload_path'), $filename
                    );
                    var_dump($filename);
                    $attachment->setFile($filename);
                }
            }
    
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();
    
            return $this->redirectToRoute('user_show', array('id' => $user->getId()));
        }
    
        return $this->render('user/new.html.twig', array(
                    'user' => $user,
                    'form' => $form->createView(),
        ));
    }
    
    0 讨论(0)
  • 2020-12-01 02:57

    Note that i try to do the same thing in sf2 using this syntax:

    In the controller:

    public function stuffAction() {
    
    $form = $this->createFormBuilder()
                    ->add('files','file',array(
                        "attr" => array(
                            "accept" => "image/*",
                            "multiple" => "multiple",
                        )
                    ))
                    ->getForm();
    
            $formView = $form->createView();
            $formView->getChild('files')->set('full_name', 'form[files][]');
    
    // name param (eg 'form[files][]') need to be the generated name followed by []
    // try doing this : $formView->getChild('files')->get('full_name') . '[]'
    
    
            $request = $this->getRequest();
            if($request->getMethod() == "POST") {
    
                $form->bindRequest($request);
    
                $data = $form->getData();
                $files = $data["files"];
    
                // do stuff with your files
            }
    
        }
    
        return $this->render('Bundle:Dir:index.html.twig',array("form" => $formView));
    }
    

    $files will be an array of uploaded files...

    Calling $form->createView() to alter the name attribute is certainly not the best way / cleanest way to do it but it's the only one i found that keeps the csrf functionality working, because altering the name attribute in a twig template makes it invalid...

    Now I still have an issue using a form class which generate the form, I don't know why during the binding of the form data & object attached to the form my array of uploaded files is transformed in array of (file) name ???

    0 讨论(0)
  • 2020-12-01 02:58

    Methods getChild and set() were removed in 2.3. Instead of this you should use children[] and vars properties

    before:

    $formView->getChild('files')->set('full_name', 'form[files][]');
    

    after:

    $formView->children['files']->vars = array_replace($formView->children['files']->vars, array('full_name', 'form[files][]'));
    
    0 讨论(0)
  • 2020-12-01 03:01

    You need to alter the input file name attribute which need to map an array.

    <input type="file" name="name[]" multiple />
    
    0 讨论(0)
  • 2020-12-01 03:06

    Ok binding issue solved (enctype syntax error) : i'll give you the code i use. maybe it will help...

    I have a Gallery Entity

    class Gallery
    {
        protected $id;
        protected $name;
        protected $description;
        private $urlName;
        public $files; // the array which will contain the array of Uploadedfiles
    
        // GETTERS & SETTERS ...
    
        public function getFiles() {
            return $this->files;
        }
        public function setFiles(array $files) {
            $this->files = $files;
        }
    
        public function __construct() {
            $files = array();
        }
    }
    

    I have a form class that generate the form

    class Create extends AbstractType {
    
        public function buildForm(FormBuilder $builder, array $options) {
    
            $builder->add('name','text',array(
                "label" => "Name",
                "required" => TRUE,
            ));
            $builder->add('description','textarea',array(
                "label" => "Description",
                "required" => FALSE,
            ));
            $builder->add('files','file',array(
                "label" => "Fichiers",
                "required" => FALSE,
                "attr" => array(
                    "accept" => "image/*",
                    "multiple" => "multiple",
                )
            ));
        }
    }
    

    Now in the controller

    class GalleryController extends Controller
    {
        public function createAction() {
            $gallery = new Gallery();
            $form = $this->createForm(new Create(), $gallery);
            // Altering the input field name attribute
            $formView = $form->createView();
            $formView->getChild('files')->set('full_name', 'create[files][]');
    
            $request = $this->getRequest();
            if($request->getMethod() == "POST")
            {
                $form->bindRequest($request);
    
                // print "<pre>".print_r($gallery->getFiles(),1)."</pre>";
                if($form->isValid())
                {
                    // Do what you want with your files
                    $this->get('gallery_manager')->save($gallery);
                    return $this->redirect($this->generateUrl("_gallery_overview"));
                }
            }
    
            return $this->render("GalleryBundle:Admin:create.html.twig", array("form" => $formView));
        }
    }
    

    Hope this help...

    NB: If someone know a better way to alter this f** name attribute, maybe in the FormView class or by declaring a new field type, feel free to show us your method...

    0 讨论(0)
提交回复
热议问题