Мультизагрузка Symfony 2.3 с Dropzone

Я попробовал новую реализацию библиотеки JQuery: dropzone.js

Эта библиотека обеспечивает хороший многопользовательский интерфейс с перетаскиванием.

Похоже, что многопользовательская система загрузки Symfony непростая.

У меня эта ошибка:

Error: Cannot use object of type Symfony\Component\HttpFoundation\File\UploadedFile as array in /vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php line 87 

Мой объект Файл:

 /** * @ORM\Entity * @ORM\Table(name="media__file") * @ORM\HasLifecycleCallbacks */ class File { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ public $id; /** * @ORM\Column(type="string", length=255) * @Assert\NotBlank */ public $name; /** * @ORM\Column(type="string", length=255, nullable=true) */ public $path; /** * @Assert\File(maxSize="6000000") */ public $file; 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() { return __DIR__.'/../../../../../web/'.$this->getUploadDir(); } protected function getUploadDir() { return 'uploads/files'; } /** * @ORM\PrePersist() * @ORM\PreUpdate() */ public function preUpload() { if (null !== $this->file) { $this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension(); } } /** * @ORM\PostPersist() * @ORM\PostUpdate() */ public function upload() { if (null === $this->file) { return; } $this->file->move($this->getUploadRootDir(), $this->path); unset($this->file); } /** * @ORM\PostRemove() */ public function removeUpload() { if ($file = $this->getAbsolutePath()) { unlink($file); } } с /** * @ORM\Entity * @ORM\Table(name="media__file") * @ORM\HasLifecycleCallbacks */ class File { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ public $id; /** * @ORM\Column(type="string", length=255) * @Assert\NotBlank */ public $name; /** * @ORM\Column(type="string", length=255, nullable=true) */ public $path; /** * @Assert\File(maxSize="6000000") */ public $file; 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() { return __DIR__.'/../../../../../web/'.$this->getUploadDir(); } protected function getUploadDir() { return 'uploads/files'; } /** * @ORM\PrePersist() * @ORM\PreUpdate() */ public function preUpload() { if (null !== $this->file) { $this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension(); } } /** * @ORM\PostPersist() * @ORM\PostUpdate() */ public function upload() { if (null === $this->file) { return; } $this->file->move($this->getUploadRootDir(), $this->path); unset($this->file); } /** * @ORM\PostRemove() */ public function removeUpload() { if ($file = $this->getAbsolutePath()) { unlink($file); } } 

Мой контроллер FileController:

 /** * @Route("/admin/media/upload") * @Template() */ public function uploadsAction (){ $file = new File(); $form = $this->createForm(new \Tperroin\Bundle\MediaBundle\Form\FileUploadType(), $file); if ($this->getRequest()->isMethod('POST')) { $form->bind($this->getRequest()); if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($file); $em->flush(); return $this->redirect($this->generateUrl('tperroin_home_default_index')); } } return array('form' => $form->createView()); } 

И, наконец, мой шаблон ветки:

 <div class="widget-content"> <form action="{{ url('tperroin_media_file_uploads') }}" method="post" {{ form_enctype(form) }} class="dropzone"> <div class="fallback"> <input name="file" type="file" multiple /> </div> </form> </div> 

РЕДАКТИРОВАТЬ :

FormType:

 class FileUploadType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('file', 'file'); } public function getName() { return 'file'; } } 

Что не так с моим кодом? Я знаю, что это проблема с UploadedFile и массивом, но я не знаю, как это решить.

Спасибо вам за все !

РЕДАКТИРОВАТЬ :

Может быть, эта ссылка может помочь кому-то, я не могу воспроизвести это:

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

EDIT с новой функцией uploadAction:

 /** * @Route("/upload/process", name="upload_media") */ public function uploadAction() { $request = $this->get('request'); $files = $request->files; $directory = $this->get('kernel')->getRootDir() . '/../web' . $this->getRequest()->getBasePath() . '/files/'; foreach ($files as $uploadedFile) { $name = $uploadedFile->getClientOriginalName(); $file = $uploadedFile->move($directory, $name); $upload = new File($name); $em = $this->get('doctrine')->getManager(); $em->persist($upload); $em->flush(); } return $this->redirect($this->generateUrl('tperroin_media_default_index')); } 

Прежде всего, вы не используете свой FileUploadType в шаблоне Twig. Вы создаете форму вручную и action путь action к URL-адресу, указанному в контроллере. Единственное, что вы используете в представлении формы, которое вы передаете шаблону, – это form_enctype . Но, как и большинство многопользовательских файлов, Dropzone, похоже, создает собственный запрос на загрузку изображения.

Это означает, что вам также необходимо вручную обрабатывать входящие данные.

 /** * @Route("/admin/media/upload") * @Template() */ public function showUploadAction() { // just show the template return []; } /** * @Route("/admin/media/upload/process", name="upload_media") */ public function uploadAction() { $request = $this->get('request'); $files = $request->files; // configuration values $directory = //... // $file will be an instance of Symfony\Component\HttpFoundation\File\UploadedFile foreach ($files as $uploadedFile) { // name the resulting file $name = //... $file = $uploadedFile->move($directory, $name); // do something with the actual file $this->doSomething($file); } // return data to the frontend return new JsonResponse([]); } 

Метод uploadAction принимает FileBag из запроса Symfony, итерации по нему и выполняет вашу пользовательскую логику в результирующем файле. Конечно, вы должны обрабатывать хранилище объекта File самостоятельно.

Ваш шаблон должен выглядеть так:

 <form action="{{ path('upload_media') }}" method="post" class="dropzone"> <div class="fallback"> <input name="file" type="file" multiple /> </div> </form> 


Благодаря этому вопросу я обратил внимание на загрузчик Dropzone и интегрировал его в OneupUploaderBundle . Таким образом, вы можете просто использовать этот комплект, который упрощает несколько шагов, упомянутых выше.

Symfony требует, чтобы каждая форма содержала csrf-токен. Ваша форма не содержит одного, поэтому symfony пытается использовать ваше поле «file» в качестве символа csrf и выдает ошибку. Первым шагом для решения этой проблемы является рендеринг csrf-токена с этим фрагментом в вашем элементе формы:

 {{ form_widget(form) }} 

Затем вы должны изменить свою сущность, чтобы она могла обрабатывать несколько файлов. Это можно сделать путем реализации отношения «один-много» (загрузка (одно) в файл (многие)).

В Symfony, если у вас есть ошибка

 Error: Call to a member function move() on a non-object 

Попробуйте изменить

 $files = $request->files 

к

 $files = $request->files->get('file');