Reputation: 85
So, what I need is a basic file upload. What I have is Symfony 4 and VichUploaderBundle, integrated exactly as described https://symfony.com/doc/current/bundles/EasyAdminBundle/integration/vichuploaderbundle.html
Entity is marked as @Vich\Uploadable, fields are defined correcty:
/**
* @Vich\UploadableField(mapping="images", fileNameProperty="fileName")
* @var File
*/
private $file;
/**
* @ORM\Column(type="string", length=255)
*/
private $fileName;
This is my Type:
class MyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('file', VichImageType::class, ['allow_file_upload' => true])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => My::class,
'allow_extra_fields' => false,
'http_method' => 'POST'
]);
$resolver->setRequired('http_method');
}
}
What I have in my controller:
$form = $this->createForm(MyType::class, null);
$form->submit(array_merge($request->request->all(), $request->files->all()));
if ($form->isSubmitted() && $form->isValid()) {
/** @var $my */
$my = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($my);
$em->flush();
return $this->json($my);
}
The outcome of this is a TransformationException:
Compound forms expect an array or NULL on submission.
I've debugged the whole thing with xDebug - it successfully submits name
field, and even file
field, for the first time. But then, for some reason, it thinks it's a compound form and tries to submit it one more time - which obviously leads to a transformation exception https://github.com/symfony/form/blob/master/Form.php#L571
And, when I try to set 'compound' => false
, it doesn't submit the file field at all.
What might be the problem here? I've seen in the docs, that for using it with EasyAdmin it's enough to just specify the field name and type 'vich_image', why it doesn't work outside the EasyAdmin? You could notice, by the way, that I've added extra parameter 'allow_file_upload' => true
as it wasn't submitting without it https://github.com/symfony/form/blob/master/Form.php#L534
Upvotes: 1
Views: 1228
Reputation: 1
I try this solution and it worked :
/**
*
* @Route("/create", name="image_create", methods={"POST"})
* @throws JsonException
* @throws \Doctrine\DBAL\Exception
* @throws Exception
*/
public function create(Request $request)
{
//Call api in form-data with key image which have image file
$file = $request->files->all()["image"];
$image = new Image();
$image->setName(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME))
->setMime($file->getClientMimeType())
->setCreatedAt(new \Datetime('now'))
->setTargetImageFile($file);
$this->entityManager->persist($image);
$this->entityManager->flush();
//response whatever you want
}
Here my entity :
<?php
namespace App\Entity;
use App\Repository\ImageRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity(repositoryClass=ImageRepository::class)
* @ORM\Table(name="img_image")
* @Vich\Uploadable
*/
class Image
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer", name="img_image_id")
*/
private $id;
/**
* @ORM\Column(type="string", length=255, name="img_image_name")
*/
private $name;
/**
* @ORM\Column(type="string", length=100, name="img_image_mime")
*/
private $mime;
/**
* @Vich\UploadableField(mapping="image", fileNameProperty="target_image")
*
* @var File
*/
private $target_image_file;
/**
* @ORM\Column(type="string", length=255, name="img_target_image")
*
* @var string
*/
private $target_image;
/**
* @ORM\Column(type="datetime", name="img_image_created_at")
*/
private $created_at;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getMime(): ?string
{
return $this->mime;
}
public function setMime(string $mime): self
{
$this->mime = $mime;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeInterface $created_at): self
{
$this->created_at = $created_at;
return $this;
}
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* @param File|UploadedFile|null $target_image_file
*/
public function setTargetImageFile(?File $target_image_file = null): void
{
$this->target_image_file = $target_image_file;
if (null !== $target_image_file) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTimeImmutable();
}
}
public function getTargetImageFile(): ?File
{
return $this->target_image_file;
}
public function setTargetImage(?string $target_image): void
{
$this->target_image = $target_image;
}
public function getTargetImage(): ?string
{
return $this->target_image;
}
}
Upvotes: 0
Reputation: 85
So, a bit of further research has lead me to this answer https://github.com/dustin10/VichUploaderBundle/issues/769#issuecomment-477173161
And the solution is to submit the form like this:
$form->submit(array_merge(
$request->request->all(),
['file' => $request->files->all()]
));
Upvotes: 0