Reputation: 111
How to handle the form update correctly, when there is a collection of entities with fileType field. I did actions and listeners according to the Symfony upload docs. Entity creation works perfect, but edit action fails, because there is no file selected and symfony tries to update collection entities with null value on file field.
AppBundle\Entity\Product:
type: entity
# ...
oneToMany:
images:
targetEntity: Image
mappedBy: product
Forms:
// AppBundle\Form\ProductType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add(
'images',
CollectionType::class,
[
'entry_type' => ImageType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'entry_options' => ['label' => false],
'label_attr' => [
'data-feature' => 'editable',
],
]
);
}
// AppBundle\Form\ImageType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, ['required' => false])
// another fields...
}
Action:
// AppBundle\Controller\Backend\ProductController
// ...
public function editAction(Request $request, EntityManagerInterface $em, Product $product)
{
$editForm = $this->createForm('AppBundle\Form\ProductType', $product);
$editForm->handleRequest($request);
$originalImages = new ArrayCollection();
foreach ($product->getImages() as $image) {
$originalImages->add($image);
}
if ($editForm->isSubmitted()) {
if ($editForm->isValid()) {
foreach ($originalImages as $image) {
if (false === $product->getImages()->contains($image)) {
$em->remove($image);
}
}
$em->flush();
$this->addFlash('success', 'Success');
} else {
$this->addFlash('warning', 'Error saving');
}
return $this->redirectToRoute('backend_product_edit', ['id' => $product->getId()]);
}
}
// ...
In my opinion I need to unset empty file field somewhere, but I don't know where...(
P.S. I know that I can use bundles like VichUploaderBundle
, but I would like to understand how it works, and what I'm doing wrong!
P.P.S. Sorry for my English
Upvotes: 3
Views: 1643
Reputation: 111
Modifying ImageType form completely solved my problem
// AppBundle\Form\ImageType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, ['required' => false, 'data_class' => null]])
// another fields...
;
// adding this forces to use old file if there is no file uploaded
$builder->get('file')->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
if (null === $event->getData()) {
$event->setData($event->getForm()->getData());
}
});
}
Upvotes: 3
Reputation: 665
I had the same problem one week ago. After having read many threads about this problem it seems that for security reasons you cannot pre-fill the "file field" of the form.
Simple solution I have implemented:
In your "editAction method": before rendering the form "edit" assign the value of the current file fields in the session of the user.
Then when the user submit the "update" form you can use a pre-update event (doctrine life cycle for exemple) to look for those file names in the session and re assign them to your entity before persisting.
Basicaly you should do something like this (I give you the code for my entity you need to adapt it to your logic)
The doctrine relation in my case was 1 News has 1 Image file.
In your editAction:
protected function editNewsAction()
{
//some code
if (!$response instanceof RedirectResponse)
{
$entityId = $this->request->query->get('id'); //the id of my entity was in the query string in my logic
$repo = $this->getDoctrine()->getManager()->getRepository('AppBundle:News');
$oldEntity = $repo->findOneBy(['id' => $entityId]);
$oldEntityImage = $oldEntity->getImage(); // I had oneToOne Relation so adapt it for your own logic
$session = $this->get('session');
$session->set('newsImage', $oldEntityImage);
}
// some code
}
And then in a pre-update event:
protected function preUpdateNewsEntity($entity)
{
//some code
if (!$entity->getImageFile())
{
$session = $this->get('session');
$entity->setImage($session->get('newsImage'));
//don't forget to remove the value in session
$session->remove('newsImage');
}
//some code
}
I hope this will help you.
Upvotes: 2