I am experiencing what to me is strange behavior when submitting and validating my Zend Framework 2 form. I have cut my form down to three elements to demonstrate what I mean, but the problem exists with other elements as well.
I have two elements; e-mail and gender. I have not specified an InputFilter for my form, so my logic tells me that my form will be valid. However, when I submit the form and do a validation check, the e-mail and gender elements give the Value is required and can't be empty error. However, I haven’t explicitly said they they are required and cannot be empty.
My e-mail element is of the type Zend\Form\Element\Email and I suspect that might have something to do with it, because if I change it to Zend\Form\Element\Text, everything is fine. But what if I want to have an e-mail field that is not required?
Next, my gender select element gives me the same error. I set the empty option, but I thought this was just for using a default value, e.g. “Select your gender”, but that it did not add a required constraint. It appears that if I remove this empty option, then I do not get this error. What is also very strange about this error is that if I do not choose a gender and submit my form, then a different option is selected in the dropdown on postback. In this case, I am submitting the form with the empty option (“Choose your gender”), but then the selected option changes to “Female” when the form is refreshed. The “Female” option has a value of 0, but if I change the value to 3, for example, it works fine. But what if I need to have a value of 0 in one of my options? Maybe it’s caused by a type conversion or something. I really don’t know.
Below is my code. I have written some comments so it may be easier to understand.
Form class excerpt:
// E-mail (generates "Value is required and can't be empty" - but what if the field should be optional? Where is this validator added?
$email = new Element\Email('email'); // If I change to "Element\Text", there are no problems
$email->setLabel('E-mail address');
$email->setLabelAttributes(array(
'for' => $email->getName(),
'class' => 'some class'
));
$email->setAttributes(array(
'id' => $email->getName(),
'placeholder' => 'E.g. andy@gmail.com',
'class' => 'some class'
));
// Gender dropdown (generates "Value is required and can't be empty error")
$gender = new Element\Select('gender');
$gender->setLabel('Gender');
$gender->setEmptyOption('Choose your gender'); // Remove this and the error disappears
$gender->setLabelAttributes(array(
'for' => $gender->getName(),
'class' => 'some class'
));
$gender->setAttributes(array(
'id' => $gender->getName(),
'class' => 'some class'
));
$gender->setValueOptions(array(
'1' => 'Male',
'0' => 'Female' // This is selected on postback when the empty option is selected. If I change the value to 3, for instance, it works fine
));
$this->add($email);
$this->add($gender);
Controller:
public function registerAction() {
$registerForm = new RegisterForm();
$request = $this->getRequest();
if ($request->isPost()) {
$registerForm->setData($request->getPost());
if ($registerForm->isValid()) {
// Nothing here yet
}
}
return new ViewModel(array('form' => $registerForm));
}
View script excerpt:
$form = $this->form;
$email = $form->get('email');
$gender = $form->get('gender');
// E-mail
echo $this->formLabel()->openTag($email) . $email->getLabel() . $this->formLabel()->closeTag();
echo $this->formInput($email);
echo $this->formElementErrors($email);
// Gender
echo $this->formLabel()->openTag($gender) . $gender->getLabel() . $this->formLabel()->closeTag();
echo $this->formSelect($gender);
echo $this->formElementErrors($gender);
I apologize if I did not explain the problems well enough, but it is really hard to explain because it seems so strange to me. I looked in the documentation, but I couldn’t find anything useful (the ZF2 documentation is still rather poor in my opinion).
Many people loathed the forms in ZF1.x for the decorators but I loved it nonetheless. What is the worst part for me with ZF2 is that you can basically throw out all your knowledge because like so many things in ZF2 it has completely changed.
There is the new (HTML5) email element but it comes with a hard coded required constraint. Similar stuff happens with select elements. In ZF1 you had the
setRequired()method on the element but it is now moved back into what are “inputs” in the form. In other word you have to get the inputs first.Now your form should accept empty submissions.
UPDATE: As for the postback problem.
It all depends on the data you set with
setData(). This could be either the POST data or on a redirect data from a session. If you submit without a selection the POST data you get should not have any “gender” data and so should the data you set into the form.UPDATE 2
It looks like the root problem is that an empty gender value is submitted and POST values are always strings, hence an empty value is of type string with length 0. Looking into
Form\View\Helper\FormSelectand the rendering of the option you will find ain_array($value, $selectedOptions)function handling the selected attribute. Unfortunately they don’t set the strict flag and without that a0(zero) value matches an empty string.So, either filter/remove this empty value from the POST or change the empty string to NULL before you’ll add it to setData() then it will be droped as a selected option. Additionally if you can of course add/change the strict option in the Zend class (which I wouldn’t do).