Adding input filter to fieldset in ZF2

2019-05-07 00:41发布

I have a form Register, which has a fieldset Profile, which in turn has a fieldset Account. The fieldsets implement InputFilterProviderInterface and thus the getInputFilterSpecification method. This is where I have added general validators and filters that should be used whenever the fieldsets are used.

Now, in my registration form, I want to validate that an account with a given username does not already exist. Therefore I need to add a validator to complement the validators that are defined on the Account fieldset. This is where I got in trouble. After digging around a bit, I found a way to add input filters to fieldsets. This way, I figured, I could add an additional input filter to my Account fieldset.

class Register extends Zend\InputFilter\InputFilter
{
    public function __construct()
    {
        $this->add(new RegisterProfileFilter(), 'profile');
    }
}

With the above code, I am able to add an input filter to my Profile fieldset, and within that input filter, I can do the same for my account fieldset. However, it looks like there are two problems with this approach:

  1. It seems as if I have to create an input filter for each of my fieldsets in the hierarchy; in this case I have to create an input filter for the Profile fieldset just so that I can add an input filter to the Account fieldset - even if I don't need to add any validators or anything to the Profile fieldset. It doesn't work if I try to add the filter to the account fieldset directly
  2. It seems as if adding an input filter object to a fieldset wipes out the filter that I have defined in the fieldset's getInputFilterSpecification method instead of merging the two like I want

Is there a way to merge the input filter specification defined on my fieldsets with an additional specification (or instance of Zend\InputFilter\InputFilter such that I don't have to copy my fieldset specification into my input filter class? That would be duplicate code and not be very maintainable. Or did I miss something causing me to be on the wrong track?

Below is my code if it is helpful in any way.

// The code has been altered to be more self-explanatory and shorter

class RegisterForm extends \Zend\Form\Form
{
    public function __construct()
    {
        parent::__construct('register');

        // Elements are added here

        $profileFieldset = new ProfileFieldset();
        $profileFieldset->setUseAsBaseFieldset(true);
        $this->add($profileFieldset);
    }
}


class ProfileFieldset extends \Zend\Form\Fieldset implements InputFilterProviderInterface
{
    public function __construct()
    {
        parent::__construct('profile');

        // Elements are added here

        $this->add(new AccountFieldset());
    }

    public function getInputFilterSpecification()
    {
        return array(
            /***** The below is apparently cleared when adding an input filter to this fieldset *****/
            'some_element1' => array(
                'required' => false,
            ),
            'some_element2' => array(
                'required' => false,
            ),
        );
    }
}


class AccountFieldset extends \Zend\Form\Fieldset implements InputFilterProviderInterface
{
    public function __construct()
    {
        parent::__construct('account');

        // Elements are added here
    }

    public function getInputFilterSpecification()
    {
        return array(
            /***** This is the element that I want to add an additional validator to in a specific context (form) *****/
            'username' => array(
                'required' => true,
                'validators' => array(
                    new Validator\StringLength(array(
                        'min' => 4,
                        'max' => 15,
                    )),
                    new I18nValidator\Alnum(false),
                ),
            ),

            // Other elements here
        );
    }
}

1条回答
beautiful°
2楼-- · 2019-05-07 01:29

Merging InputFilters isn't very well covered in the Zend\Form component. Someone must really refactor the whole thing.

Anyway, what will work and therefore I would recommend in your situation, is adding the validator after the whole InputFilter has been created by overriding the getInputFilter method in your Form.

class RegisterForm extends \Zend\Form\Form
{
    public function __construct()
    {
        // add stuff
    }

    public function getInputFilter()
    {
        $formInputFilter = parent::getInputFilter();
        $usernameInput = $formInputFilter->get('profile')->get('account')->get('username');

        $myValidator = new Validator\SomeValidator();
        $usernameInput->getValidatorChain()->addValidator($myValidator);

        return $formInputFilter;
    }
}    

As a sidenote I would recommend defining InputFilters per Form basis and not per Fieldset, since elements in a Fieldset often have different "validation requirements" in different contexts(=Form). But maybe that's more a personal preference.

查看更多
登录 后发表回答