I need to make changes to the collection (Symfony CollectionType
form) to respect the ordering and deletion of objects, and I use the preSubmit
event preSubmit
to make changes as per this suggestion . However, the changes do not return to the controller / persistence.
The data is correct after preSubmit
and is set in the event using $event->setData($data)
, but the changes are not saved after sending to $form->getData()
My imagine an abstract class:
abstract class AbstractEntityFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit']); } public function onPreSubmit(FormEvent $event) { $form = $event->getForm(); $data = $event->getData(); $document = $form->getData(); foreach ($form->all() as $field) { $fieldName = $field->getName(); if ($field->getConfig()->getType()->getInnerType() instanceof CollectionType) {
When I give $data
here, everything is correct.
FormType extending this AbstractEntityFormType
class:
class DocumentType extends AbstractEntityFormType { public function buildForm(FormBuilderInterface $builder, array $options) { parent::buildForm($builder, $options); $builder->add('title', TextType::class, [ 'required' => true, 'constraints' => [ new NotBlank([ 'message' => '"title" is empty', ]), ], ]); $builder->add('symptoms', CollectionType::class, [ 'entry_type' => SymptomType::class, 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, ]); $builder->add('tags', CollectionType::class, [ 'entry_type' => TagType::class, 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, ]); $builder->add('submit', SubmitType::class); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Document::class, ]); } }
My controller action:
public function formAction(Request $request, int $documentId = null) { if (!$documentId) { $document = new Document(); } else { try { $document = $this->documentService->getDocument($documentId); } catch (InvalidDocumentException $e) { return new NotFoundResponse('Document not found'); } } $document = $this->setAuthor($document); $form = $this->formFactory->create(DocumentType::class, $document); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $document = $this->documentService->createDocument($form->getData()); return new RedirectResponse($this->router->generate('ui.document.view', [ 'documentId' => $document->getId() ])); } return $this->templating->renderResponse( '@KBS/Document/form.html.twig', [ 'form' => $form->createView(), ] ); }
When I delete $form->getData()
before continuing with this service, the data is incorrect - it was not affected by preSubmit
. What am I missing?
FYI, this uses the core components of Symfony 3.2.
Update
Thanks @LBT, I'm a little closer, but still run into some issues. Using this approach in the controller, I can get the correct data from the request at the time the form is submitted:
public function formAction(Request $request, int $documentId = null) { if (!$documentId) { $document = new Document(); } else { try { $document = $this->documentService->getDocument($documentId); } catch (InvalidDocumentException $e) { return new NotFoundResponse('Document not found'); } } $document = $this->setAuthor($document); $form = $this->formFactory->create(DocumentType::class, $document); if ($request->isMethod('POST')) { $form->submit($request->request->get($form->getName())); if ($form->isSubmitted() && $form->isValid()) { $document = $this->documentService->createDocument($form->getData()); return new RedirectResponse($this->router->generate('ui.document.view', [ 'documentId' => $document->getId() ])); } } return $this->templating->renderResponse( '@KBS/Document/form.html.twig', [ 'form' => $form->createView(), ] ); }
However, $form->submit($request->request->get($form->getName()));
also saves incorrect (original) data before conversion. Even if the data in the request is correct:
/var/www/html/src/Controller/DocumentController.php:94: array (size=8) 'title' => string 'Tag test' (length=8) 'symptoms' => array (size=1) 0 => array (size=3) 'position' => string '0' (length=1) 'title' => string 'The smell is terrible' (length=21) 'description' => string 'pew' (length=3) 'tags' => array (size=4) 0 => array (size=1) 'title' => string 'Volvo' (length=5) 1 => array (size=1) 'title' => string 'Engine' (length=6) 2 => array (size=1) 'title' => string 'BMW' (length=3) 3 => array (size=1) 'title' => string 'Funky' (length=5)
It seems like I'm getting closer, but it seems like I can't use this query data as suggested in the documentation for for some reason.