Create "Time" rule

This commit is contained in:
Henrique Moody 2018-01-30 09:29:45 +01:00
parent 0db1cd6e1b
commit 2007c7dc6e
No known key found for this signature in database
GPG key ID: 221E9281655813A6
8 changed files with 293 additions and 0 deletions

View file

@ -43,3 +43,4 @@ See also:
- [MinimumAge](MinimumAge.md)
- [LeapDate](LeapDate.md)
- [LeapYear](LeapYear.md)
- [Time](Time.md)

49
docs/Time.md Normal file
View file

@ -0,0 +1,49 @@
# Time
- `Time()`
- `Time(string $format)`
Validates whether an input is a time or not. The `$format` argument should be in
accordance to PHP's [date()](http://php.net/date) function, but only those are
allowed:
Format | Description | Values
--------|----------------------------------------------------|--------
`g` | 12-hour format of an hour without leading zeros | 1 through 12
`G` | 24-hour format of an hour without leading zeros | 0 through 23
`h` | 12-hour format of an hour with leading zeros | 01 through 12
`H` | 24-hour format of an hour with leading zeros | 00 through 23
`i` | Minutes with leading zeros | 00 to 59
`s` | Seconds, with leading zeros | 00 through 59
`u` | Microseconds | 000000 through 999999
`v` | Milliseconds | 000 through 999
`a` | Lowercase Ante meridiem and Post meridiem | am or pm
`A` | Uppercase Ante meridiem and Post meridiem | AM or PM
When a `$format` is not given its default value is `H:i:s`.
```php
v::time()->validate('00:00:00'); // true
v::time()->validate('23:20:59'); // true
v::time('H:i')->validate('23:59'); // true
v::time('g:i A')->validate('8:13 AM'); // true
v::time('His')->validate(232059); // true
v::time()->validate('24:00:00'); // false
v::time()->validate(new DateTime()); // false
v::time()->validate(new DateTimeImmutable()); // false
```
## Changelog
Version | Description
--------|-------------
2.0.0 | Created
***
See also:
- [Date](Date.md)
- [DateTime](DateTime.md)
- [LeapDate](LeapDate.md)
- [LeapYear](LeapYear.md)

View file

@ -135,6 +135,7 @@
- [LeapDate](LeapDate.md)
- [LeapYear](LeapYear.md)
- [MinimumAge](MinimumAge.md)
- [Time](Time.md)
## Group Validators
@ -331,6 +332,7 @@
- [StringVal](StringVal.md)
- [SubdivisionCode](SubdivisionCode.md)
- [SymbolicLink](SymbolicLink.md)
- [Time](Time.md)
- [Tld](Tld.md)
- [TrueVal](TrueVal.md)
- [Type](Type.md)

View file

@ -0,0 +1,45 @@
<?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 Henrique Moody <henriquemoody@gmail.com>
*/
final class TimeException extends ValidationException
{
/**
* {@inheritdoc}
*/
public static $defaultTemplates = [
self::MODE_DEFAULT => [
self::STANDARD => '{{name}} must be a valid time in the format {{sample}}',
],
self::MODE_NEGATIVE => [
self::STANDARD => '{{name}} must not be a valid time in the format {{sample}}',
],
];
/**
* {@inheritdoc}
*/
public function configure($name, array $params = [])
{
$params['sample'] = date(
$params['format'],
strtotime('23:59:59')
);
return parent::configure($name, $params);
}
}

63
library/Rules/Time.php Normal file
View file

@ -0,0 +1,63 @@
<?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 whether an input is a time or not
*
* @author Henrique Moody <henriquemoody@gmail.com>
*/
final class Time extends AbstractRule
{
/**
* @var string
*/
private $format;
/**
* Initializes the rule.
*
* @param string $format
*
* @throws ComponentException
*/
public function __construct(string $format = 'H:i:s')
{
if (!preg_match('/^[gGhHisuvaA\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 ($info['error_count'] + $info['warning_count']) === 0;
}
}

View file

@ -142,6 +142,7 @@ use Respect\Validation\Rules\Key;
* @method static Validator stringVal()
* @method static Validator subdivisionCode(string $countryCode)
* @method static Validator symbolicLink()
* @method static Validator time(string $format = 'H:i:s')
* @method static Validator tld()
* @method static Validator trueVal()
* @method static Validator type(string $type)

View file

@ -0,0 +1,37 @@
--FILE--
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Exceptions\TimeException;
use Respect\Validation\Validator as v;
try {
v::time()->check('2018-01-30');
} catch (TimeException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::not(v::time())->check('09:25:46');
} catch (TimeException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::time()->assert('2018-01-30');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::not(v::time('g:i A'))->assert('8:13 AM');
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
?>
--EXPECTF--
"2018-01-30" must be a valid time in the format "23:59:59"
"09:25:46" must not be a valid time in the format "23:59:59"
- "2018-01-30" must be a valid time in the format "23:59:59"
- "8:13 AM" must not be a valid time in the format "11:59 PM"

View file

@ -0,0 +1,95 @@
<?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\Time
*
* @author Henrique Moody <henriquemoody@gmail.com>
*/
final class TimeTest extends RuleTestCase
{
/**
* {@inheritdoc}
*/
public function providerForValidInput(): array
{
return [
[new Time(), '00:00:00'],
[new Time(), '23:20:59'],
[new Time('H:i'), '23:59'],
[new Time('g:i A'), '8:13 AM'],
[new Time('His'), 232059],
[new Time('H:i:s.u'), '08:16:01.000000'],
[new Time('ga'), '3am'],
];
}
/**
* {@inheritdoc}
*/
public function providerForInvalidInput(): array
{
return [
[new Time(), '00:00:60'],
[new Time(), '00:60:00'],
[new Time(), '24:00:00'],
[new Time(), '00:00'],
[new Time(), new DateTime()],
[new Time(), new DateTimeImmutable()],
[new Time(), ''],
];
}
public function invalidFormatsProvider(): array
{
return [
['Y-m-d H:i:s'],
['M g:i A'],
];
}
/**
* @test
*
* @dataProvider invalidFormatsProvider
*
* @param string $format
*/
public function shouldThrowAnExceptionWhenFormatIsNotValid(string $format): void
{
$this->expectException(ComponentException::class);
new Time($format);
}
/**
* @test
*/
public function shouldPassFormatToParameterToException(): void
{
$format = 'g:i A';
$equals = new Time($format);
$exception = $equals->reportError('input');
self::assertSame($format, $exception->getParam('format'));
}
}