Téléchargement de plusieurs fichiers avec Symfony2

j'essaie de télécharger plusieurs fichiers via un formulaire, mais je ne peux télécharger qu'un fichier à la fois, le dernier que je marque dans le navigateur. Y a-t-il un moyen de télécharger plus d'images avec Symfony2 en utilisant un formulaire simple? Voici le modèle de la forme que j'utilise pour marquer plus d'un fichier:

{{ form_widget(form.post_image, { 'attr': {'multiple': 'multiple' }}) }} 
20
demandé sur Ondrej Slinták 2011-07-18 21:40:43

11 réponses

pas besoin de cours supplémentaires (excepté le service gallery_manger mais la question que vous décrivez se produit avant...)

Je ne sais pas vraiment ce qui ne va pas. Vérifiez votre modèle (peut-être mauvais enctype... ou le nom de l'attribut missmatching)

d'abord essayer de faire un seul téléchargement de fichiers, consultez la documentation:

  1. type de champ de fichier
  2. Comment gérer les Uploads de Fichier avec Doctrine

une Fois que cela fonctionne, vous il faut modifier quelques lignes.

  1. ajouter un attribut multiple au fichier d'entrée.
  2. ajouter [] à la fin de l'attribut du nom du fichier d'entrée (mine is créer...[] parce que mon nom de classe de forme est create, si votre est createType il sera createType...[])
  3. init $fichiers sous forme de tableau.

Copier/coller votre code ici.

12
répondu thierry 2014-04-02 03:11:17

problème de liaison Ok résolu (erreur de syntaxe d'enctype) : je vais vous donner le code que j'utilise. peut-être que ça va aider...

j'ai un Galerie 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();
    }
}

j'ai un formulaire classe qui génère la forme

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",
            )
        ));
    }
}

dans le 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));
    }
}

Espérons que cette aide...

NB: si quelqu'un connaît une meilleure façon de modifier ce f** attribut name, peut-être dans la classe FormView ou par déclaration d'un nouveau type de champ, n'hésitez pas à nous montrer votre méthode...

11
répondu thierry 2011-07-20 21:53:17

toutes les suggestions que j'ai trouvées ici sont des solutions pour la situation réelle.

pour pouvoir avoir plusieurs pièces jointes, vous devez utiliser la collecte de formulaires.

citation tirée de la documentation:

dans cette entrée, vous apprendrez comment créer une forme qui intègre une collection de plusieurs autres formes. Cela pourrait être utile, par exemple, si vous aviez une classe de tâche et que vous vouliez éditer/créer/supprimer de nombreux objets de balise liés à cette tâche, n'est-ce pas? à l'intérieur de la même forme.

http://symfony.com/doc/2.0/cookbook/form/form_collections.html

exemple de cas: vous avez un document, quel formulaire est spécifié par DocumentType. Le document doit avoir plusieurs pièces jointes, que vous pouvez avoir en définissant le formulaire AttachmentType et en l'ajoutant comme une collection au formulaire DocumentType.

7
répondu Nikola Petkanski 2012-01-10 13:08:01

utilisez cette méthode:

$form = $this->createFormBuilder()
->add('attachments','file', array('required' => true,"attr" => array(
  "multiple" => "multiple",
  )))
->add('save', 'submit', array(
  'attr' => array('class' => 'btn btn-primary btn-block btn-lg'),
  'label' => 'save'
  ))
->getForm();

puis vous ajoutez [] le nom de votre entrée via jQuery :

<input id="form_attachments" name="form[attachments]" required="required" multiple="multiple" type="file">

jQuery code:

 <script>
  $(document).ready(function() {
    $('#form_attachments').attr('name',$('#form_attachments').attr('name')+"[]");
  });
</script>
3
répondu Yassine EL MALKI 2014-05-08 14:09:45

pour sf > 2,2 : En vous classe de type de formulaire, ajoutez cette surdéfini méthode :

public function finishView(FormView $view, FormInterface $form, array $options) {
    $view->vars['form']->children['files']->vars['full_name'] .= '[]';
}
3
répondu Prometee 2014-08-11 13:22:00

Notez que j'essaie de faire la même chose dans sf2 en utilisant cette syntaxe:

dans le contrôleur:

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 sera un tableau de fichiers téléchargés...

appel $form->createView() modifier l'attribut name n'est certainement pas la meilleure façon de le faire, mais c'est le seul que j'ai trouvé qui maintient la fonctionnalité csrf fonctionnelle, parce que modifier l'attribut name dans un modèle de brindille le rend invalide...

maintenant j'ai encore un problème à utiliser un classe de forme qui génère la forme, Je ne sais pas pourquoi pendant la liaison des données de forme et l'objet attaché à la forme mon tableau de fichiers téléchargés est transformé en tableau de nom (de fichier)???

2
répondu thierry 2012-07-27 04:28:16

voici un exemple simple pour télécharger plusieurs fichiers. J'ai le même problème avec les fichiers de téléchargement.

https://github.com/marekz/example_symfony_multiply_files_example

pour symfony 3.*

d'Abord: à la Fois la forme 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';
    }


}

maintenant, mes 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;
    }
    }

Enfin, Symfony Contrôleur:

/**
 * 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(),
    ));
}
2
répondu Grzegorz Brzęczyszczykiewicz 2017-05-21 05:39:22

vous devez modifier l'attribut de nom de fichier d'entrée qui doit cartographier un tableau.

<input type="file" name="name[]" multiple />
1
répondu thierry 2011-07-20 20:56:35

méthodes getChild et set() ont été enlevés en 2.3. Au lieu de cela, vous devez utiliser children[] et vars propriétés

avant:

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

après:

$formView->children['files']->vars = array_replace($formView->children['files']->vars, array('full_name', 'form[files][]'));
1
répondu ZuyRzuuf 2013-08-02 15:44:17

Symfony introduit 'multiple' option pour type de champ file dans symfony 2.5

$builder->add('file', 'file', array('multiple' => TRUE));
1
répondu Khaled Attia 2014-07-26 20:24:18

que se passerait-il s'il y avait des erreurs de validation? Seront Formulaire de Symfony reposter plusieurs champ d'envoi de fichier. Parce que je l'ai essayé et je pense que dans ce but vous devez utiliser collection de champs de fichier. Que forme symfony doit rendre tous les champs ont ajouté avant correctement.

0
répondu setty 2012-04-20 07:44:55