I tried a new implementation of JQuery library : dropzone.js
This library provides a good multi upload interface with drag and drop solution.
It seems that the multi upload system of Symfony isn't easy.
I've this error :
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
My entity 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);
}
}
My controller 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());
}
And finally my twig template :
<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>
EDIT :
FormType :
class FileUploadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', 'file');
}
public function getName()
{
return 'file';
}
}
What is wrong with my code ? I know it's a problem with UploadedFile and array but I don't know how to resolve that.
Thank you for all !
EDIT :
Maybe this link can help someone, I fail to reproduce this :
Problems With Multiple File Upload In Symfony2
EDIT with new uploadAction function :
/**
* @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'));
}
First of all, you don't really use your FileUploadType
in the Twig template. You create a form manually and set the action
path to the url you defined in your Controller. The only thing you use from the form view you pass to the template is the form_enctype
. But like most multi file uploaders, Dropzone seems to forge its own request to upload an Image.
This means you also have to handle the incoming data manually.
/**
* @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([]);
}
The method uploadAction
takes the FileBag
from Symfony's request, iterates over it, and performs your custom logic on the resulting file. Of course you have to handle the storage of the File
entity by yourself.
Your template should look like this:
<form action="{{ path('upload_media') }}" method="post" class="dropzone">
<div class="fallback">
<input name="file" type="file" multiple />
</div>
</form>
Symfony requires that every form contains a csrf-token. Your form doesn't contain one so symfony tries to use your "file"-field as a csrf-token and throws the error. The first step to solve this problem is to render a csrf-token with this snippet in your form-element:
{{ form_widget(form) }}
Then you have to change your entity that it can handle multiple files. This can be done by implementing a one to many relation (upload (one) to file (many)).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With