zf2 validation: How can I validate dependent field

2020-02-08 16:08发布

问题:

How can I set a input filter which is dependent from another input field. I want to verify that the 'apDepTime' field is more than 'apArrTime'.

How can i handle this in zf2?

I also want to note that I am using 'Date validator'.

Please help me anybody.

FlightDataForm.php

<?php

namespace FcFlight\Form;

use Zend\Form\Form;
use Zend\Form\Element;

class FlightDataForm extends Form
{
/**
 * @var string
 */
protected $_formName = 'flightData';

/**
 * @param null $name
 * @param array $options
 */
public function __construct($name = null)
{
    if (!is_null($name)) {
        $this->_formName = $name;
    }

    parent::__construct($this->_formName);

    //Fieldset Ap Dep
    $this->add(array(
        'name'          => 'apDep',
        'type'          => 'Zend\Form\Fieldset',
        'options'       => array(
            'legend'        => 'App Dep',
        ),
        'elements'      => array(
            array(
                'spec' => array(
                    'name' => 'apDepTime',
                    'type' => 'Zend\Form\Element\Text',
                    'attributes' => array(
                        'required' => true,
                        'maxlength' => '5',
                        'id' => 'apDepTime',
                    ),
                    'options' => array(
                        'label' => 'Time',
                        'hint' => 'HH:MM',
                        'description' => 'UTC',
                    ),
                ),
            ),
        ),
    ));

    //Fieldset Ap Arr
    $this->add(array(
        'name'          => 'apArr',
        'type'          => 'Zend\Form\Fieldset',
        'options'       => array(
            'legend'        => 'App Arr',
        ),
        'elements'      => array(
            //apArrTime
            array(
                'spec' => array(
                    'name' => 'apArrTime',
                    'type' => 'Zend\Form\Element\Text',
                    'attributes' => array(
                        'required' => true,
                        'maxlength' => '5',
                        'id' => 'apArrTime',
                    ),
                    'options' => array(
                        'label' => 'Time',
                        'hint' => 'HH:MM',
                        'description' => 'UTC',
                    ),
                ),
            ),
        ),
    ));

    $this->add(new Element\Csrf('csrf'));

    //Submit button
    $this->add(array(
        'name' => 'submitBtn',
        'attributes' => array(
            'type' => 'submit',
            'value' => 'Add',
        ),
    ));

}
}

FlightDataFilter.php

<?php
namespace FcFlight\Filter;

use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\Db\Adapter\Adapter;

class FlightDataFilter implements InputFilterAwareInterface
{

/**
 * @var $inputFilter
 */
protected $inputFilter;

/**
 * @var $dbAdapter
 */
protected $dbAdapter;

/**
 * @var string
 */
protected $table = '';

public $apDepTime;
public $apArrTime;

/**
 * @param \Zend\Db\Adapter\Adapter $dbAdapter
 */
public function __construct(Adapter $dbAdapter)
{
    $this->dbAdapter = $dbAdapter;
}

/**
 * @return \Zend\Db\Adapter\Adapter
 */
public function getDbAdapter()
{
    return $this->dbAdapter;
}

/**
 * Array to Object
 *
 * @param array $data
 */
public function exchangeArray(array $data)
{
    $this->apDepTime = (isset($data['apDep']['apDepTime'])) ? $data['apDep']['apDepTime'] : null;
    $this->apArrTime = (isset($data['apArr']['apArrTime'])) ? $data['apArr']['apArrTime'] : null;
}

/**
 * @return array
 */
public function getArrayCopy()
{
    return get_object_vars($this);
}

/**
 * @param InputFilterInterface $inputFilter
 * @return void|InputFilterAwareInterface
 * @throws \Exception
 */
public function setInputFilter(InputFilterInterface $inputFilter)
{
    throw new \Exception("Not used");
}


/**
 * @return \Zend\InputFilter\InputFilter|\Zend\InputFilter\InputFilterInterface
 */
public function getInputFilter()
{
    if (!$this->inputFilter) {

        $inputFilter = new InputFilter();
        $factory = new InputFactory();

        $flightNumberInputFilter = new InputFilter();

        $flightNumberInputFilter->add($factory->createInput(array(
            'name' => 'flightNumberIdIcao',
            'required' => true,
        )));

        $apDepInputFilter = new InputFilter();

        $apDepInputFilter->add($factory->createInput(array(
            'name' => 'apDepTime',
            'required' => true,
            'validators' => array(
                array(
                    'name' => 'Date',
                    'options' => array(
                        'format' => 'H:i',
                    ),
                ),
            ),
        )));

        $inputFilter->add($apDepInputFilter, 'apDep');

        $apArrInputFilter = new InputFilter();

        $apArrInputFilter->add($factory->createInput(array(
            'name' => 'apArrTime',
            'required' => true,
            'validators' => array(
                array(
                    'name' => 'Date',
                    'options' => array(
                        'format' => 'H:i',
                    ),
                ),
                array(
                    'name' => 'Callback',
                    'options' => array(
                        'messages' => array(
                            \Zend\Validator\Callback::INVALID_VALUE => 'The arrival time is less than the departure time',
                        ),
                        'callback' => function($value, $context = array()) {
                            // value of this input
                            $apArrTime = \DateTime::createFromFormat('H:i', $value);
                            // value of input to check against from context
                            $apDepTime = \DateTime::createFromFormat('H:i', $context['apDepTime']);
                            // compare times, eg..
                            return $apDepTime > $apArrTime;
                        },
                    ),
                ),
            ),
        )));

        $inputFilter->add($apArrInputFilter, 'apArr');

        $this->inputFilter = $inputFilter;
    }

    return $this->inputFilter;
}
}

回答1:

You can use the Zend\Validator\Callback validator for this

The first parameter passed to your callback is the value of the input to which the validator is applied.

The second parameter is an array of your other form values keyed by input names and represents the context in which you want to compare values.

As a simple example...

    $apArrInputFilter->add($factory->createInput(array(
        'name' => 'apArrTime',
        'required' => true,
        'validators' => array(
                array(
                    'name' => 'Callback',
                    'options' => array(
                        'messages' => array(
                            \Zend\Validator\Callback::INVALID_VALUE => 'The departure time is less than the arrival time',
                        ),
                        'callback' => function($value, $context=array()) {
                            // value of this input
                            $apArrTime = $value;
                            // value of input to check against from context
                            $apDepTime = $context['apDepTime'];
                            // compare times, eg..
                            $isValid = $apDepTime > $apArrTime;
                            return $isValid;
                        },
                    ),
                ),
        ),
    )));

Obviously you'll need to write code to your needs for the actual date comparison, but that should get you started.



回答2:

You could also use a different approach. Usa an InputFilter to define youre own isValid() function.

Tell youre form to use an InputFilter.

$this->setInputFilter(new Filter\MyFilter());

Implement your own isValid() function.

namespace Application\Form\Filter;

use Zend\InputFilter\InputFilter;  
use Zend\Validator;  
use Zend\Filter;

class MyFilter extends InputFilter  
{
    public function isValid($context = null)
    {
        // add your dependent validation 
    }

    public function __construct()
    {
        // Add youre form field validations
    }

http://theabstract.de/zf2-dynamic-form-validation/