From 6bc658491f0c21b69f6986c2654f65087f0ae505 Mon Sep 17 00:00:00 2001 From: pamparam Date: Thu, 11 Jan 2024 20:29:07 +0300 Subject: [PATCH 1/9] add DateRule --- src/Rule/Date.php | 108 +++++++++++++++++++++++++++++++++++ src/Rule/DateHandler.php | 48 ++++++++++++++++ tests/Rule/DateTest.php | 119 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 src/Rule/Date.php create mode 100644 src/Rule/DateHandler.php create mode 100644 tests/Rule/DateTest.php diff --git a/src/Rule/Date.php b/src/Rule/Date.php new file mode 100644 index 000000000..ae890fd32 --- /dev/null +++ b/src/Rule/Date.php @@ -0,0 +1,108 @@ +format; + } + + /** + * Get a message used when the input is incorrect. + * + * @return string A message used when the input is incorrect. + * @see $incorrectInputMessage + */ + public function getIncorrectInputMessage(): string + { + return $this->incorrectInputMessage; + } + + public function getOptions(): array + { + return [ + 'format' => $this->format, + 'pattern' => $this->pattern, + 'incorrectInputMessage' => [ + 'template' => $this->incorrectInputMessage, + 'parameters' => [], + ], + 'message' => [ + 'template' => $this->message, + 'parameters' => [], + ], + 'skipOnEmpty' => $this->getSkipOnEmptyOption(), + 'skipOnError' => $this->skipOnError, + ]; + } + + public function getMessage(): string + { + return $this->message; + } + + public function getName(): string + { + return self::class; + } + + public function getHandler(): string + { + return DateHandler::class; + } + + public function getPattern(): string + { + return $this->pattern; + } +} diff --git a/src/Rule/DateHandler.php b/src/Rule/DateHandler.php new file mode 100644 index 000000000..2682a15b1 --- /dev/null +++ b/src/Rule/DateHandler.php @@ -0,0 +1,48 @@ +getPattern(), $rule->getFormat()) ) { + return $result->addError($rule->getIncorrectInputMessage(), [ + 'attribute' => $context->getTranslatedAttribute(), + 'type' => get_debug_type($value), + ]); + } + + $date = DateTime::createFromFormat($rule->getFormat(), $value); + $errors = DateTime::getLastErrors(); + + if ($date === false || ($errors !== false && ($errors['error_count'] || $errors['warning_count'])) + || ($date->format($rule->getFormat()) !== $value)) { + $result->addError($rule->getMessage(), [ + 'attribute' => $context->getTranslatedAttribute(), + 'value' => $value, + ]); + } + + return $result; + } +} diff --git a/tests/Rule/DateTest.php b/tests/Rule/DateTest.php new file mode 100644 index 000000000..b07b89891 --- /dev/null +++ b/tests/Rule/DateTest.php @@ -0,0 +1,119 @@ + [ + 1, + [new Date(incorrectInputMessage: 'Custom incorrect input message.')], + ['' => ['Custom incorrect input message.']], + ], + [ + '2023-02-30', + [new Date(format: 'Y-m-d', message: 'Attribute - {attribute}, value - {value}.')], + ['' => ['Attribute - , value - 2023-02-30.']], + ], + [ + '2023-02-20ee', + [new Date(format: 'Y-m-dee', incorrectInputMessage: 'The must be a date.')], + ['' => ['The must be a date.']], + ], + + [ + '10-02-2023 00:00', + [new Date(format: 'd-m-Y H:i', incorrectInputMessage: 'The must be a date.')], + ['' => ['The must be a date.']], + ], + [ + '2023-02-2023', + [new Date(format: 'Y-d-Y', incorrectInputMessage: 'The must be a date.')], + ['' => ['The must be a date.']], + ], + 'incorrect input, is not date' => [ + 'asdadas', + [new Date(message: 'Attribute - {attribute}, value - {value}.')], + ['' => ['Attribute - , value - asdadas.']], + ], + 'empty string and custom message' => [ + '', + [new Date(message: 'Custom message.')], + ['' => ['Custom message.']], + ], + ]; + } + + public function dataOptions(): array + { + return [ + [ + new Date(), + [ + 'format' => 'Y-m-d', + 'pattern' => '/^(?=.*Y)(?=.*[mM])(?=.*d).*[Ymd](-|\/|.)[Ymd]\1[Ymd]$/', + 'incorrectInputMessage' => [ + 'template' => 'The {attribute} must be a date.', + 'parameters' => [], + ], + 'message' => [ + 'template' => 'The {attribute} is not a valid date.', + 'parameters' => [], + ], + 'skipOnEmpty' => false, + 'skipOnError' => false, + ], + ], + ]; + } + + public function testSkipOnError(): void + { + $this->testSkipOnErrorInternal(new Date(), new Date(skipOnError: true)); + } + + public function testWhen(): void + { + $when = static fn(mixed $value): bool => $value !== null; + $this->testWhenInternal(new Date(), new Date(when: $when)); + } + + protected function getDifferentRuleInHandlerItems(): array + { + return [Date::class, DateHandler::class]; + } + + public function testGetName(): void + { + $rule = new Date(); + $this->assertSame(Date::class, $rule->getName()); + } + +} From 7c859965a0026730c9cec244d40a55f86f0a0007 Mon Sep 17 00:00:00 2001 From: pamparam Date: Thu, 11 Jan 2024 21:21:15 +0300 Subject: [PATCH 2/9] fix --- src/Rule/Date.php | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Rule/Date.php b/src/Rule/Date.php index ae890fd32..fbf8b21a7 100644 --- a/src/Rule/Date.php +++ b/src/Rule/Date.php @@ -6,6 +6,7 @@ use Closure; use Attribute; +use InvalidArgumentException; use Yiisoft\Validator\WhenInterface; use Yiisoft\Validator\DumpedRuleInterface; use Yiisoft\Validator\SkipOnErrorInterface; @@ -25,6 +26,17 @@ final class Date implements DumpedRuleInterface, SkipOnErrorInterface, WhenInter use SkipOnErrorTrait; use WhenTrait; + /** + * @var string The regular expression used to validate the value. See + * {@link https://www.regular-expressions.info/email.html}. + * @psalm-var non-empty-string + */ + private string $pattern; + + /** + * @psalm-var non-empty-string + */ + private string $format; /** * @param string $format The format of the date. * @param string $message A message used when the value is not valid. @@ -41,16 +53,35 @@ final class Date implements DumpedRuleInterface, SkipOnErrorInterface, WhenInter * @psalm-param WhenType $when */ public function __construct( - private string $format = 'Y-m-d', - private string $pattern = '/^(?=.*Y)(?=.*[mM])(?=.*d).*[Ymd](-|\/|.)[Ymd]\1[Ymd]$/', + string $format = 'Y-m-d', + string $pattern = '/^(?=.*Y)(?=.*[mM])(?=.*d).*[Ymd](-|\/|.)[Ymd]\1[Ymd]$/', private string $incorrectInputMessage = 'The {attribute} must be a date.', private string $message = 'The {attribute} is not a valid date.', private mixed $skipOnEmpty = null, private bool $skipOnError = false, private ?Closure $when = null, ) { + if ($pattern === '') { + throw new InvalidArgumentException('Pattern can\'t be empty.'); + } + + $this->pattern = $pattern; + + if ($format === '') { + throw new InvalidArgumentException('Format can\'t be empty.'); + } + + $this->format = $format; } + /** + * The format date. + * + * @return string The format. + * @psalm-return non-empty-string + * + * @see $format + */ public function getFormat(): string { @@ -100,7 +131,14 @@ public function getHandler(): string { return DateHandler::class; } - + /** + * Get the regular expression used to validate the value. + * + * @return string The regular expression. + * @psalm-return non-empty-string + * + * @see $pattern + */ public function getPattern(): string { return $this->pattern; From 874130b1bda4145c65a768789d6d7bf608749076 Mon Sep 17 00:00:00 2001 From: pamparam Date: Thu, 11 Jan 2024 21:35:05 +0300 Subject: [PATCH 3/9] add test --- tests/Rule/DateTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Rule/DateTest.php b/tests/Rule/DateTest.php index b07b89891..38c317606 100644 --- a/tests/Rule/DateTest.php +++ b/tests/Rule/DateTest.php @@ -4,7 +4,9 @@ namespace Yiisoft\Validator\Tests\Rule; +use InvalidArgumentException; use Yiisoft\Validator\Rule\Date; +use Yiisoft\Validator\Rule\Email; use Yiisoft\Validator\Rule\DateHandler; use Yiisoft\Validator\Tests\Rule\Base\RuleTestCase; use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait; @@ -19,6 +21,24 @@ final class DateTest extends RuleTestCase use SkipOnErrorTestTrait; use WhenTestTrait; + public function dataInvalidConfiguration(): array + { + return [ + [['pattern' => ''], 'Pattern can\'t be empty.'], + [['format' => ''], 'Format can\'t be empty.'], + ]; + } + + /** + * @dataProvider dataInvalidConfiguration + */ + public function testinvalidConfiguration(array $arguments, string $expectedExceptionMessage): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($expectedExceptionMessage); + new Date(...$arguments); + } + public function dataValidationPassed(): array { return [ From b4dc5c18f6fe0c33c5270dadea5c306d4e3cf308 Mon Sep 17 00:00:00 2001 From: pamparam Date: Sun, 14 Jan 2024 20:43:43 +0300 Subject: [PATCH 4/9] kill mutant --- src/Rule/Date.php | 3 ++- src/Rule/DateHandler.php | 8 +++----- tests/Rule/DateTest.php | 21 ++++++++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Rule/Date.php b/src/Rule/Date.php index fbf8b21a7..94ce48d1d 100644 --- a/src/Rule/Date.php +++ b/src/Rule/Date.php @@ -12,6 +12,7 @@ use Yiisoft\Validator\SkipOnErrorInterface; use Yiisoft\Validator\SkipOnEmptyInterface; use Yiisoft\Validator\Rule\Trait\WhenTrait; +use Yiisoft\Validator\RuleHandlerInterface; use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait; use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait; @@ -127,7 +128,7 @@ public function getName(): string return self::class; } - public function getHandler(): string + public function getHandler(): string|RuleHandlerInterface { return DateHandler::class; } diff --git a/src/Rule/DateHandler.php b/src/Rule/DateHandler.php index 2682a15b1..974661d5a 100644 --- a/src/Rule/DateHandler.php +++ b/src/Rule/DateHandler.php @@ -25,7 +25,7 @@ public function validate(mixed $value, object $rule, ValidationContext $context) $result = new Result(); - if (!is_string($value) || !preg_match($rule->getPattern(), $rule->getFormat()) ) { + if (!is_string($value) || empty($value)|| !preg_match($rule->getPattern(), $rule->getFormat()) ) { return $result->addError($rule->getIncorrectInputMessage(), [ 'attribute' => $context->getTranslatedAttribute(), 'type' => get_debug_type($value), @@ -33,11 +33,9 @@ public function validate(mixed $value, object $rule, ValidationContext $context) } $date = DateTime::createFromFormat($rule->getFormat(), $value); - $errors = DateTime::getLastErrors(); - if ($date === false || ($errors !== false && ($errors['error_count'] || $errors['warning_count'])) - || ($date->format($rule->getFormat()) !== $value)) { - $result->addError($rule->getMessage(), [ + if ($date === false || ($date->format($rule->getFormat()) !== $value)) { + $result->addError($rule->getMessage(), [ 'attribute' => $context->getTranslatedAttribute(), 'value' => $value, ]); diff --git a/tests/Rule/DateTest.php b/tests/Rule/DateTest.php index 38c317606..0663b4aea 100644 --- a/tests/Rule/DateTest.php +++ b/tests/Rule/DateTest.php @@ -6,7 +6,6 @@ use InvalidArgumentException; use Yiisoft\Validator\Rule\Date; -use Yiisoft\Validator\Rule\Email; use Yiisoft\Validator\Rule\DateHandler; use Yiisoft\Validator\Tests\Rule\Base\RuleTestCase; use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait; @@ -57,17 +56,11 @@ public function dataValidationFailed(): array [new Date(incorrectInputMessage: 'Custom incorrect input message.')], ['' => ['Custom incorrect input message.']], ], - [ - '2023-02-30', - [new Date(format: 'Y-m-d', message: 'Attribute - {attribute}, value - {value}.')], - ['' => ['Attribute - , value - 2023-02-30.']], - ], [ '2023-02-20ee', [new Date(format: 'Y-m-dee', incorrectInputMessage: 'The must be a date.')], ['' => ['The must be a date.']], ], - [ '10-02-2023 00:00', [new Date(format: 'd-m-Y H:i', incorrectInputMessage: 'The must be a date.')], @@ -78,6 +71,16 @@ public function dataValidationFailed(): array [new Date(format: 'Y-d-Y', incorrectInputMessage: 'The must be a date.')], ['' => ['The must be a date.']], ], + [ + '2023-02-30', + [new Date(format: 'Y-m-d', message: 'Attribute - {attribute}, value - {value}.')], + ['' => ['Attribute - , value - 2023-02-30.']], + ], + 'custom incorrect input message with parameters, attribute set' => [ + ['attribute' => 1], + ['attribute' => [new Date(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')]], + ['attribute' => ['Attribute - attribute, type - int.']], + ], 'incorrect input, is not date' => [ 'asdadas', [new Date(message: 'Attribute - {attribute}, value - {value}.')], @@ -85,8 +88,8 @@ public function dataValidationFailed(): array ], 'empty string and custom message' => [ '', - [new Date(message: 'Custom message.')], - ['' => ['Custom message.']], + [new Date()], + ['' => ['The must be a date.']], ], ]; } From 761e1e3747af4477a4c412063417208f624ce964 Mon Sep 17 00:00:00 2001 From: pamparam Date: Mon, 15 Jan 2024 21:23:13 +0300 Subject: [PATCH 5/9] add DateTime --- src/Rule/DateTime.php | 151 ++++++++++++++++++++++++++++++ src/Rule/DateTimeHandler.php | 101 ++++++++++++++++++++ tests/Rule/DateTimeTest.php | 175 +++++++++++++++++++++++++++++++++++ 3 files changed, 427 insertions(+) create mode 100644 src/Rule/DateTime.php create mode 100644 src/Rule/DateTimeHandler.php create mode 100644 tests/Rule/DateTimeTest.php diff --git a/src/Rule/DateTime.php b/src/Rule/DateTime.php new file mode 100644 index 000000000..f12dd0125 --- /dev/null +++ b/src/Rule/DateTime.php @@ -0,0 +1,151 @@ +formats = $formats; + $this->min = is_int($min) ? DateTimeImmutable::createFromFormat('U', (string) $min) : $min; + $this->max = is_int($max) ? DateTimeImmutable::createFromFormat('U', (string) $max) : $max; + } + + /** + * @return string[] + */ + public function getFormats(): array + { + if ($this->formats) { + return $this->formats; + } + + return [ + DateTimeInterface::ATOM, + DateTimeInterface::COOKIE, + DateTimeInterface::RFC822, + DateTimeInterface::RFC850, + DateTimeInterface::RFC1036, + DateTimeInterface::RFC1123, + DateTimeInterface::RFC7231, + DateTimeInterface::RFC2822, + DateTimeInterface::RFC3339, + DateTimeInterface::RFC3339_EXTENDED, + DateTimeInterface::RSS, + DateTimeInterface::W3C, + ]; + } + + + public function getLessThanMinMessage(): string + { + return $this->lessThanMinMessage; + } + + public function getGreaterThanMaxMessage(): string + { + return $this->greaterThanMaxMessage; + } + + public function getMin(): DateTimeInterface|false|null + { + return $this->min; + } + + public function getMax(): DateTimeInterface|false|null + { + return $this->max; + } + + + public function getOptions(): array + { + return [ + 'formats' => $this->formats, + 'min' => $this->min, + 'max' => $this->max, + 'lessThanMinMessage' => [ + 'template' => $this->lessThanMinMessage, + 'parameters' => [], + ], + 'greaterThanMaxMessage' => [ + 'template' => $this->greaterThanMaxMessage, + 'parameters' => [], + ], + 'message' => [ + 'template' => $this->message, + 'parameters' => [], + ], + 'skipOnEmpty' => $this->getSkipOnEmptyOption(), + 'skipOnError' => $this->skipOnError, + ]; + } + + public function getMessage(): string + { + return $this->message; + } + + public function getName(): string + { + return self::class; + } + + public function getHandler(): string|RuleHandlerInterface + { + return DateTimeHandler::class; + } +} diff --git a/src/Rule/DateTimeHandler.php b/src/Rule/DateTimeHandler.php new file mode 100644 index 000000000..dbeb926f4 --- /dev/null +++ b/src/Rule/DateTimeHandler.php @@ -0,0 +1,101 @@ +toDateTime($value, $rule); + + $debugType = get_debug_type($value); + + if ($datetime === null) { + $result->addError($rule->getMessage(), [ + 'attribute' => $context->getTranslatedAttribute(), + 'value' => $debugType, + ]); + } + + if ($rule->getMin() && $datetime < $rule->getMin()) { + return $result->addError($rule->getLessThanMinMessage(), [ + 'attribute' => $context->getTranslatedAttribute(), + 'value' => $debugType, + 'min' => $rule->getMin()->format($this->format), + ]); + } + + if ($rule->getMax() && $datetime > $rule->getMax()) { + return $result->addError($rule->getGreaterThanMaxMessage(), [ + 'attribute' => $context->getTranslatedAttribute(), + 'value' => $debugType, + 'max' => $rule->getMax()->format($this->format), + ]); + } + + return $result; + } + + + /** + * Converts a value to a DateTime object based on a given rule. + * + * @param mixed $value The value to convert. + * @param DateTime $rule The DateTime rule to use for conversion. + * @return DateTimeInterface|null The converted DateTime object, or null if the conversion fails. + */ + private function toDateTime(mixed $value, DateTime $rule): ?DateTimeInterface + { + if ($value instanceof DateTimeInterface) { + return $value; + } + if (filter_var($value, FILTER_VALIDATE_INT) !== false) { + $this->format = 'U'; + if ($value = \DateTime::createFromFormat($this->format, (string) $value)) { + return $value; + } + return null; + } + + if (!is_string($value)) { + return null; + } + // Try to convert the value to a DateTime object using each format in the rule's formats array. + foreach ($rule->getFormats() as $format) { + if ($formatted = \DateTime::createFromFormat($format, $value)) { + $this->format = $format; + return $formatted; + } + } + + return null; + } +} diff --git a/tests/Rule/DateTimeTest.php b/tests/Rule/DateTimeTest.php new file mode 100644 index 000000000..52a4ff189 --- /dev/null +++ b/tests/Rule/DateTimeTest.php @@ -0,0 +1,175 @@ + [' must be no greater than 2024-08-15 15:52:01.']], + ], + + [ + 1705322898, + [new DateTime()], + ['' => [' value is not a valid DateTime.']], + ], + ]; + } + + public function dataValidationFailed(): array + { + return [ + + [ + '2023-02-20ee', + [new DateTime(message: '{attribute} value is not a valid DateTime.')], + ['' => [' value is not a valid DateTime.']], + ], + [ + '', + [new DateTime(message: '{attribute} value is not a valid DateTime.')], + ['' => [' value is not a valid DateTime.']], + ], + [ + '2024-08-14 15:52:01', + [ + new DateTime( + min: new DateTimeImmutable('2024-08-15 15:52:01'), + formats: 'Y-m-d H:i:s' + ), + ], + ['' => [' must be no less than 2024-08-15 15:52:01.']], + ], + [ + '2024-08-15 15:52:02', + [ + new DateTime( + max: new DateTimeImmutable('2024-08-15 15:52:01'), + formats: 'Y-m-d H:i:s' + ), + ], + ['' => [' must be no greater than 2024-08-15 15:52:01.']], + ], + ]; + } + + public function dataOptions(): array + { + return [ + [ + new DateTime(), + [ + 'formats' => [], + 'min' => null, + 'max' => null, + 'lessThanMinMessage' => [ + 'template' => '{attribute} must be no less than {min}.', + 'parameters' => [], + ], + 'greaterThanMaxMessage' => [ + 'template' => '{attribute} must be no greater than {max}.', + 'parameters' => [], + ], + 'message' => [ + 'template' => '{attribute} value is not a valid DateTime.', + 'parameters' => [], + ], + 'skipOnEmpty' => false, + 'skipOnError' => false, + ], + ], + ]; + } + + public function testSkipOnError(): void + { + $this->testSkipOnErrorInternal(new DateTime(), new DateTime(skipOnError: true)); + } + + public function testWhen(): void + { + $when = static fn(mixed $value): bool => $value !== null; + $this->testWhenInternal(new DateTime(), new DateTime(when: $when)); + } + + protected function getDifferentRuleInHandlerItems(): array + { + return [DateTime::class, DateTimeHandler::class]; + } + + public function testGetName(): void + { + $rule = new DateTime(); + $this->assertSame(DateTime::class, $rule->getName()); + } + +} From 6f22c189cb3055c29c4626fb400f7236a046207b Mon Sep 17 00:00:00 2001 From: pamparam Date: Sun, 21 Jan 2024 19:52:19 +0300 Subject: [PATCH 6/9] deleted Date --- CHANGELOG.md | 1 + src/Rule/Date.php | 147 --------------------------------- src/Rule/DateHandler.php | 46 ----------- src/Rule/DateTime.php | 153 ++++++++++++++++++----------------- src/Rule/DateTimeHandler.php | 72 ++--------------- tests/Rule/DateTest.php | 142 -------------------------------- tests/Rule/DateTimeTest.php | 148 +++++++++++++-------------------- 7 files changed, 144 insertions(+), 565 deletions(-) delete mode 100644 src/Rule/Date.php delete mode 100644 src/Rule/DateHandler.php delete mode 100644 tests/Rule/DateTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d8b67d108..50df18c0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2.0.0 under development +- New #646: Add DateTime rule (@pamparam83) - New #615: Add the `Each::PARAMETER_EACH_KEY` validation context parameter that available during `Each` rule handling and containing the current key (@dood-) - Enh #648: Raise the minimum version of PHP to 8.1 (@pamparam83) diff --git a/src/Rule/Date.php b/src/Rule/Date.php deleted file mode 100644 index 94ce48d1d..000000000 --- a/src/Rule/Date.php +++ /dev/null @@ -1,147 +0,0 @@ -pattern = $pattern; - - if ($format === '') { - throw new InvalidArgumentException('Format can\'t be empty.'); - } - - $this->format = $format; - } - - /** - * The format date. - * - * @return string The format. - * @psalm-return non-empty-string - * - * @see $format - */ - - public function getFormat(): string - { - return $this->format; - } - - /** - * Get a message used when the input is incorrect. - * - * @return string A message used when the input is incorrect. - * @see $incorrectInputMessage - */ - public function getIncorrectInputMessage(): string - { - return $this->incorrectInputMessage; - } - - public function getOptions(): array - { - return [ - 'format' => $this->format, - 'pattern' => $this->pattern, - 'incorrectInputMessage' => [ - 'template' => $this->incorrectInputMessage, - 'parameters' => [], - ], - 'message' => [ - 'template' => $this->message, - 'parameters' => [], - ], - 'skipOnEmpty' => $this->getSkipOnEmptyOption(), - 'skipOnError' => $this->skipOnError, - ]; - } - - public function getMessage(): string - { - return $this->message; - } - - public function getName(): string - { - return self::class; - } - - public function getHandler(): string|RuleHandlerInterface - { - return DateHandler::class; - } - /** - * Get the regular expression used to validate the value. - * - * @return string The regular expression. - * @psalm-return non-empty-string - * - * @see $pattern - */ - public function getPattern(): string - { - return $this->pattern; - } -} diff --git a/src/Rule/DateHandler.php b/src/Rule/DateHandler.php deleted file mode 100644 index 974661d5a..000000000 --- a/src/Rule/DateHandler.php +++ /dev/null @@ -1,46 +0,0 @@ -getPattern(), $rule->getFormat()) ) { - return $result->addError($rule->getIncorrectInputMessage(), [ - 'attribute' => $context->getTranslatedAttribute(), - 'type' => get_debug_type($value), - ]); - } - - $date = DateTime::createFromFormat($rule->getFormat(), $value); - - if ($date === false || ($date->format($rule->getFormat()) !== $value)) { - $result->addError($rule->getMessage(), [ - 'attribute' => $context->getTranslatedAttribute(), - 'value' => $value, - ]); - } - - return $result; - } -} diff --git a/src/Rule/DateTime.php b/src/Rule/DateTime.php index f12dd0125..26127a287 100644 --- a/src/Rule/DateTime.php +++ b/src/Rule/DateTime.php @@ -6,8 +6,7 @@ use Closure; use Attribute; -use DateTimeImmutable; -use DateTimeInterface; +use InvalidArgumentException; use Yiisoft\Validator\WhenInterface; use Yiisoft\Validator\DumpedRuleInterface; use Yiisoft\Validator\SkipOnErrorInterface; @@ -18,7 +17,41 @@ use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait; /** + * Defines validation options to check that the value is a date. + * + * An example for simple that can be used to validate the date: + * ```php + * use Yiisoft\Validator\Rule\DateTime; + * + * $rules = [ + * 'date' => [ + * new DateTime(format: 'Y-m-d'), + * ], + * ]; + * ``` + * In the example above, the PHP attributes equivalent will be: + * + * ```php + * use Yiisoft\Validator\Validator; + * use Yiisoft\Validator\Rule\DateTime; + * + * final class User + * { + * public function __construct( + * #[DateTime(format: 'Y-m-d')] + * public string $date, + * ){ + * } + * } + * + * $user = new User( date: '2022-01-01' ); + * + * $validator = (new Validator())->validate($user); + * + * ``` + * * @see DateTimeHandler + * * @psalm-import-type WhenType from WhenInterface */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] @@ -29,100 +62,73 @@ final class DateTime implements DumpedRuleInterface, SkipOnErrorInterface, WhenI use WhenTrait; /** - * @var string[] + * @link https://www.php.net/manual/en/function.date.php + * @psalm-var non-empty-string + * @var string The allowed date formats. */ - private array $formats = []; - private DateTimeInterface|false|null $min; - private DateTimeInterface|false|null $max; + private string $format; /** - * Constructor for the class. - * - * @param int|DateTimeInterface|null $min The minimum value allowed. - * @param int|DateTimeInterface|null $max The maximum value allowed. - * @param string $message The validation error message for invalid DateTime value. - * @param string $lessThanMinMessage The validation error message for values less than the minimum. - * @param string $greaterThanMaxMessage The validation error message for values greater than the maximum. - * @param mixed $skipOnEmpty Determines if the validation should be skipped when the value is empty. - * @param bool $skipOnError Determines if the validation should be skipped when there is an error. - * @param Closure|null $when The condition that determines when the validation should be applied. - * @param string ...$formats The allowed date formats. + * @param string $format The format of the date. See {@see $format} + * @param string $message A message used when the value is not valid. + * You may use the following placeholders in the message: + * - `{attribute}`: the translated label of the attribute being validated. + * - `{value}`: the value of the attribute being validated. + * @param string $incorrectInputMessage A message used when the input is incorrect. + * You may use the following placeholders in the message: + * - `{attribute}`: the translated label of the attribute being validated. + * - `{type}`: the type of the value being validated. + * @param bool|callable|null $skipOnEmpty Whether to skip this rule if the value validated is empty. See {@see SkipOnEmptyInterface}. + * @param bool $skipOnError Whether to skip this rule if any of the previous rules gave an error. See {@see SkipOnErrorInterface}. + * @param Closure|null $when A callable to define a condition for applying the rule. See {@see WhenInterface}. + * @psalm-param WhenType $when */ public function __construct( - int|DateTimeInterface|null $min = null, - int|DateTimeInterface|null $max = null, - private string $message = '{attribute} value is not a valid DateTime.', - private string $lessThanMinMessage = '{attribute} must be no less than {min}.', - private string $greaterThanMaxMessage = '{attribute} must be no greater than {max}.', + string $format = 'Y-m-d', + private string $incorrectInputMessage = 'The {attribute} must be a date.', + private string $message = 'The {attribute} is not a valid date.', private mixed $skipOnEmpty = null, private bool $skipOnError = false, private ?Closure $when = null, - string ...$formats ) { - $this->formats = $formats; - $this->min = is_int($min) ? DateTimeImmutable::createFromFormat('U', (string) $min) : $min; - $this->max = is_int($max) ? DateTimeImmutable::createFromFormat('U', (string) $max) : $max; - } - - /** - * @return string[] - */ - public function getFormats(): array - { - if ($this->formats) { - return $this->formats; + if ($format === '') { + throw new InvalidArgumentException('Format can\'t be empty.'); } - return [ - DateTimeInterface::ATOM, - DateTimeInterface::COOKIE, - DateTimeInterface::RFC822, - DateTimeInterface::RFC850, - DateTimeInterface::RFC1036, - DateTimeInterface::RFC1123, - DateTimeInterface::RFC7231, - DateTimeInterface::RFC2822, - DateTimeInterface::RFC3339, - DateTimeInterface::RFC3339_EXTENDED, - DateTimeInterface::RSS, - DateTimeInterface::W3C, - ]; - } - - - public function getLessThanMinMessage(): string - { - return $this->lessThanMinMessage; + $this->format = $format; } - public function getGreaterThanMaxMessage(): string - { - return $this->greaterThanMaxMessage; - } + /** + * The date format. + * + * @return string The format. See {@see $format} + * @psalm-return non-empty-string + * + * @see $format + */ - public function getMin(): DateTimeInterface|false|null + public function getFormat(): string { - return $this->min; + return $this->format; } - public function getMax(): DateTimeInterface|false|null + /** + * Get a message used when the input is incorrect. + * + * @return string A message used when the input is incorrect. + * @see $incorrectInputMessage + */ + public function getIncorrectInputMessage(): string { - return $this->max; + return $this->incorrectInputMessage; } - public function getOptions(): array { return [ - 'formats' => $this->formats, - 'min' => $this->min, - 'max' => $this->max, - 'lessThanMinMessage' => [ - 'template' => $this->lessThanMinMessage, - 'parameters' => [], - ], - 'greaterThanMaxMessage' => [ - 'template' => $this->greaterThanMaxMessage, + 'format' => $this->format, + 'incorrectInputMessage' => [ + 'template' => $this->incorrectInputMessage, 'parameters' => [], ], 'message' => [ @@ -148,4 +154,5 @@ public function getHandler(): string|RuleHandlerInterface { return DateTimeHandler::class; } + } diff --git a/src/Rule/DateTimeHandler.php b/src/Rule/DateTimeHandler.php index dbeb926f4..dd723f531 100644 --- a/src/Rule/DateTimeHandler.php +++ b/src/Rule/DateTimeHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Validator\Rule; -use DateTimeInterface; use Yiisoft\Validator\Result; use Yiisoft\Validator\ValidationContext; use Yiisoft\Validator\RuleHandlerInterface; @@ -17,85 +16,30 @@ */ final class DateTimeHandler implements RuleHandlerInterface { - private string $format = DateTimeInterface::W3C; - - /** - * Validates a value against a DateTime rule. - * - * @param mixed $value The value to validate. - * @param object $rule The DateTime rule. - * @param ValidationContext $context The validation context. - * @return Result The validation result. - * @throws UnexpectedRuleException If the rule is not an instance of DateTime. - */ public function validate(mixed $value, object $rule, ValidationContext $context): Result { if (!$rule instanceof DateTime) { throw new UnexpectedRuleException(DateTime::class, $rule); } - $result = new Result(); - $datetime = $this->toDateTime($value, $rule); - $debugType = get_debug_type($value); + $result = new Result(); - if ($datetime === null) { - $result->addError($rule->getMessage(), [ + if (!is_string($value) || empty($value)) { + return $result->addError($rule->getIncorrectInputMessage(), [ 'attribute' => $context->getTranslatedAttribute(), - 'value' => $debugType, + 'type' => get_debug_type($value), ]); } - if ($rule->getMin() && $datetime < $rule->getMin()) { - return $result->addError($rule->getLessThanMinMessage(), [ - 'attribute' => $context->getTranslatedAttribute(), - 'value' => $debugType, - 'min' => $rule->getMin()->format($this->format), - ]); - } + $date = \DateTime::createFromFormat($rule->getFormat(), $value); - if ($rule->getMax() && $datetime > $rule->getMax()) { - return $result->addError($rule->getGreaterThanMaxMessage(), [ + if ($date === false || ($date->format($rule->getFormat()) !== $value)) { + $result->addError($rule->getMessage(), [ 'attribute' => $context->getTranslatedAttribute(), - 'value' => $debugType, - 'max' => $rule->getMax()->format($this->format), + 'value' => $value, ]); } return $result; } - - - /** - * Converts a value to a DateTime object based on a given rule. - * - * @param mixed $value The value to convert. - * @param DateTime $rule The DateTime rule to use for conversion. - * @return DateTimeInterface|null The converted DateTime object, or null if the conversion fails. - */ - private function toDateTime(mixed $value, DateTime $rule): ?DateTimeInterface - { - if ($value instanceof DateTimeInterface) { - return $value; - } - if (filter_var($value, FILTER_VALIDATE_INT) !== false) { - $this->format = 'U'; - if ($value = \DateTime::createFromFormat($this->format, (string) $value)) { - return $value; - } - return null; - } - - if (!is_string($value)) { - return null; - } - // Try to convert the value to a DateTime object using each format in the rule's formats array. - foreach ($rule->getFormats() as $format) { - if ($formatted = \DateTime::createFromFormat($format, $value)) { - $this->format = $format; - return $formatted; - } - } - - return null; - } } diff --git a/tests/Rule/DateTest.php b/tests/Rule/DateTest.php deleted file mode 100644 index 0663b4aea..000000000 --- a/tests/Rule/DateTest.php +++ /dev/null @@ -1,142 +0,0 @@ - ''], 'Pattern can\'t be empty.'], - [['format' => ''], 'Format can\'t be empty.'], - ]; - } - - /** - * @dataProvider dataInvalidConfiguration - */ - public function testinvalidConfiguration(array $arguments, string $expectedExceptionMessage): void - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage($expectedExceptionMessage); - new Date(...$arguments); - } - - public function dataValidationPassed(): array - { - return [ - ['2020-01-01', [new Date(format: 'Y-m-d')]], - ['10.02.2023', [new Date(format: 'd.m.Y')]], - ['10/02/2023', [new Date(format: 'd/m/Y')]], - ['', [new Date(format: 'd-m-Y', skipOnEmpty: true)]], - ]; - } - - public function dataValidationFailed(): array - { - return [ - 'incorrect input, is integer' => [ - 1, - [new Date(incorrectInputMessage: 'Custom incorrect input message.')], - ['' => ['Custom incorrect input message.']], - ], - [ - '2023-02-20ee', - [new Date(format: 'Y-m-dee', incorrectInputMessage: 'The must be a date.')], - ['' => ['The must be a date.']], - ], - [ - '10-02-2023 00:00', - [new Date(format: 'd-m-Y H:i', incorrectInputMessage: 'The must be a date.')], - ['' => ['The must be a date.']], - ], - [ - '2023-02-2023', - [new Date(format: 'Y-d-Y', incorrectInputMessage: 'The must be a date.')], - ['' => ['The must be a date.']], - ], - [ - '2023-02-30', - [new Date(format: 'Y-m-d', message: 'Attribute - {attribute}, value - {value}.')], - ['' => ['Attribute - , value - 2023-02-30.']], - ], - 'custom incorrect input message with parameters, attribute set' => [ - ['attribute' => 1], - ['attribute' => [new Date(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')]], - ['attribute' => ['Attribute - attribute, type - int.']], - ], - 'incorrect input, is not date' => [ - 'asdadas', - [new Date(message: 'Attribute - {attribute}, value - {value}.')], - ['' => ['Attribute - , value - asdadas.']], - ], - 'empty string and custom message' => [ - '', - [new Date()], - ['' => ['The must be a date.']], - ], - ]; - } - - public function dataOptions(): array - { - return [ - [ - new Date(), - [ - 'format' => 'Y-m-d', - 'pattern' => '/^(?=.*Y)(?=.*[mM])(?=.*d).*[Ymd](-|\/|.)[Ymd]\1[Ymd]$/', - 'incorrectInputMessage' => [ - 'template' => 'The {attribute} must be a date.', - 'parameters' => [], - ], - 'message' => [ - 'template' => 'The {attribute} is not a valid date.', - 'parameters' => [], - ], - 'skipOnEmpty' => false, - 'skipOnError' => false, - ], - ], - ]; - } - - public function testSkipOnError(): void - { - $this->testSkipOnErrorInternal(new Date(), new Date(skipOnError: true)); - } - - public function testWhen(): void - { - $when = static fn(mixed $value): bool => $value !== null; - $this->testWhenInternal(new Date(), new Date(when: $when)); - } - - protected function getDifferentRuleInHandlerItems(): array - { - return [Date::class, DateHandler::class]; - } - - public function testGetName(): void - { - $rule = new Date(); - $this->assertSame(Date::class, $rule->getName()); - } - -} diff --git a/tests/Rule/DateTimeTest.php b/tests/Rule/DateTimeTest.php index 52a4ff189..6a6ac8f79 100644 --- a/tests/Rule/DateTimeTest.php +++ b/tests/Rule/DateTimeTest.php @@ -4,8 +4,7 @@ namespace Yiisoft\Validator\Tests\Rule; -use DateTimeInterface; -use DateTimeImmutable; +use InvalidArgumentException; use Yiisoft\Validator\Rule\DateTime; use Yiisoft\Validator\Rule\DateTimeHandler; use Yiisoft\Validator\Tests\Rule\Base\RuleTestCase; @@ -21,103 +20,72 @@ final class DateTimeTest extends RuleTestCase use SkipOnErrorTestTrait; use WhenTestTrait; + public function dataInvalidConfiguration(): array + { + return [ + [['format' => ''], 'Format can\'t be empty.'], + ]; + } + + /** + * @dataProvider dataInvalidConfiguration + */ + public function testinvalidConfiguration(array $arguments, string $expectedExceptionMessage): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($expectedExceptionMessage); + new DateTime(...$arguments); + } public function dataValidationPassed(): array { return [ - ['2024-08-15T15:52:01+00:00', [new DateTime(formats: DateTimeInterface::W3C)]], - ['2024-08-15 15:52:01', [new DateTime(formats: 'Y-m-d H:i:s')]], - ['15-08-2024 15:52', [new DateTime(formats: 'd-m-Y H:i')]], - [ - '2024-08-15 15:52:01', - [ - new DateTime( - min: null, - max: null, - message: 'The value must be between 2024-08-15 15:52:01 and 2024-08-15 15:52:01.', - lessThanMinMessage: 'The value must be no less than 2024-08-15 15:52:01.', - greaterThanMaxMessage: 'The value must be no greater than 2024-08-15 15:52:01.', - skipOnEmpty: false, - skipOnError: false, - when: null, - formats: 'Y-m-d H:i:s', format: DateTimeInterface::W3C, - ), - ], - ], - [ - '2024-08-15 15:52:01', - [ - new DateTime( - min: new DateTimeImmutable('2024-08-15 15:52:01'), - formats: 'Y-m-d H:i:s' - ), - ], - ], - [ - new DateTimeImmutable('2024-08-15 15:52:01'), - [new DateTime(formats: 'Y-m-d H:i:s')], - ], - [ - '2024-08-15 15:51:59', - [ - new DateTime( - max: new DateTimeImmutable('2024-08-15 15:52:01'), - formats: 'Y-m-d H:i:s' - ), - ], - ], - [ - '2024-08-15 15:52:01', - [ - new DateTime( - max: new DateTimeImmutable('2024-08-15 15:52:01'), - formats: 'Y-m-d H:i:s' - ), - ], - ['' => [' must be no greater than 2024-08-15 15:52:01.']], - ], - - [ - 1705322898, - [new DateTime()], - ['' => [' value is not a valid DateTime.']], - ], + ['2020-01-01', [new DateTime(format: 'Y-m-d')]], + ['2020-01-01 10:10:10', [new DateTime(format: 'Y-m-d H:i:s')]], + ['10.02.2023', [new DateTime(format: 'd.m.Y')]], + ['10/02/2023', [new DateTime(format: 'd/m/Y')]], + ['April 30, 2023, 5:16 pm', [new DateTime(format: 'F j, Y, g:i a')]], + ['', [new DateTime(format: 'd-m-Y', skipOnEmpty: true)]], ]; } public function dataValidationFailed(): array { return [ - + 'incorrect input, is integer' => [ + 1, + [new DateTime(incorrectInputMessage: 'Custom incorrect input message.')], + ['' => ['Custom incorrect input message.']], + ], [ '2023-02-20ee', - [new DateTime(message: '{attribute} value is not a valid DateTime.')], - ['' => [' value is not a valid DateTime.']], + [new DateTime(format: 'Y-m-dee',)], + ['' => ['The is not a valid date.']], ], [ - '', - [new DateTime(message: '{attribute} value is not a valid DateTime.')], - ['' => [' value is not a valid DateTime.']], + '2023-02-30', + [new DateTime(format: 'Y-m-d', message: 'Attribute - {attribute}, value - {value}.')], + ['' => ['Attribute - , value - 2023-02-30.']], ], - [ - '2024-08-14 15:52:01', - [ - new DateTime( - min: new DateTimeImmutable('2024-08-15 15:52:01'), - formats: 'Y-m-d H:i:s' - ), - ], - ['' => [' must be no less than 2024-08-15 15:52:01.']], + 'custom incorrect input message with parameters, attribute set' => [ + ['attribute' => 1], + ['attribute' => [new DateTime(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')]], + ['attribute' => ['Attribute - attribute, type - int.']], ], - [ - '2024-08-15 15:52:02', - [ - new DateTime( - max: new DateTimeImmutable('2024-08-15 15:52:01'), - formats: 'Y-m-d H:i:s' - ), - ], - ['' => [' must be no greater than 2024-08-15 15:52:01.']], + 'incorrect input, is not date' => [ + 'datetime', + [new DateTime(message: 'Attribute - {attribute}, value - {value}.')], + ['' => ['Attribute - , value - datetime.']], + ], + 'empty string and custom message' => [ + '', + [new DateTime()], + ['' => ['The must be a date.']], + ], + [ + null, + [new DateTime()], + ['' => ['The must be a date.']], ], ]; } @@ -128,19 +96,13 @@ public function dataOptions(): array [ new DateTime(), [ - 'formats' => [], - 'min' => null, - 'max' => null, - 'lessThanMinMessage' => [ - 'template' => '{attribute} must be no less than {min}.', - 'parameters' => [], - ], - 'greaterThanMaxMessage' => [ - 'template' => '{attribute} must be no greater than {max}.', + 'format' => 'Y-m-d', + 'incorrectInputMessage' => [ + 'template' => 'The {attribute} must be a date.', 'parameters' => [], ], 'message' => [ - 'template' => '{attribute} value is not a valid DateTime.', + 'template' => 'The {attribute} is not a valid date.', 'parameters' => [], ], 'skipOnEmpty' => false, From fe64d1e2213df91a0f51931da005179eebc8bcf1 Mon Sep 17 00:00:00 2001 From: pamparam Date: Tue, 23 Jan 2024 20:37:54 +0300 Subject: [PATCH 7/9] corrected the condition --- src/Rule/DateTime.php | 2 +- src/Rule/DateTimeHandler.php | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Rule/DateTime.php b/src/Rule/DateTime.php index 26127a287..159bcdda7 100644 --- a/src/Rule/DateTime.php +++ b/src/Rule/DateTime.php @@ -62,7 +62,7 @@ final class DateTime implements DumpedRuleInterface, SkipOnErrorInterface, WhenI use WhenTrait; /** - * @link https://www.php.net/manual/en/function.date.php + * @link https://www.php.net/manual/en/datetimeimmutable.createfromformat.php * @psalm-var non-empty-string * @var string The allowed date formats. */ diff --git a/src/Rule/DateTimeHandler.php b/src/Rule/DateTimeHandler.php index dd723f531..53d69cd19 100644 --- a/src/Rule/DateTimeHandler.php +++ b/src/Rule/DateTimeHandler.php @@ -30,11 +30,12 @@ public function validate(mixed $value, object $rule, ValidationContext $context) 'type' => get_debug_type($value), ]); } + \DateTime::createFromFormat($rule->getFormat(), $value); - $date = \DateTime::createFromFormat($rule->getFormat(), $value); - - if ($date === false || ($date->format($rule->getFormat()) !== $value)) { - $result->addError($rule->getMessage(), [ + // Before PHP 8.2 may return array instead of false (see https://github.com/php/php-src/issues/9431). + $errors = \DateTime::getLastErrors() ?: [ 'error_count' => 0, 'warning_count' => 0 ]; + if($errors['error_count'] != 0 || $errors['warning_count'] != 0){ + $result->addError($rule->getMessage(), [ 'attribute' => $context->getTranslatedAttribute(), 'value' => $value, ]); From 2cfa452cae14582f3e68c335e2147d890b2f2a59 Mon Sep 17 00:00:00 2001 From: pamparam Date: Thu, 25 Jan 2024 15:21:25 +0300 Subject: [PATCH 8/9] added tests and types --- src/Rule/DateTimeHandler.php | 6 +++--- tests/Rule/DateTimeTest.php | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Rule/DateTimeHandler.php b/src/Rule/DateTimeHandler.php index 53d69cd19..68f80b388 100644 --- a/src/Rule/DateTimeHandler.php +++ b/src/Rule/DateTimeHandler.php @@ -24,17 +24,17 @@ public function validate(mixed $value, object $rule, ValidationContext $context) $result = new Result(); - if (!is_string($value) || empty($value)) { + if ((!is_string($value) && !is_int($value) && !is_float($value)) || empty($value)) { return $result->addError($rule->getIncorrectInputMessage(), [ 'attribute' => $context->getTranslatedAttribute(), 'type' => get_debug_type($value), ]); } - \DateTime::createFromFormat($rule->getFormat(), $value); + \DateTime::createFromFormat($rule->getFormat(), (string)$value); // Before PHP 8.2 may return array instead of false (see https://github.com/php/php-src/issues/9431). $errors = \DateTime::getLastErrors() ?: [ 'error_count' => 0, 'warning_count' => 0 ]; - if($errors['error_count'] != 0 || $errors['warning_count'] != 0){ + if($errors['error_count'] !== 0 || $errors['warning_count'] !== 0){ $result->addError($rule->getMessage(), [ 'attribute' => $context->getTranslatedAttribute(), 'value' => $value, diff --git a/tests/Rule/DateTimeTest.php b/tests/Rule/DateTimeTest.php index 6a6ac8f79..0065518d3 100644 --- a/tests/Rule/DateTimeTest.php +++ b/tests/Rule/DateTimeTest.php @@ -46,14 +46,17 @@ public function dataValidationPassed(): array ['10/02/2023', [new DateTime(format: 'd/m/Y')]], ['April 30, 2023, 5:16 pm', [new DateTime(format: 'F j, Y, g:i a')]], ['', [new DateTime(format: 'd-m-Y', skipOnEmpty: true)]], + ['125636000', [new DateTime(format: 'U')]], + [125636000, [new DateTime(format: 'U')]], + [123456.344, [new DateTime(format: 'U.u')]], ]; } public function dataValidationFailed(): array { return [ - 'incorrect input, is integer' => [ - 1, + 'incorrect input, is boolean' => [ + true, [new DateTime(incorrectInputMessage: 'Custom incorrect input message.')], ['' => ['Custom incorrect input message.']], ], @@ -62,15 +65,20 @@ public function dataValidationFailed(): array [new DateTime(format: 'Y-m-dee',)], ['' => ['The is not a valid date.']], ], + [ + '2024-02-20', + [new DateTime(format: 'H:i',)], + ['' => ['The is not a valid date.']], + ], [ '2023-02-30', [new DateTime(format: 'Y-m-d', message: 'Attribute - {attribute}, value - {value}.')], ['' => ['Attribute - , value - 2023-02-30.']], ], 'custom incorrect input message with parameters, attribute set' => [ - ['attribute' => 1], + ['attribute' => []], ['attribute' => [new DateTime(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')]], - ['attribute' => ['Attribute - attribute, type - int.']], + ['attribute' => ['Attribute - attribute, type - array.']], ], 'incorrect input, is not date' => [ 'datetime', From a0a4d49e41f203d58ab435b48c0138b717eb42cd Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 25 Jan 2024 21:19:44 +0300 Subject: [PATCH 9/9] Update CHANGELOG.md Co-authored-by: Sergei Tigrov --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50df18c0b..e353623e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.0.0 under development -- New #646: Add DateTime rule (@pamparam83) +- New #646: Add `DateTime` rule (@pamparam83) - New #615: Add the `Each::PARAMETER_EACH_KEY` validation context parameter that available during `Each` rule handling and containing the current key (@dood-) - Enh #648: Raise the minimum version of PHP to 8.1 (@pamparam83)