Подтвердить что ты не робот

Загрузка нескольких файлов с помощью Symfony2

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

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

Ответ 1

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

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

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

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

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

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

Ответ 2

Проблема с привязкой к окну решена (синтаксическая ошибка 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();
    }
}

У меня есть класс 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",
            )
        ));
    }
}

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

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

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

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

Ответ 3

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

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

Цитата из документации:

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

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

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

Ответ 4

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

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

Ответ 5

Для sf > 2.2: В форме типа type добавьте этот метод с переопределением:

public function finishView(FormView $view, FormInterface $form, array $options) {
    $view->vars['form']->children['files']->vars['full_name'] .= '[]';
}

Ответ 6

Обратите внимание, что я пытаюсь сделать то же самое в 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(), чтобы изменить атрибут name, конечно, не самый лучший способ/самый чистый способ сделать это, но он единственный, который я нашел, который поддерживает работу csrf, потому что изменение атрибута имени в шаблоне веточки делает его недействительным...

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

Ответ 7

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

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

Ответ 8

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

<input type="file" name="name[]" multiple />

Ответ 9

Методы 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][]'));

Ответ 10

Symfony представила параметр 'multiple' для типа поля файла в symfony 2.5

$builder->add('file', 'file', array('multiple' => TRUE));

Ответ 11

Что произойдет, если будут ошибки проверки? Будет ли Symfony Form повторно загружать поле для загрузки нескольких файлов. Потому что я попробовал это, и я думаю, для этого вам нужно использовать коллекцию полей файлов. Чем должна быть форма symfony, все поля должны быть добавлены правильно.