I am getting trouble with symfony2 forms which is overriding my entity's data by null if the corresponding form input is not submitted.
Here is an example:
Form type:
$builder
->add('customerid', 'text')
->add('field1', 'text')
->add('field2', 'text')
...
Controller :
$customer = new Customer();
$customer->setId('the customerID');
$customerForm = $this->createForm(new CustomerType(), $customer);
if ($request->getMethod() == 'POST') {
$customerForm->bind($request);
...
}
On the view, i don't render the customerid text field.
Only others fields are submitted.
After submitting the form, $customerForm->bind($request); is overriding the previously setted customerID by null even if no empty value was submitted for it.
Is there any way to not override the value if the input fields was not rendered?
Here seems to be the same problem :
https://github.com/symfony/symfony/issues/1341
A patch was submitted but i did not found documentation on how to use it.
Thanks
Any field in the form (whether rendered or not) will have a value, either null or the value of the field.
Which version of Symfony are you using?
I assume you're using <2.3 as I think bind was changed to submit at 2.3.
With bind every field is merged into the object meaning it will replace the data, null or otherwise.
I think the only way to work around this would be to either just not include the unwanted fields in the form or the use an event listener as documented in the cookbook.
If you are using 2.3+ (or you upgrade to 2.3+) then you should be using $form->submit() which has a second argument which allows you to set the form to not overwrite object properties if they are null. eg $form->submit($request->get($form->getName()), false) (true being the boolean to set/unset the overwrite, or $clearMissing on the actual code)
Related
I have a dynamic form.
For exemple, if something, my form contains FormType1 else my form contains FormType2 or FormType3 ....
I would detect if my form is modify.
If my form is completed, I apply is valid() method and if there is an error I return in the form or if there is no error, I apply a redirection.
I know how to do that.
But, if my fom was submitted without modifications (with no new value) I want to apply an other redirection without validation because my validation will return false with required fields.
I can't test if all values are null because in form there may be combobox or boolean, or initial value, ...
I have a solution with javascript and two submit buttons.
If the value of button submit is 'just_redirection' I don't apply the validation else I apply validation.
Is there a way in Symfony2 (or full PHP) to know if the submitted form is the same that the initial form?
Let's assume your form is bound with an entity MyEntity, in your controller you need to copy your original object, let the form handle the request, then compare your objects:
public function aRouteAction(Request $request, MyEntity $myEntity)
{
$entityFromForm = clone $myEntity;
// you need to clone your object, because since PHP5 a variable contains a reference to the object, so $entityFromForm = $myEntity wouldn't work
$form = $this->createForm(new MyFormType(), $entityFromForm);
$form->handleRequest($request);
if($entityFromForm == $myEntity) {
// redirect when no changes
}
if($form->isValid()) {
// redirect when there are changes and form submission is valid
}
else {
// return errors
}
}
For object cloning please refer to the php manual.
Consider the following form:
$builder->add('home_team', 'choice', [$options])
->add('away_team', 'choice', [$more_options])
->add('timestamp', 'datetime_picker', [$usual_stuff]);
I wish to validate these fields, and see that no other Match exists with the same home_team, away_team and timestamp.
I have made a UniqueMatchValidator with a validate() function but I need some help here.
I'm going to do a database call with the values from the form to check for duplicates, but in order to do that, I need to know the values of all three fields, while applying the Validator to only one of the fields.
Question
How can I access the values of all the form fields from inside the Validator?
As mentioned above it's better to use FormTypes and data classes.
However even with arrays you can use form validation and get all fields using event listener:
$builder
->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$event->getData(); //you will get array with field values
$event->getForm()->addError(...); // if something happens error can be addded
})
Actually form validator uses this event too.
Your form should basically contains an entity. You need to do your validations using callbacks in the entity. Using callback, you can access all the properties of that entity.
This link will surely help you to understand it better:
Symfony2 Form Validation Callback
Let say I have an HTML form with bunch of fields. Some fields belong to Product, some to Order, some to Other. When the form is submitted I want to take that request and then create Symfony forms for Product, Order, and Other in controller. Then I want to take partial form data and bind it with appropriate forms. An example would something like this:
$productArray = array('name'=>$request->get('name'));
$pf = $this->createForm(new \MyBundle\Form\ProductType(), $product);
$pf->bind($productArray);
if($pf->isValid()) {
// submit product data
}
// Do same for Order (but use order data)
// Do same for Other (but use other data)
The thing is when I try to do it, I can't get $form->isValid() method working. It seems that bind() step fails. I have a suspicion that it might have to do with the form token, but I not sure how to fix it. Again, I build my own HTML form in a view (I did not use form_widget(), cause of all complications it would require to merge bunch of FormTypes into one somehow). I just want a very simple way to use basic HTML form together with Symfony form feature set.
Can anyone tell me is this even possible with Symfony and how do I go about doing it?
You need to disable CSRF token to manually bind data.
To do this you can pass the csrf_protection option when creating form object.
Like this:
$pf = $this->createForm(new \MyBundle\Form\ProductType(), $product, array(
'csrf_protection' => false
));
I feel like you might need a form that embed the other forms:
// Main form
$builder
->add('product', new ProductType)
->add('order', new OrderType);
and have an object that contains association to these other objects to which you bind to the request. Like so you just have to bind one object with the request and access embedded object via simple getters.
Am I clear enough?
I am not able to understand why Symfony does this.
Suppose i have the UserFormType class
->add(username);
->add(datecreated);
Now i don't show dateCreated in my template then symfony sets the DateCreated to null which overwrites the database value.
I want to know what the problem in not setting that value to null and just have original value if its not in the template
From the documentation: Additionally, if there are any fields on the form that aren't included in the submitted data, those fields will be explicitly set to null. so you must render all your fields otherwise they will be set to null.
You can either not add it in the form and Symfony will leave that value alone on update, I'm guessing you set dateCreated in your code anyway so you don't need the Forms library trying to update that field.
The other option is to add the field as a hidden field ->add('dateCreated', 'hidden') you will need to render the field in your template and Symfony will keep around the dateCreated data. If you are rendering each row you can use form_rest(form) in your twig to render all the missing fields.
This is an old topic but I ran into the same situation and the easiest and cleanest way for me to handle this was to remove the field from the form when you don't want to do anything with it.
For example I want to show the list of groups a user is attached to but some other user can't see them. The result was any changes for those users would remove the group they already had.
The solution:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) {
$this->onPreSubmit($event);
}
);
.....
}
public function onPreSubmit(FormEvent $event)
{
$params = $event->getData();
if (!isset($params['groups'])) {
$event->getForm()->remove('groups');
}
}
Now your form will reject the groups if it is set, to avoid that you can add to your form the options 'allow_extra_fields' => true. It will pass validation and do nothing with it.
Although it is neat I am not a big fan but I can't see any other solution, or you will have to build the html yourself and the action/service to handle validation without symfony built in form system.
I would like to validate an embedded form field before it gets saved in the database. Currently it will save an empty value into the database if the form field is empty. I'm allowing empty fields, but I want nothing inserted if the form field is empty.
Also quick question, how to alter field values before validating/saving an embedded form field?
$this->form->getObject works in the action, but $this->embeddedForm->getObject says object not found
I found a really easy solution. The solution is to override your Form's model class save() method manually.
class SomeUserClass extends myUser {
public function save(Doctrine_Connection $conn = null)
{
$this->setFirstName(trim($this->getFirstName()));
if($this->getFirstName())
{
return parent::save();
}else
{
return null;
}
}
}
In this example, I'm checking if the firstname field is blank. If its not, then save the form. If its empty, then we don't call save on the form.
I haven't been able to get the validators to work properly, and this is an equally clean solution.
Symfony gives you a bunch of hooks into the form/object saving process.
You can overwrite the blank values with null pre/post validation using by overriding the the doSave() or processValues() functions of the form.
You can read more about it here: http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms#chapter_06_saving_object_forms