Combining input filters in Zend Framework 2

I have several fields, and I would like to create an input filter class for each of them. The idea is that for each of my forms I can create an input filter class that consists of other input filters. For example, when creating an account through the registration form, I would like to use the basic input filter Account for my Account object and use it in a new class of input filters, which can change inputs or add additional ones, Something like 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 the input filter to the constructor, and I want to add the inputs of this filter to my Register filter and change the inputs.

The problem I am facing is that only some of my inputs seem to confirm what was supposed to, and I cannot understand why. When I submit my form, only some inputs are checked as expected:

Postback result

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

Debugging POST request

The form filter has the correct inputs with the correct validators, and as shown in the image above, the username input seems to be validated 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()); } } 

The 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)); 

I do not understand something? Is there a better way to do this while still having multiple input filter classes? I would rather keep my code maintained in this way, rather than copy validation rules for different forms. Sorry for the long post - it was very difficult to explain this problem!

+6
source share
2 answers

Well, it looks like I figured it out. Apparently my first approach was completely wrong. I found a way to have a class of input filters for each of my fields, and then reuse these input filters for my form, adding additional validation rules for certain form elements (from my fields). Thus, I can have general validation rules defined in the standard input filter classes for each set of fields, and change them for different contexts (i.e. Forms). Below is the code. Classes are slightly different from the question because it was a bit simplified.

Main input filter

 // This input filter aggregates the "fieldset input filters" and adds additional validation rules class Register extends InputFilter { public function __construct(ObjectRepository $accountRepository, InputFilter $profileFilter) { /***** ADD ADDITIONAL VALIDATION RULES *****/ // Username $usernameAvailability = new NoObjectExists(array( 'object_repository' => $accountRepository, 'fields' => array('username'), )); $emailInput = $profileFilter->get('account')->get('username'); $emailInput->getValidatorChain()->attach($usernameAvailability, true); // E-mail $emailAvailability = new NoObjectExists(array( 'object_repository' => $accountRepository, 'fields' => array('email'), )); $emailInput = $profileFilter->get('account')->get('email'); $emailInput->getValidatorChain()->attach($emailAvailability, true); /***** ADD FIELDSET INPUT FILTERS *****/ $this->add($profileFilter, 'profile'); } } 

Profile Entry Filter

 class Profile extends InputFilter { public function __construct(InputFilter $accountFilter) { $this->add($accountFilter, 'account'); // Add generic validation rules (inputs) for the profile fieldset here } } 

The Account input filter mentioned in the code above is a completely normal input filter class that extends Zend\InputFilter\InputFilter and adds inputs. Nothing special about that.

My fields remain untouched and identical to those asked in the question, as well as the form class and controller. The Register input filter is added to the form using the setInputFilter method and what is it!

With this approach, each instance of the input filter is added to the set of fields - something that my first approach did not perform. Hope this helps someone with similar problems!

+1
source

I have a User object with some validators specified in it.

But I want to expand this list of validators to add one based on a service call, to check if user email is being used.

The problem is that I need an object manager, which is entered into the validator to call the service. And I can’t (or rather, I don’t know how I don’t want to :-) introduce an entity manager into an entity.

I also want to leave the existing entity check in place, as it is closer to the repository and can be used outside my controller. Therefore, I cannot transfer all validators from this entity to my new custom filter.

My new custom filter will thus reuse existing object validators as is.

The new custom filter is called UserFormFilter , and it receives an existing entity filter in its controller, loops on it, adding to itself, each of the transferred ones in the validators:

 class UserFormFilter extends InputFilter { public function __construct(EntityManager $em, $identity, InputFilter $userDefaultInputFilter) { // Add the validators specified in the user entity foreach ($userDefaultInputFilter->inputs as $inputFilter) { $this->add($inputFilter); } $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array(), 'validators' => array( array('name' => 'EmailAddress'), array( 'name' => 'Application\Validator\User', 'options' => array('manager' => $em, 'identity' => $identity) ) ), )); } } 

Now I can create an instance of the custom UserFormFilter in my UserController:

 $formFilter = new \Application\Form\UserFormFilter($em, $user->getInputFilter()); $form->setInputFilter($formFilter); 

In the above code, you can see that the user UserFormFilter accepts the default filter specified in my User entity getInputFilter method. As an additional note, it also passes an entity manager, which allows the custom filter to make a service call.

0
source

Source: https://habr.com/ru/post/969873/


All Articles