Search code examples
formsvalidationzend-framework2zend-formzend-form-element

How to make a field validation dependent on another field usind array form setup in ZF2?


In my form I have a field foo, that should be unique in the database table. So I added a Zend\Validator\Db\NoRecordExists to its validators list:

namespace Bar\Form\Fieldset;

use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
use Zend\Db\Adapter\AdapterInterface;

class BuzFieldset extends Fieldset implements InputFilterProviderInterface
{
    protected $dbAdapter;

    public function __construct($name = null, $options = []) {...}

    public function setDbAdapter(AdapterInterface $dbAdapter) {...}

    public function init()
    {
        $this->add([
            'name' => 'id',
            'type' => 'hidden'
        ]);
        $this->add(
            [
                'name' => 'foo',
                'type' => 'text',
                'options' => [...],
                'attributes' => [
                    'required' => 'required',
                    'class' => 'form-control'
                ]
            ]);
        ...
    }

    public function getInputFilterSpecification()
    {
        return [
            'foo' => [
                'required' => true,
                'validators' => [
                    [
                        'name' => 'Regex',
                        'options' => [
                            'pattern' => '/.../',
                            'message' => _(...)
                        ]
                    ],
                    [
                        'name' => 'Zend\Validator\Db\NoRecordExists',
                        'options' => [
                            'table' => 'buz',
                            'field' => 'foo',
                            'adapter' => $this->dbAdapter
                        ]
                    ]
                ]
            ],
            ...
        ];
    }
}

Now I want to use the same form for updating entries and of course cannot get the form validated. So I need to make the NoRecordExists validation for this field dependent on the field id. If id is set (that means, it's updating, not a creating), all validators (e.g. here Regex) should be applied, but this one not. How to do that?


Solution

  • You can have a look at the Callback validator. This validator will give you access to the form context allowing you to get the values of other fields. Use the NoRecordExists validator inside the Callback validator to make it dependend. Something like this. I didn't test this, but you'll get the idea.

    'foo' => [
        'required' => true,
        'validators' => [
            [
                'name' => 'Callback',
                'options' => [
                    'callback' => function($value, $context = []) {
                        if (empty($context['id'])) {
                            return $this->noRecordExistsValidator->isValid($value);
                        }
    
                        return true;
                    },
                ],
            ]
        ]
    ]
    

    You'll need to inject the NoRecordExistsValidator as a dependency to this form class, or better yet create a seperate InputFilter and corresponding factories which fully setup the InputFilter and inject that instance into the Fieldset object.