How do compare two values of a form in a validator?

I have a form that has 2 fields - fromDate and toDate. My implementation is that my validator extends the AbstractValidator and my implementation has the following snippet:

 */
    public function isValid($value) 
    {
       ....
      
        if( ($this->options['itemType']== 'fromDate') || 
            ($this->options['itemType']== 'toDate')  )
                $isDateRangeValid = $this->checkIfDateRangeIsValid($value); 
        /********************Net Validatation ***************************/    
		$isValid = true;
		//if any of the above criteria is invalid, isValid is false
		if!$isDateValid )
			$isValid = false;    
        ...
        // Return validation result.
        return $isValid;
        
    }

 public function checkIfDateRangeIsValid($date) {
    //it is here my dilemma is - how do I access 2 dates - fromDate and toDate since at a time only one //'value' is accessible

    }  

laminas-inputfilter is used within a form and this component sets a second parameter for the isValid method of a validator / validator chain:

The second parameter contains all the values set for the form / input filter.

Check the Identical validator as reference for the usage:

Here’s my implementation. I found this code somewhere online (Cannot recall the source for credits).

<?php

namespace CalendarModule\Validator;

use Carbon\Carbon;
use Laminas\Validator\AbstractValidator;

/**
 * Class BeforeDateValidator
 * @package CalendarModule\Service
 */
class BeforeDateValidator extends AbstractValidator
{
    /** @var string NOT_BEFORE */
    public const NOT_BEFORE = 'not-before';

    /** @var string NOT_A_VALID_DATE */
    public const NOT_A_VALID_DATE = 'not-a-date';

    /** @var array */
    protected array $messageTemplates = [
        self::NOT_BEFORE => "'%value%' should be before the end date.",
        self::NOT_A_VALID_DATE => "'%value%' is not a valid date.",
    ];

    /** @var mixed|string */
    protected string $dateTimeFormat = 'Y-m-d\TH:i';

    /** @var mixed|string */
    protected string $secondDateFieldName = 'endDateTime';

    /** @var bool|mixed */
    protected bool $strictlyBefore = false;

    /**
     * BeforeDateValidator constructor.
     * @param array|null $options
     */
    public function __construct(array $options = null)
    {
        if (is_array($options)) {
            if (array_key_exists('second_date_field', $options)) {
                $this->secondDateFieldName = $options['second_date_field'];
            }
            if (array_key_exists('date_format', $options)) {
                $this->dateTimeFormat = $options['date_format'];
            }
            if (array_key_exists('strict', $options)) {
                $this->strictlyBefore = $options['strict'];
            }
            if (array_key_exists('messages', $options)) {
                $this->messageTemplates = array_merge($this->messageTemplates, $options['messages']);
            }
        }
        parent::__construct($options);
    }

    /**
     * @param mixed $value
     * @param null $context
     * @return bool
     */
    public function isValid($value, $context = null): bool
    {
        $isValid = true;
        $date1 = Carbon::createFromFormat($this->dateTimeFormat, $value);
        if (!$date1) {
            $this->error(self::NOT_A_VALID_DATE, $value);
            $isValid = false;
        }

        $secondDateFieldValue = trim($context[$this->secondDateFieldName]);
        $date2 = Carbon::createFromFormat($this->dateTimeFormat, $secondDateFieldValue);
        if (!$date2) {
            $this->error(self::NOT_A_VALID_DATE, $secondDateFieldValue);
            $isValid = false;
        }

        if ($this->strictlyBefore) {
            if ($date1 >= $date2) {
                $this->error(self::NOT_BEFORE, $value);
                $isValid = false;
            }
        } elseif ($date1 > $date2) {
            $this->error(self::NOT_BEFORE, $value);
            $isValid = false;
        }

        return $isValid;
    }
}

And here’s the code from EventFormInputFilter.php.

/**
 * Class EventFormInputFilter
 * @package CalendarModule\InputFilter
 */
class EventFormInputFilter extends InputFilter
{
    /** */
    public function init()
    {
        parent::init();

        $this->add(
            [
                "name" => "startDateTime",
                "required" => false,
                "filters" => [
                    ["name" => Filter\StripTags::class],
                    ["name" => Filter\StringTrim::class],
                    ["name" => Filter\DateSelect::class],
                ],
                "validators" => [
                    [
                        "name" => Validator\Date::class,
                        "options" => [
                            "format" => "Y-m-d\TH:i",
                        ],
                    ],
                    [
                        'name' => BeforeDateValidator::class,
                        'options' => [
                            'second_date_field' => 'endDateTime',
                            'date_format' => 'Y-m-d\TH:i',
                            'strict' => false,
                            'messages' => [
                                BeforeDateValidator::NOT_BEFORE => "Start Date Time should be before the End Date Time.",
                                BeforeDateValidator::NOT_A_VALID_DATE => "\"%value%\" is not a valid Date Time.",
                            ],
                        ],
                    ],
                ],
            ]
        )->add(
            [
                "name" => "endDateTime",
                "required" => false,
                "filters" => [
                    ["name" => Filter\StripTags::class],
                    ["name" => Filter\StringTrim::class],
                    ["name" => Filter\DateSelect::class],
                ],
                "validators" => [
                    [
                        "name" => Validator\Date::class,
                        "options" => [
                            "format" => "Y-m-d\TH:i",
                        ],
                    ],
                ],
            ]
        );
    }
}
1 Like