Несколько загрузок файлов с Symfony2 - PullRequest
20 голосов
/ 18 июля 2011

Я пытаюсь загрузить несколько файлов через форму, но я могу загрузить только один файл за раз, последний, который я отмечаю в браузере.Есть ли способ загрузить больше изображений с Symfony2, используя простую форму?Вот шаблон веточки формы, которую я использую, чтобы иметь возможность пометить более одного файла:

{{ form_widget(form.post_image, { 'attr': {'multiple': 'multiple' }}) }} 

Ответы [ 11 ]

12 голосов
/ 03 августа 2011

Никаких дополнительных классов не требуется (кроме службы gallery_manger, но описанная вами проблема возникает раньше ...)

Я действительно не знаю, что случилось. Проверьте ваш шаблон (возможно, неправильный enctype ... или неправильное совпадение имени)

сначала попробуйте выполнить загрузку одного файла, проверьте документацию:

  1. Тип поля файла
  2. Как обрабатывать загрузку файлов с помощью Doctrine

Как только это сработает, вам нужно отредактировать несколько строк.

  1. добавить несколько атрибутов входного файла.
  2. append [] в конце атрибута имени входного файла (мой создать ... [] потому что мое имя класса формы является создание, если ваш createType это будет createType ... [])
  3. init $ файлы в виде массива.

Скопируйте / вставьте ваш код сюда.

12 голосов
/ 21 июля 2011

Ok проблема с привязкой решена (ошибка синтаксиса enctype): я дам вам код, который я использую.может быть, это поможет ...

У меня есть Галерея Сущность

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

У меня есть форма класс, который генерирует форму

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

Теперь в контроллере

<code>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)."
"; if ($ form-> isValid ()) {// Делайте что хотите со своими файлами $ this-> get('gallery_manager') -> save ($ gallery); вернуть $ this-> redirect ($ this-> generateUrl ("_ gallery_overview"));}} вернуть $ this-> render ("GalleryBundle: Admin: create.html.twig ", array (" form "=> $ formView));}}

Надеюсь, это поможет ...

Примечание: если кто-то знает лучший способ изменить это значение** атрибут name, возможно, в классе FormView или объявив новый тип поля, не стесняйтесь показать нам ваш метод ...

7 голосов
/ 10 января 2012

Все предложения, которые я нашел здесь, являются обходными путями для реальной ситуации.

Чтобы иметь возможность иметь несколько вложений, вы должны использовать коллекцию форм.:

В этой записи вы узнаете, как создать форму, которая встраивает коллекцию из многих других форм.Это может быть полезно, например, если у вас есть класс Task, и вы хотите отредактировать / создать / удалить множество объектов Tag, связанных с этой задачей, прямо в той же форме.1012 *

Пример case: у вас есть документ, форма которого указана в DocumentType.Документ должен иметь несколько вложений, которые можно получить, определив форму AttachmentType и добавив ее в виде коллекции в форму DocumentType.

4 голосов
/ 11 августа 2014

для sf> 2.2: В класс формы формы добавьте этот переопределенный метод:

public function finishView(FormView $view, FormInterface $form, array $options) {
    $view->vars['form']->children['files']->vars['full_name'] .= '[]';
}
3 голосов
/ 08 мая 2014

используйте этот метод:

$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();

затем вы добавляете [] к имени вашего ввода через jQuery:

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

JQuery код:

 <script>
  $(document).ready(function() {
    $('#form_attachments').attr('name',$('#form_attachments').attr('name')+"[]");
  });
</script>
2 голосов

Вот простой пример загрузки нескольких файлов.У меня похожая проблема с загрузкой файлов.

https://github.com/marekz/example_symfony_multiply_files_example

Для Symfony 3. *

Первая: обе формы 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';
    }


}

сейчас, мои сущности:

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

Наконец, контроллер Symfony:

/**
 * 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 голосов
/ 21 июля 2011

Обратите внимание, что я пытаюсь сделать то же самое в sf2, используя следующий синтаксис:

В контроллере:

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 будет массивом загруженных файлов ...

Вызов $form->createView() для изменения атрибута имени, безусловно, не самый лучший / самый чистый способ сделать это, но я нашел только один, который поддерживает функционирование csrf, потому что изменение атрибута имени в шаблоне веткиделает его недействительным ...

Теперь у меня все еще есть проблема с использованием класса формы, который генерирует форму, я не знаю, почему во время привязки данных формы и объекта, присоединенного к форме, мой массив загруженфайлы преобразуются в массив имени (файла) ???

2 голосов
/ 21 июля 2011

Вам необходимо изменить атрибут имени входного файла, который должен отображать массив.

<input type="file" name="name[]" multiple />
1 голос
/ 27 июля 2014

В Symfony появилась опция 'множественные' для типа поля файла в Symfony 2.5

$builder->add('file', 'file', array('multiple' => TRUE));
1 голос
/ 02 августа 2013

Методы getChild и set() были удалены в 2.3.Вместо этого вы должны использовать children[] и vars свойства

до:

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

после:

$formView->children['files']->vars = array_replace($formView->children['files']->vars, array('full_name', 'form[files][]'));
...