Я попробовал новую реализацию библиотеки 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>
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');