Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 - How to stop Form->handleRequest from nulling fields that don't exist in post data

Tags:

forms

php

symfony

I've got a form built in Symfony and when rendered in the view, the html form may or may not contain all of the fields in the form object (the entity sort of has a couple of different states and not all fields are rendedered in the view).

The problem is that when the form is processed in the submit handler, via handleRequest() method of the form object, it resets any properties in the entity that are not present in the post data to null, blowing away any existing value.

Is there any way to tell Symfony not to be so stupid and only process the fields present in the POST data?

Or do I have to clone the entity before the handleRequest call and then loop over the POST values and copy the related values from the post-handleRequest entity over to the pre-handleRequest clone of the entity, so I preserve the fields that are not in the POST data.

phew! as you can see, its a bit of a daft solution, to a bit of a daft problem, tbh.

I could understand symfony doing this if the entity was in effect a newly created object, but its been loaded from the DB and then handleRequest called - it should be sensible enough to know the object has already been initialised and only set the fields passed in the POST data.

Thanks for any help.

Regards

Steve.

like image 719
Steve Childs Avatar asked Aug 13 '14 16:08

Steve Childs


2 Answers

In short, don't use handleRequest.

You should use submit directly instead along with the clearMissing parameter set to false.

Symfony/Component/Form/FormInterface

/**  * Submits data to the form, transforms and validates it.  *  * @param null|string|array $submittedData The submitted data.  * @param bool              $clearMissing  Whether to set fields to NULL  *                                         when they are missing in the  *                                         submitted data.  *  * @return FormInterface The form instance  *  * @throws Exception\AlreadySubmittedException If the form has already been submitted.  */ public function submit($submittedData, $clearMissing = true); 

When you use handleRequest it works out what data you are wanting the submit and then submits it using $form->submit($data, 'PATCH' !== $method);, meaning that unless you have submitted the form using the PATCH method then it will clear the fields.

To submit the form yourself without clearing your can use...

$form->submit($request->get($form->getName()), false); 

.. which get the form data array from the request and submit it directly, but with the clear missing fields parameter set to false.

like image 197
qooplmao Avatar answered Sep 18 '22 12:09

qooplmao


If your entity has different states, you could reflect this in your form type.

Either create multiple form types (maybe using inheritance) containing the different field setups and instantiate the required one in your controller.

Something like this:

class YourState1FormType extends AbstractType {      public function buildForm(FormBuilderInterface $builder, array $options)     {         $builder             ->add('someField')         ;     }  }  class YourState2FormType extends AbstractType {      public function buildForm(FormBuilderInterface $builder, array $options)     {         $builder             ->add('someOtherField')         ;     }  } 

Or pass a parameter to the single form type upon creation in the controller and adapt the field setup depending on the state. If you don't add the fields that are not present, they don't get processed.

Something like this:

class YourFormType extends AbstractType {      public function buildForm(FormBuilderInterface $builder, array $options)     {         if($options['state'] == 'state1') {             $builder                 ->add('someField')             ;         } else if($options['state'] == 'state2') {             $builder                 ->add('someOtherField')             ;         }     }      public function setDefaultOptions(OptionsResolverInterface $resolver)     {         $resolver->setDefaults(array(             'state' => 'state1'         ));     }  } 

Update

Another approach you can take to modify your form based on the submitted data is to register event listeners to the form's PRE_SET_DATA and POST_SUBMIT events. These listeners get called at different moments within the form submission process and allow you to modify your form depending on the data object passed to the form type upon form creation (PRE_SET_DATA) or the form data submitted by the user (POST_SUBMIT).

You can find an explanation and examples in the docs.

like image 30
janwschaefer Avatar answered Sep 21 '22 12:09

janwschaefer