Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Utilize ValidatorManager to work with Custom Validator in Zend\Form

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on February 2, 2014

zf2-zendframework2ValidatorManager is a Plugin Manager that corresponding to Zend\Validator\ValidatorPluginManager, and used to manage validator instances. While we work with existing validators in Zend\Form, we can call validators in ‘validators’ key under inputFilter specification with the ‘invokables’ registered service at Zend\Validator\ValidatorPluginManager. In this post, I will propose detail way to work with custom validator.

For example, we have custom validator named Special to handle words with at least one special character in it, so the form when not valid will show like this :
form-validator-custom
So, we need to start with creating the validator like the following :

//filename : module/TutorialValidator/src/TutorialValidator/Validator/Special.php
namespace TutorialValidator\Validator;

use Zend\Validator\AbstractValidator;
                    
class Special extends AbstractValidator
{
    const NOTSPECIAL = 'NOTSPECIAL';

    protected $messageTemplates = array(
        self::NOTSPECIAL => 'Value should at least one special character',
    );
    
    public function __construct(array $options = array())
    {
       parent::__construct($options);
    }

    public function isValid($value)
    {
       $this->setValue($value);
       
       $special   = preg_match('#[\W]{1,}#', $value);

       if (!$special) {
           $this->error(self::NOTSPECIAL);
           return false;
       }

       return true;
    }
}

And we need to use it to validate the forms, so we need to register the validator in ‘validators’ key in our configuration:

//filename : module/TutorialValidator/config/module.config.php
'validators' => array(
    'invokables' => array(
        'Special' => 'TutorialValidator\Validator\Special'  
     ),
),

There are two ways to build form with custom validator.

A. We can use Zend\Form\FormAbstractServiceFactory that can be configured via ‘forms’ key in configuration files.
To do this, we need to :
1. register Zend\Form\FormAbstractServiceFactory into configuration

//filename : module/TutorialValidator/config/module.config.php
'service_manager' => array(
    //other service registration here...
    'abstract_factories' => array(
        'Zend\Form\FormAbstractServiceFactory',
    ),
    //other service registration here...
),

2. And then, configure the ‘forms’

//filename : module/TutorialValidator/config/module.config.php
'forms' => array(
    'SampleForm' => array(
        'hydrator' => 'ObjectProperty',
        'type'     => 'Zend\Form\Form',
        'elements' => array(
            array(
                'spec' => array(
                    'type' => 'Text',
                    'name' => 'sampleinput',
                    'options' => array(
                        'label' => 'Sample Input:',
                    )
                ),
            ),
            array(
                'spec' => array(
                    'type' => 'Submit',
                    'name' => 'submit',
                    'attributes' => array(
                        'value' => 'Go',
                    )
                ),
            ),
        ),
        'input_filter' => array(
            'sampleinput' => array(
                'required'   => true,
                'validators' => array(
                    array(
                        'name' => 'Special',
                    ),
                ),
            ),
        ),
    ),
),

SampleForm is a registered form service that can be called via ‘FormElementManager’ manager. Special is a custom validator that registered at ‘validators’ key or getValidatorConfig() under Module class.

B. Using form class
For form class, we need to implements Zend\InputFilter\InputFilterProviderInterface and implement method getInputFilterSpecification :
To do this, we need to :
1. create the form class

//filename : module/TutorialValidator/src/TutorialValidator/Form/SampleForm.php
namespace TutorialValidator\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;

class SampleForm extends Form implements InputFilterProviderInterface
{
    public function init()
    {
        $this->add(array(
            'name' => 'sampleinput',
            'type' => 'Text',
            'options' => array(
                'label' => 'Sample Input: ',
            ),
        ));

        $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                'type'  => 'submit',
                'value' => 'Go',
                'id' => 'submitbutton',
            ),
        ));
    }

    public function getInputFilterSpecification()
    {
        return array(
            array(
                'name' => 'sampleinput',
                'required' => true,
                'validators' => array(
                    array('name' => 'Special'),
                ),
            ),
        );
    }
}

2. Register form service in ‘form_elements’ key in config

//filename : module/TutorialValidator/config/module.config.php
'form_elements' => array(
    'invokables' => array(
        'SampleForm' => 'TutorialValidator\Form\SampleForm'
    ),                         
),

When everything is OK, we can call the form via ‘FormElementManager’ in controller ( you can inject controller with SampleForm service via ‘factories’ key of course :)) :

    public function indexAction()
    {
        $form = $this->getServiceLocator()
                     ->get('FormElementManager')
                     ->get('SampleForm');
        
        $request = $this->getRequest();
        if ($request->isPost()) {
            $form->setData($request->getPost());
            if ($form->isValid()) {
                echo 'Great!form is valid';
            }
        }
        
        $viewmodel = new ViewModel;
        $viewmodel->setVariable('form', $form);
        
        return $viewmodel;
    }

Done. I’ve uploaded the sample code to my github account : https://github.com/samsonasik/TutorialValidator . Hope it helpful 😉

Note : Thanks to Daniel Gimenes for the suggestion to this post and make a PR to my repository on github.
danizord-suggestion-on-getInputFilterSpecification

References :
1. http://zf2.readthedocs.org/en/latest/modules/zend.mvc.services.html
2. http://stackoverflow.com/questions/19642139/possible-to-create-a-factory-to-instantiate-custom-form-validators
3. http://stackoverflow.com/questions/13476164/zend-framework-2-custom-validators-for-forms
4. https://github.com/samsonasik/TutorialValidator/pull/1