Skip to content
This repository has been archived by the owner on Jan 31, 2020. It is now read-only.

Strict mode for Date validator #275

Merged
merged 4 commits into from
Dec 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/book/validators/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,24 @@ $validator = new Zend\Validator\Date(['format' => 'Y']);
$validator->isValid('2010'); // returns true
$validator->isValid('May'); // returns false
```

## Strict mode

- **Since 2.13.0**

By default, `Zend\Validator\Date` only validates that it can convert the
provided value to a valid `DateTime` value.

If you want to require that the date is specified in a specific format, you can
provide both the [date format](#specifying-a-date-format) and the `strict`
options. In such a scenario, the value must both be covertable to a `DateTime`
value **and** be in the same format as provided to the validator. (Generally,
this will mean the value must be a string.)

```php
$validator = new Zend\Validator\Date(['format' => 'Y-m-d', 'strict' => true]);

$validator->isValid('2010-10-10'); // returns true
$validator->isValid(new DateTime('2010-10-10)); // returns false; value is not a string
$validator->isValid('2010.10.10'); // returns false; format differs
```
26 changes: 24 additions & 2 deletions src/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2019 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

Expand Down Expand Up @@ -56,6 +56,11 @@ class Date extends AbstractValidator
*/
protected $format = self::FORMAT_DEFAULT;

/**
* @var bool
*/
protected $strict = false;

/**
* Sets validator options
*
Expand Down Expand Up @@ -100,6 +105,17 @@ public function setFormat($format = self::FORMAT_DEFAULT)
return $this;
}

public function setStrict(bool $strict) : self
{
$this->strict = $strict;
return $this;
}

public function isStrict() : bool
{
return $this->strict;
}

/**
* Returns true if $value is a DateTime instance or can be converted into one.
*
Expand All @@ -110,11 +126,17 @@ public function isValid($value)
{
$this->setValue($value);

if (! $this->convertToDateTime($value)) {
$date = $this->convertToDateTime($value);
if (! $date) {
$this->error(self::INVALID_DATE);
return false;
}

if ($this->isStrict() && $date->format($this->getFormat()) !== $value) {
$this->error(self::FALSEFORMAT);
return false;
}

return true;
}

Expand Down
89 changes: 54 additions & 35 deletions test/DateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2019 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

Expand Down Expand Up @@ -44,48 +44,55 @@ public function testSetFormatIgnoresNull()
public function datesDataProvider()
{
return [
// date format isValid
['2007-01-01', null, true],
['2007-02-28', null, true],
['2007-02-29', null, false],
['2008-02-29', null, true],
['2007-02-30', null, false],
['2007-02-99', null, false],
['2007-02-99', 'Y-m-d', false],
['9999-99-99', null, false],
['9999-99-99', 'Y-m-d', false],
['Jan 1 2007', null, false],
['Jan 1 2007', 'M j Y', true],
['asdasda', null, false],
['sdgsdg', null, false],
['2007-01-01something', null, false],
['something2007-01-01', null, false],
['10.01.2008', 'd.m.Y', true],
['01 2010', 'm Y', true],
['2008/10/22', 'd/m/Y', false],
['22/10/08', 'd/m/y', true],
['22/10', 'd/m/Y', false],
// date format isValid isValid Strict
['2007-01-01', null, true, true],
['2007-02-28', null, true, true],
['2007-02-29', null, false, false],
['2008-02-29', null, true, true],
['2007-02-30', null, false, false],
['2007-02-99', null, false, false],
['2007-02-99', 'Y-m-d', false, false],
['9999-99-99', null, false, false],
['9999-99-99', 'Y-m-d', false, false],
['Jan 1 2007', null, false, false],
['Jan 1 2007', 'M j Y', true, true],
['asdasda', null, false, false],
['sdgsdg', null, false, false],
['2007-01-01something', null, false, false],
['something2007-01-01', null, false, false],
['10.01.2008', 'd.m.Y', true, true],
['01 2010', 'm Y', true, true],
['2008/10/22', 'd/m/Y', false, false],
['22/10/08', 'd/m/y', true, true],
['22/10', 'd/m/Y', false, false],
// time
['2007-01-01T12:02:55Z', DateTime::ISO8601, true],
['12:02:55', 'H:i:s', true],
['25:02:55', 'H:i:s', false],
['2007-01-01T12:02:55Z', DateTime::ISO8601, true, false],
['2007-01-01T12:02:55+0000', DateTime::ISO8601, true, true],
['12:02:55', 'H:i:s', true, true],
['25:02:55', 'H:i:s', false, false],
// int
[0, null, true],
[1340677235, null, true],
[0, null, true, false],
[6, 'd', true, false],
['6', 'd', true, false],
['06', 'd', true, true],
[123, null, true, false],
[1340677235, null, true, false],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe also add Unix timestamp with a format here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is that input argument must be string even for U format. Output of DateTime::format is always a string.

[1340677235, 'U', true, false],
['1340677235', 'U', true, true],
// 32bit version of php will convert this to double
[999999999999, null, true],
[999999999999, null, true, false],
// double
[12.12, null, false],
[12.12, null, false, false],
// array
[['2012', '06', '25'], null, true],
[['2012', '06', '25'], null, true, false],
// 0012-06-25 is a valid date, if you want 2012, use 'y' instead of 'Y'
[['12', '06', '25'], null, true],
[['2012', '06', '33'], null, false],
[[1 => 1], null, false],
[['12', '06', '25'], null, true, false],
[['2012', '06', '33'], null, false, false],
[[1 => 1], null, false, false],
// DateTime
[new DateTime(), null, true],
[new DateTime(), null, true, false],
// invalid obj
[new stdClass(), null, false],
[new stdClass(), null, false, false],
];
}

Expand All @@ -100,6 +107,18 @@ public function testBasic($input, $format, $result)
$this->assertEquals($result, $this->validator->isValid($input));
}

/**
* @dataProvider datesDataProvider
*
* @param mixed $input
*/
public function testBasicStrictMode($input, ?string $format, bool $result, bool $resultStrict) : void
{
$this->validator->setStrict(true);
$this->validator->setFormat($format);
$this->assertSame($resultStrict, $this->validator->isValid($input));
}

public function testDateTimeImmutable()
{
$this->assertTrue($this->validator->isValid(new DateTimeImmutable()));
Expand Down