After taking a short break from Zend Framework 2 I started working on a new project in it. I created a Form class that looks like:
<?php namespace MyProject\Form; use ... class RegistrationForm extends Form { public function __construct($name = null) { parent::__construct('registration'); $this->add( array( 'name' => 'name', 'type' => 'Text', 'options' => array( 'label' => _t('Full name'), ), ) ); $this->add( array( 'name' => 'email', 'type' => 'Email', 'options' => array( 'label' => _t('Email'), ) ) ); } public function getInputFilter() { $inputFilter = new InputFilter(); $fullName = new Input('name'); $v = new ValidatorChain(); $v->attach(new StringLength(array('min' => 3))); $fullName->setValidatorChain($v); $fullName->setRequired(true); $inputFilter->add($fullName); $email = new Input('email'); $email->setRequired(true); $v = new ValidatorChain(); $v->attach(new EmailAddress()); $email->setValidatorChain($v); $inputFilter->add($email); return $inputFilter; } }
The problem arose when I validated the form and tried to access the data in the controller:
$form->setData($postData); if ($form->isValid()) { $data = $form->getData(); }
However, for some reason, the output of $data was missing values, something of this sort:
[ 'name' => null, 'email' => null, ]
So, the getData() keys were present, but values were missing!
It took me a while to figure out what’s going on. In order to validate the form, Zend Framework 2 calls getInputFilter on it. However, it does not store the resulting InputFilter, but rather calls this method again whenever it needs it – essentially overwriting any data put into it by $form->setData($postData);
The solution was to store form’s InputFilter as a static variable. The code now looks like this and behaves as expected:
<?php namespace MyProject\Form; use ... class RegistrationForm extends Form { /** * @var \Zend\InputFilter\InputFilter */ static private $inputFilter; public function __construct($name = null) { ... same as before ... } public function getInputFilter() { // Keep reusing the same instance of InputFilter if (isset(self::$inputFilter)) return self::$inputFilter; $inputFilter = new InputFilter(); $fullName = new Input('name'); $v = new ValidatorChain(); $v->attach(new StringLength(array('min' => 3))); $fullName->setValidatorChain($v); $fullName->setRequired(true); $inputFilter->add($fullName); $email = new Input('email'); $email->setRequired(true); $v = new ValidatorChain(); $v->attach(new EmailAddress()); $email->setValidatorChain($v); $inputFilter->add($email); // Make sure we store $inputFilter as a static variable return self::$inputFilter = $inputFilter; } }
Output of getData() looks like:
[ 'name' => 'User submitted name', 'email' => 'their@email.com', ]
Looks like a bug at the first glance, but I suppose this behavior allows for bigger flexibility when validating forms. I still have to find the good use for it, but oh well…