zendframework / zend-form

Form component from Zend Framework
BSD 3-Clause "New" or "Revised" License
69 stars 87 forks source link

DateTime min/max validators are not working when using costum format #190

Open BigMichi1 opened 6 years ago

BigMichi1 commented 6 years ago

given this input definition

        $this->add([
            'type' => DateTime::class,
            'name' => 'dutyDate',
            'options' => [
                'label' => 'duty date',
                'format' => 'd.m.Y H:i'
            ],
            'attributes' => [
                'min' => '01.01.2000 00:00',
                'max' => '31.12.2099 00:00',
            ]
        ]);

when you now enter '2.2.2199 12:43' it is accepted without causing the validator to fail

from what i have seen is that to the GreaterThan and LessThan validator the raw string is passed and compared with the raw string from the input definition. i suggest to fill the validator with real DateTime objects for 'value' and also 'min' and 'max'

ghost commented 6 years ago

the documentation clearly states that greaterThan etc validators only support numbers https://docs.zendframework.com/zend-validator/validators/greater-than/#only-supports-numbers building a custom isBefore validator should be quite easy

BigMichi1 commented 6 years ago

that is completly right but if these validators are added automatically if you specifiy min or max in the supported options. i implemented a new Element that replaces that validators but this is only workaround from my pointof view because if these validators are added automatically the should be added in the right way, i thunk.

namespace Administration\Element;

use Administration\Filter\ToDateTime;
use Zend\Filter\StringTrim;
use Zend\InputFilter\InputProviderInterface;
use Zend\Validator\GreaterThan;
use Zend\Validator\LessThan;

/**
 * Class DateTime.
 *
 * @package Administration\Element
 */
class DateTime extends \Zend\Form\Element\DateTime implements InputProviderInterface
{
    /**
     * @inheritdoc
     */
    public function getInputSpecification()
    {
        $validators = $this->getValidators();
        foreach ($validators as $validator) {
            if ($validator instanceof LessThan) {
                /** @var LessThan $validator */
                $validator->setMax(\DateTime::createFromFormat($this->getFormat(), $validator->getMax()));
            } elseif ($validator instanceof GreaterThan) {
                /** @var GreaterThan $validator */
                $validator->setMin(\DateTime::createFromFormat($this->getFormat(), $validator->getMin()));
            }
        }

        return [
            'name' => $this->getName(),
            'required' => true,
            'filters' => [
                ['name' => StringTrim::class],
                [
                    'name' => ToDateTime::class,
                    'options' => [
                        'format' => $this->getFormat(),
                    ],
                ],
            ],
            'validators' => $validators,
        ];
    }
}

and

namespace Administration\Filter;

use Zend\Filter\AbstractFilter;
use Zend\Filter\FilterInterface;

/**
 * Class ToDateTime
 *
 * @package Administration\Filter
 */
class ToDateTime extends AbstractFilter implements FilterInterface
{
    /**
     * @var string
     */
    protected $format = \DateTime::ISO8601;

    /**
     * @param array|\Traversable $options
     */
    public function __construct($options = null)
    {
        if ($options) {
            $this->setOptions($options);
        }
    }

    /**
     * @see \Zend\Filter\FilterInterface::filter()
     * @param  string $value
     * @return \DateTime
     */
    public function filter($value)
    {
        try {
            $date = (is_int($value)) ? new \DateTime($value) : \DateTime::createFromFormat($this->getFormat(), $value);
        } catch (\Exception $e) {
            $date = $value;
        }

        return $date;
    }

    /**
     * @return string
     */
    public function getFormat()
    {
        return $this->format;
    }

    /**
     * @param string $format
     * @return ToDateTime
     */
    public function setFormat($format)
    {
        $this->format = $format;
        return $this;
    }
}
ghost commented 6 years ago

TL;DR your are completely right. Since there are added automagically, they should probably handle date objects. a "nice to have"...

weierophinney commented 4 years ago

This repository has been closed and moved to laminas/laminas-form; a new issue has been opened at https://github.com/laminas/laminas-form/issues/7.