Проблемы с загрузкой нескольких файлов в Symfony2

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

Теперь мне нужно превратить это в систему множественной загрузки. Я также прочитал несколько ответов от Stack Overflow, но ничего не работает.

Вопрос о переполнении стека:

  1. Загрузка нескольких файлов с помощью Symfony2
  2. множественная загрузка файлов symfony 2

На данный момент у меня есть следующий код:

Сущность файла :

<?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 Code:

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

Это известная проблема, о которой упоминается в GitHub .

Как говорится, вы должны добавить [] в атрибут full_name в своем шаблоне:

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

У меня была такая же проблема в последнее время, последовали за предложениями здесь, но получили сообщение об ошибке, потому что файл validator 'file' не может обрабатывать массивы.

Поэтому мне пришлось написать собственный валидатор, который может обрабатывать несколько файлов. Для этого я следовал этому руководству с Symfony.com , копировал / вставлял код из файла проверки валидатора в него, инкапсулировал его циклом foreach и при необходимости менял переменные.

Если вы это сделаете, вы можете использовать его для $file в своей сущности.

Я не знаю, возможно ли это с синтаксисом аннотации. Поэтому я собираюсь записать его в простой 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. До этого вам пришлось бы поместить multiple атрибут в ключ attr как вы уже делали.

Как я уже сказал, вам нужно сделать эту работу с аннотациями. Это может сработать, но может быть менее читаемым, если вам нужно поместить все в одну строку.

Повеселись 😉