Zend Framework: isValid() clears values from disabled form fields! - zend-framework

When you submit a form, disabled form fields are not submitted in the request.
So if your form has a disabled form field, it makes working with Zend_Form::isValid() a little frustrating.
$form->populate($originalData);
$form->my_text_field->disabled = 'disabled';
if (!$form->isValid($_POST)) {
//form is not valid
//since my_text_field is disabled, it doesn't get submitted in the request
//isValid() will clear the disabled field value, so now we have to re-populate the field
$form->my_text_field->value($originalData['my_text_field']);
$this->view->form = $form;
return;
}
// if the form is valid, and we call $form->getValues() to save the data, our disabled field value has been cleared!
Without having to re-populate the form, and create duplicate lines of code, what is the best way to approach this problem?

Are you setting the element to disabled so that the user can't edit it's contents but only to see it? If so, just set the element's readonly attribute to true, I think it'll work that way.

I use a custom class inherited from Zend_Form. Class adds some features and solves this problem by replacing the method isValid as follows:
class Murdej_Form extends Zend_Form {
function isValid($data) {
$_data = $this->getValues();
$valid = parent::isValid($data);
$this->populate($_data);
return $valid;
};
};

instead of using isValid() we can use isValidPartial(). Unlike isValid(), however, if a particular key is not present, it will not run validations for that particular element. So, isValidPartial() will not validate for disabled fields.
Reference: ZF Documentation

Related

Suppress errors in Symfony 2

I try to remove some fields from form in event listener. But when I do that I get an error like this form should not contain extra fields. How can I suppress this error?
Here is my listener:
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$form = $event->getForm();
$form->remove('field');
}
});
if you want to ignore data submitted for a field you could unset it's data on "PRE_SET_DATA" or set it to current value in the entity.
Not sure why you would like to first allow the user to submit a form and then cut out part of it instead of just presenting a shorter form in the first place
you could also unset the data AND remove the field from the form on PRE_SUBMIT, but then in case vlaidation goes wrong, user gets back a different form

Symfony 2.x Form Field Name

When I render a form, form Filed Name is given as an array. For example: search[item], search[keyword] etc. where search is name of the form.
I'm not great on working with forms but I think, the name should be rendered as simply, name="item" or name="keyword".
I've looked at all the documentation, customizing form rendering topic etc. but I can't find any way to change the default behaviour of Symfony form to render form filed name from 'search[item]' to 'item'.
This way, when I ask for the POST data, I can ask simply $this->getRequest()->request->get('item'), as I have to deal with lots of individual parameters.
Help would be great i) To figure out how to achieve what I want. ii) to let me know, why the name is rendered this way. is this the good practice?
Rather than accessing parameters from the Request object, you can bind the Request object to the form.
For example, in your controller method that you post your form to:
namespace Acme\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\Form\MyFormClass;
class MyFormController extends Controller
{
receiveFormAction(Request $request)
{
$form = new MyFormClass();
// you can specify that a route only accepts a post
// request in the routing definition
if ($request->isMethod('POST')) {
// this populates the form object with the data
// from the form submission
$form->bind($request);
if ( ! $form->isValid()) {
throw new \Exception('Invalid form');
}
// an array of the data the format you require
$data = $form->getData();
$data['item'];
$data['keyword'];
// etc.
}
}
}
The above is the way you should be handling forms in Symfony 2, and is how you can leverage the power that the forms component gives you, with validation etc.
Symfony supports multiple forms on a page. They might be instances of the same form or have similar field names. Having the fields for each form all together in an array makes this easy to do.

Adding a form field that is not in the schema to Doctrine form Symfony 1.4

I have an image upload form and at the bottom, I'd like to have a checkbox that the user must check before submitting the form, certifying that they have the right to distribute the photo. I've tried adding it as a Widget in the Form class, but it is not displaying. What is the best way to accomplish this?
For validation, you can add this to your form class to allow fields outside the model:
$this->validatorSchema->setOption('allow_extra_fields', true);
$this->validatorSchema->setOption('filter_extra_fields', false); // true or false
Other than that, just adding the widget in the standard way should work fine.
Adding a new widget to your form should be the right way.
class ImageForm extends BaseImageForm
{
public function configure()
{
$this->widgetSchema['copyright'] = new sfWidgetFormInputCheckbox();
}
}
For conditional validation, check this cookbook page should still be valid.

How can I use the sfValidatorEmail validator in Symfony to validate a single email field

I have a form with 2 elements that will be submitted and then update part of a user profile.
I don't want to use the entire generated form and have to remove all the fields except for the two I need. I just want to be able to create a quite simple form to do my update.
Is there a way to utilize Symfony's sfValidatorEmail inside the action on the returned value of an email field?
Since the regex is already written in the validator, I would like to reuse it, but I don't know how to use it in the action after the non-symfony form has been submitted.
Two approaches here - you could construct a simple form anyway extending from sfForm/sfFormSymfony (doesn't have to be ORM-based) that just contains the 2 fields you want. That way you can use the existing validation framework, and then use $myForm->getValues() after everything has been validated to get your values for your profile update.
Alternatively, as you've mentioned, you can use the sfValidatorEmail class in your action like so:
$dirtyValue = "broken.email.address"
$v = new sfValidatorEmail();
try
{
$v->clean($dirtyValue);
}
catch (sfValidatorError $e)
{
// Validation failed
}
The latter approach quickly leads to messy code if you have many values that need cleaning, and it's worth putting the logic back into a form to handle this in the usual manner.
If you're submitting a form with 2 elements, it should be a form on the edit and update end, period. Symfony forms are lightweight, there's no performance reason to not use them. Instead, make a custom form for this purpose:
class ProfileUpdateForm extends ProfileForm
{
public function configure()
{
$this->useFields(array('email', 'other_field'));
}
}

Must I re-populate Zend_Form fields after the post back manually?

After a post back, suppose validation fails and I want to show the form again with errors, I find that the form is empty, must I repopulate the form fields manually?
The method isValid populate the form field. You don't have to repopulate manually.
I find the best way to handle form processing is to use something like
$form = new My_Form;
if ($this->getRequest()->isPost()
&& $form->isValid($this->getRequest()->getPost()) {
// process form and redirect (PRG pattern)
}
$this->view->form = $form;
This way, your form is shown on the first request and if not valid, is re-shown with the submitted values and any validation messages.
In case you are using some custom isValid don't forget your form also has a populate() function.
So
$data = $this->getRequest()->getPost();
if(!$myForm->isValid($data)){
$myForm->populate($data);
}
No need to do it by hand thats for sure.
Of course dont forget to assign the same object you did the isValid - populate calls on
$this->view->form = $myForm;
After the checks.