I have a number of fieldsets, and I would like to create an input filter class for each of them. The idea is then that for each of my forms, I can create an input filter class that is composed of other input filters. For instance, when creating an account via a registration form, I would like to take the base Account input filter I have for my Account entity and use it in a new input filter class that can modify the inputs or add additional ones. Something like the below.
class Register extends InputFilter
{
public function __construct(ObjectRepository $accountRepository, Account $accountFilter)
{
/***** Add inputs from input filters *****/
$this->inputs = $accountFilter->getInputs();
/***** Add additional validation rules *****/
// Username
$usernameAvailability = new NoObjectExists(array(
'object_repository' => $accountRepository,
'fields' => array('username'),
));
$username = $this->get('username');
$username->getValidatorChain()
->attach($usernameAvailability, true);
// E-mail
$emailAvailability = new NoObjectExists(array(
'object_repository' => $accountRepository,
'fields' => array('email'),
));
$email = $this->get('email');
$email->getValidatorChain()
->attach($emailAvailability, true);
}
}
I pass in an input filter to the constructor, and I want to add the inputs of this filter to my Register filter and modify the inputs.
The problem I am having is that only some of my inputs seem to validate as intended, and I cannot seem to figure out why. When I submit my form, only some inputs are validated as expected:

Interestingly, the e-mail input does not behave as expected when filling out an e-mail that already exists in my database. The result should be a validation error that it already exists, but this does not happen. If I debug and look at my form, I found the following:

The form's filter has the right inputs with the right validators, and as shown on the above image, the username input does seem to validate correctly. But for some reason, this is not visually reflected in my form.
Below is my code.
Fieldsets
class Profile extends Fieldset
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('profile');
$this->setHydrator(new DoctrineHydrator($objectManager))
->setObject(new ProfileEntity());
// Elements go here
$this->add(new AccountFieldset($objectManager));
}
}
class Account extends Fieldset
{
public function __construct()
{
parent::__construct('account');
$username = new Element\Text('username');
$username->setLabel('Username');
$password = new Element\Password('password');
$password->setLabel('Password');
$repeatPassword = new Element\Password('repeatPassword');
$repeatPassword->setLabel('Repeat password');
$email = new Element\Email('email');
$email->setLabel('E-mail address');
$birthdate = new Element\DateSelect('birthdate');
$birthdate->setLabel('Birth date');
$gender = new Element\Select('gender');
$gender->setLabel('Gender')
->setEmptyOption('Please choose')
->setValueOptions(array(
1 => 'Male',
2 => 'Female',
));
$this->add($username);
$this->add($password);
$this->add($repeatPassword);
$this->add($email);
$this->add($birthdate);
$this->add($gender);
$this->add(new CityFieldset());
}
}
Form
class Register extends Form
{
public function __construct()
{
parent::__construct('register');
// Terms and Conditions
$terms = new Element\Checkbox('terms');
$terms->setLabel('I accept the Terms and Conditions');
$terms->setCheckedValue('yes');
$terms->setUncheckedValue('');
$terms->setAttribute('id', $terms->getName());
// Submit button
$submit = new Element\Submit('btnRegister');
$submit->setValue('Register');
$profileFieldset = new ProfileFieldset($objectManager);
$profileFieldset->setUseAsBaseFieldset(true);
// Add elements to form
$this->add($terms);
$this->add($profileFieldset);
$this->add($submit);
}
}
View
$form->prepare();
echo $this->form()->openTag($form);
$profile = $form->get('profile');
$account = $profile->get('account');
echo $this->formRow($account->get('username'));
echo $this->formRow($account->get('password'));
echo $this->formRow($account->get('repeatPassword'));
echo $this->formRow($account->get('email'));
echo $this->formRow($account->get('birthdate'));
echo $this->formRow($account->get('gender'));
$city = $account->get('city');
echo $this->formRow($city->get('postalCode'));
echo $this->formRow($form->get('terms'));
echo $this->formSubmit($form->get('btnRegister'));
echo $this->form()->closeTag();
Controller
$form = new Form\Register();
$profile = new Profile();
if ($this->request->isPost()) {
$form->bind($profile);
$form->setData($this->request->getPost());
$form->setInputFilter($this->serviceLocator->get('Profile\Form\Filter\Register'));
if ($form->isValid()) {
// Do stuff
}
}
return new ViewModel(array('form' => $form));
Am I misunderstanding something here? Is there a better way to do this while still having multiple input filter classes? I would really prefer to keep my code maintainable like this rather than copying validation rules around for different forms. Sorry for the long post - it was really difficult to explain this problem!