Create "Date" rule

This commit is contained in:
Henrique Moody 2018-01-29 09:37:40 +01:00
parent c80524b457
commit 0db1cd6e1b
No known key found for this signature in database
GPG key ID: 221E9281655813A6
7 changed files with 286 additions and 0 deletions

45
docs/Date.md Normal file
View file

@ -0,0 +1,45 @@
# Date
- `Date()`
- `Date(string $format)`
Validates if input is a date. The `$format` argument should be in accordance to
PHP's [date()](http://php.net/date) function, but only those are allowed:
Format | Description | Values
--------|-----------------------------------------------------------------------|-------------------------
`d` | Day of the month, 2 digits with leading zeros | 01 to 31
`j` | Day of the month without leading zeros | 1 to 31
`S` | English ordinal suffix for the day of the month, 2 characters | st, nd, rd or th
`F` | A full textual representation of a month, such as January or March | January to December
`m` | Numeric representation of a month, with leading zeros | 01 to 12
`M` | A short textual representation of a month, three letters | Jan to Dec
`n` | Numeric representation of a month, without leading zeros | 1 to 12
`Y` | A full numeric representation of a year, 4 digits | Examples: 1988 or 2017
`y` | A two digit representation of a year | Examples: 88 or 17
When a `$format` is not given its default value is `Y-m-d`.
```php
v::date()->validate('2017-12-31'); // true
v::date()->validate('2020-02-29'); // true
v::date()->validate('2019-02-29'); // false
v::date('m/d/y')->validate('12/31/17'); // true
v::date('F jS, Y')->validate('May 1st, 2017'); // true
v::date('Ydm')->validate(20173112); // true
```
## Changelog
Version | Description
--------|-------------
2.0.0 | Created
***
See also:
- [DateTime](DateTime.md)
- [MinimumAge](MinimumAge.md)
- [LeapDate](LeapDate.md)
- [LeapYear](LeapYear.md)

View file

@ -130,6 +130,7 @@
- [Age](Age.md)
- [Between](Between.md)
- [Date](Date.md)
- [DateTime](DateTime.md)
- [LeapDate](LeapDate.md)
- [LeapYear](LeapYear.md)
@ -237,6 +238,7 @@
- [Cpf](Cpf.md)
- [CreditCard](CreditCard.md)
- [CurrencyCode](CurrencyCode.md)
- [Date](Date.md)
- [DateTime](DateTime.md)
- [Digit](Digit.md)
- [Directory](Directory.md)

View file

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Respect\Validation\Exceptions;
/**
* @author Bruno Luiz da Silva <contato@brunoluiz.net>
* @author Henrique Moody <henriquemoody@gmail.com>
*/
final class DateException extends ValidationException
{
/**
* {@inheritdoc}
*/
public static $defaultTemplates = [
self::MODE_DEFAULT => [
self::STANDARD => '{{name}} must be a valid date in the format {{sample}}',
],
self::MODE_NEGATIVE => [
self::STANDARD => '{{name}} must not be a valid date in the format {{sample}}',
],
];
/**
* {@inheritdoc}
*/
public function configure($name, array $params = [])
{
$params['sample'] = date(
$params['format'],
strtotime('2005-12-30')
);
return parent::configure($name, $params);
}
}

64
library/Rules/Date.php Normal file
View file

@ -0,0 +1,64 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Respect\Validation\Rules;
use function date_parse_from_format;
use function is_scalar;
use function preg_match;
use function sprintf;
use Respect\Validation\Exceptions\ComponentException;
/**
* Validates if input is a date.
*
* @author Bruno Luiz da Silva <contato@brunoluiz.net>
* @author Henrique Moody <henriquemoody@gmail.com>
*/
final class Date extends AbstractRule
{
/**
* @var string
*/
private $format;
/**
* Initializes the rule.
*
* @param string $format
*
* @throws ComponentException
*/
public function __construct(string $format = 'Y-m-d')
{
if (!preg_match('/^[djSFmMnYy\W]+$/', $format)) {
throw new ComponentException(sprintf('"%s" is not a valid date format', $format));
}
$this->format = $format;
}
/**
* {@inheritdoc}
*/
public function validate($input): bool
{
if (!is_scalar($input)) {
return false;
}
$info = date_parse_from_format($this->format, (string) $input);
return 0 === $info['error_count'] && 0 === $info['warning_count'];
}
}

View file

@ -51,6 +51,7 @@ use Respect\Validation\Rules\Key;
* @method static Validator currencyCode()
* @method static Validator cpf()
* @method static Validator creditCard(string $brand = null)
* @method static Validator date(string $format = 'Y-m-d')
* @method static Validator dateTime(string $format = null)
* @method static Validator digit(string $additionalChars = null)
* @method static Validator directory()

View file

@ -0,0 +1,37 @@
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\DateException;
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Validator as v;
try {
v::date()->check('2018-01-29T08:32:54+00:00');
} catch (DateException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::not(v::date())->check('2018-01-29');
} catch (DateException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::date()->assert('2018-01-29T08:32:54+00:00');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::not(v::date('d/m/Y'))->assert('29/01/2018');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
?>
--EXPECTF--
"2018-01-29T08:32:54+00:00" must be a valid date in the format "2005-12-30"
"2018-01-29" must not be a valid date in the format "2005-12-30"
- "2018-01-29T08:32:54+00:00" must be a valid date in the format "2005-12-30"
- "29/01/2018" must not be a valid date in the format "30/12/2005"

View file

@ -0,0 +1,91 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Respect\Validation\Rules;
use DateTime;
use DateTimeImmutable;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Test\RuleTestCase;
/**
* @group rule
*
* @covers \Respect\Validation\Rules\Date
*
* @author Bruno Luiz da Silva <contato@brunoluiz.net>
* @author Henrique Moody <henriquemoody@gmail.com>
*/
final class DateTest extends RuleTestCase
{
/**
* {@inheritdoc}
*/
public function providerForValidInput(): array
{
return [
[new Date(), '2017-12-31'],
[new Date('m/d/y'), '12/31/17'],
[new Date('F jS, Y'), 'May 1st, 2017'],
[new Date('Ydm'), 20173112],
[new Date(), '2020-02-29'],
];
}
/**
* {@inheritdoc}
*/
public function providerForInvalidInput(): array
{
return [
[new Date(), '1988-02-30'],
[new Date('d/m/y'), '12/31/17'],
[new Date(), '2019-02-29'],
[new Date(), new DateTime()],
[new Date(), new DateTimeImmutable()],
[new Date(), ''],
];
}
public function validFormatsProvider(): array
{
return [
['Y-m-d H:i:s'],
['c'],
];
}
/**
* @test
*
* @dataProvider validFormatsProvider
*/
public function shouldThrowAnExceptionWhenFormatIsNotValid(string $format): void
{
$this->expectException(ComponentException::class);
new Date($format);
}
/**
* @test
*/
public function shouldPassFormatToParameterToException(): void
{
$format = 'F jS, Y';
$equals = new Date($format);
$exception = $equals->reportError('input');
self::assertSame($format, $exception->getParam('format'));
}
}