I've been following a Symfony tutorial on Udemy, a simple CMS which I'm now trying to expand.
I've added a file upload field to a form, the file is uploaded and the file name is stored in the database.
Adding new records works as does editing records if I select a new file add a new file on the edit form.
But if i try to edit without select a new file to upload, the original file name is removed from the db.
This is what I have so far in the controller
public function editAction(Request $request, Car $car)
{
$deleteForm = $this->createDeleteForm($car);
$editForm = $this->createForm('CarBundle\Form\CarType', $car);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$file = $editForm['brochure']->getData();
if(!empty($file)) {
// Generate a unique name for the file before saving it
$fileName = md5(uniqid()).'.'.$file->guessExtension();
// Move the file to the directory where brochures are stored
$file->move( $this->getParameter('brochures_directory'), $fileName );
$car->setBrochure($fileName);
} else {
$id = $car->getId();
$em = $this->getDoctrine()->getManager();
$car = $em->getRepository('CarBundle:Car')->find($id);
$fileName = $car->getBrochure();
$car->setBrochure($fileName);
}
$em = $this->getDoctrine()->getManager();
$em->merge($car);
$em->flush();
return $this->redirectToRoute('car_edit', array('id' => $car->getId()));
// return $this->redirectToRoute("car_index");
}
If the Symfony form builder I have this
->add('brochure', FileType::class,[
'label' => 'Image',
'data_class' => null,
'required' => false
])
I think the problem is coming from the form builder data_class which I had to add due to the error
The form's view data is expected to be an instance of class >Symfony\Component\HttpFoundation\File\File, but is a(n) string.
But I'm not sure how to fix it, any suggestion or help welcome!
ps. I've read that this should probably be a service, but baby steps first!
At the bottom of this page (ctrl+f for "When creating a form to edit an already persisted item ..") it says if you're editing an item, it's better to just create a new file with the old file's name.
public function editAction(Request $request, Car $car)
{
$editForm = $this->createForm('CarBundle\Form\CarType', $car);
$editForm->handleRequest($request);
$brochureDir = $this->getParameter('brochures_directory');
if (!empty($car->getBrochure()) {
$car->setBrochure(
new File($brochureDir . '/' . $car->getBrochure()
);
}
if ($editForm->isSubmitted() && $editForm->isValid()) {
$file = $car->getBrochure();
if (!empty($file)) {
// Generate a unique name for the file before saving it
$fileName = md5(uniqid()) . '.' . $file->guessExtension();
// Move the file to the directory where brochures are stored
$file->move($brochureDir, $fileName);
$car->setBrochure($fileName);
}
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirectToRoute('car_edit', array('id' => $car->getId()));
}
}
Now can you remove the "'data_class' => null" from your form and just let it either be a new File or null from an old entry.
I also cleaned up some other stuff in there --got rid of your two doctrine calls, got rid of that "merge" (never seen that, not even sure what it does. If this is an edit form the entity already exists in doctrine so just editing the entity and flushing should work.). I also got rid of that else statement because I couldn't see what it was doing besides setting a few variables. If this code doesn't work and you need that else statement (or anything else I've removed) put it back in there and work on it some more. This is not tested code.
Good luck.
So I found a solutions, thanks for the suggestions to all who helped! I'll post my solution for others to see, but please be aware I'm not a Symfony expert so I can't say if its correct for Symfony or even best practice!
public function editAction(Request $request, Car $car)
{
$deleteForm = $this->createDeleteForm($car);
$editForm = $this->createForm('CarBundle\Form\CarType', $car);
//get the current file name if there is one
$currentFile = $car->getBrochure();
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$file = $editForm['brochure']->getData();
if(!empty($file)) {
//if new file has been posted, use it to update DB
// Generate a unique name for the file before saving it
$fileName = md5(uniqid()).'.'.$file->guessExtension();
// Move the file to the directory where brochures are stored
$file->move(
$this->getParameter('brochures_directory'),
$fileName
);
$car->setBrochure($fileName);
} else {
//if no new file has been posted and there is a current file use that to update the DB
if (!empty($currentFile)) {
$car->setBrochure($currentFile);
}
}
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirectToRoute('car_edit', array('id' => $car->getId()));
// return $this->redirectToRoute("car_index");
}
return array(
'car' => $car,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}