From 31a72cd4c86b4a75d6f1dfef2995932ef2f62707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Tue, 19 Mar 2024 15:27:53 +0000 Subject: [PATCH 1/6] chore: simplified min and max parameter naming --- docs/03-rules_choice.md | 70 +++++++++++++++---------------- docs/03-rules_range.md | 28 ++++++------- src/ChainedValidatorInterface.php | 14 +++---- src/Rule/Choice.php | 28 ++++++------- src/Rule/Range.php | 22 +++++----- src/StaticValidatorInterface.php | 14 +++---- tests/ChoiceTest.php | 10 ++--- tests/RangeTest.php | 8 ++-- 8 files changed, 97 insertions(+), 97 deletions(-) diff --git a/docs/03-rules_choice.md b/docs/03-rules_choice.md index 459e9b1..71ebe5e 100644 --- a/docs/03-rules_choice.md +++ b/docs/03-rules_choice.md @@ -6,12 +6,12 @@ Validates that a value (or multiple values) exist in a given set of choices. Choice( array $constraints, bool $multiple = false, - ?int $minConstraint = null, - ?int $maxConstraint = null, + ?int $min = null, + ?int $max = null, string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - string $minMessage = 'The {{ name }} value must have at least {{ minConstraint }} choices, {{ numValues }} choices given.', - string $maxMessage = 'The {{ name }} value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given.' + string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', + string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' ); ``` @@ -27,23 +27,23 @@ Validator::choice(['red', 'green', 'blue'], multiple: true)->validate(['red', 'b Validator::choice(['red', 'green', 'blue'], multiple: true)->validate(['red', 'yellow']); // false; // Multiple with minimum number of choices -Validator::choice(['red', 'green', 'blue'], multiple: true, minConstraint: 2)->validate(['red', 'blue']); // true -Validator::choice(['red', 'green', 'blue'], multiple: true, minConstraint: 2)->validate(['red']); // false +Validator::choice(['red', 'green', 'blue'], multiple: true, min: 2)->validate(['red', 'blue']); // true +Validator::choice(['red', 'green', 'blue'], multiple: true, min: 2)->validate(['red']); // false // Multiple with maximum number of choices -Validator::choice(['red', 'green', 'blue'], multiple: true, maxConstraint: 2)->validate(['red', 'blue']); // true -Validator::choice(['red', 'green', 'blue'], multiple: true, maxConstraint: 2)->validate(['red', 'green', 'blue']); // false +Validator::choice(['red', 'green', 'blue'], multiple: true, max: 2)->validate(['red', 'blue']); // true +Validator::choice(['red', 'green', 'blue'], multiple: true, max: 2)->validate(['red', 'green', 'blue']); // false // Multiple with minimum and maximum number of choices -Validator::choice(['red', 'green', 'blue'], multiple: true, minConstraint: 2, maxConstraint: 3)->validate(['red', 'blue']); // true -Validator::choice(['red', 'green', 'blue'], multiple: true, minConstraint: 2, maxConstraint: 3)->validate(['red']); // false +Validator::choice(['red', 'green', 'blue'], multiple: true, min: 2, max: 3)->validate(['red', 'blue']); // true +Validator::choice(['red', 'green', 'blue'], multiple: true, min: 2, max: 3)->validate(['red']); // false ``` > [!NOTE] > An `UnexpectedValueException` will be thrown when `multiple` is `true` and the input value is not an `array`. > [!NOTE] -> An `UnexpectedValueException` will be thrown when the `minConstraint` value is greater than or equal to the `maxConstraint` value. +> An `UnexpectedValueException` will be thrown when the `min` value is greater than or equal to the `max` value. ## Options @@ -60,21 +60,21 @@ type: `bool` default: `false` If this option is `true`, validation against an `array` of input values is enabled. Each element of the input array must be a valid choice, otherwise it will fail. -### `minConstraint` +### `min` type: `?int` default: `null` If `multiple` is `true`, set a minimum number of input values to be required. -For example, if `minConstraint` is 2, the input array must have at least 2 values. +For example, if `min` is 2, the input array must have at least 2 values. -### `maxConstraint` +### `max` type: `?int` default: `null` If `multiple` is `true`, set a maximum number of input values to be required. -For example, if `maxConstraint` is 2, the input array must have at most 2 values. +For example, if `max` is 2, the input array must have at most 2 values. ### `message` @@ -106,37 +106,37 @@ The following parameters are available: ### `minMessage` -type: `string` default: `The {{ name }} value must have at least {{ minConstraint }} choices, {{ numValues }} choices given.` +type: `string` default: `The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.` -Message that will be shown when `multiple` is `true` and input array has fewer values than the defined in `minConstraint`. +Message that will be shown when `multiple` is `true` and input array has fewer values than the defined in `min`. The following parameters are available: -| Parameter | Description | -|-----------------------|--------------------------------------| -| `{{ value }}` | The current invalid value | -| `{{ numValues }}` | The current invalid number of values | -| `{{ name }}` | Name of the invalid value | -| `{{ constraints }}` | The array of valid choices | -| `{{ minConstraint }}` | The minimum number of valid choices | -| `{{ maxConstraint }}` | The maximum number of valid choices | +| Parameter | Description | +|---------------------|--------------------------------------| +| `{{ value }}` | The current invalid value | +| `{{ numValues }}` | The current invalid number of values | +| `{{ name }}` | Name of the invalid value | +| `{{ constraints }}` | The array of valid choices | +| `{{ min }}` | The minimum number of valid choices | +| `{{ max }}` | The maximum number of valid choices | ### `maxMessage` -type: `string` default: `The {{ name }} value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given.` +type: `string` default: `The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.` -Message that will be shown when `multiple` is `true` and input array has more values than the defined in `maxConstraint`. +Message that will be shown when `multiple` is `true` and input array has more values than the defined in `max`. The following parameters are available: -| Parameter | Description | -|-----------------------|--------------------------------------| -| `{{ value }}` | The current invalid value | -| `{{ numValues }}` | The current invalid number of values | -| `{{ name }}` | Name of the invalid value | -| `{{ constraints }}` | The array of valid choices | -| `{{ minConstraint }}` | The minimum number of valid choices | -| `{{ maxConstraint }}` | The maximum number of valid choices | +| Parameter | Description | +|---------------------|--------------------------------------| +| `{{ value }}` | The current invalid value | +| `{{ numValues }}` | The current invalid number of values | +| `{{ name }}` | Name of the invalid value | +| `{{ constraints }}` | The array of valid choices | +| `{{ min }}` | The minimum number of valid choices | +| `{{ max }}` | The maximum number of valid choices | ## Changelog diff --git a/docs/03-rules_range.md b/docs/03-rules_range.md index 6f7e3e8..f5fbfde 100644 --- a/docs/03-rules_range.md +++ b/docs/03-rules_range.md @@ -5,9 +5,9 @@ Can compare between strings, numbers and dates. ```php Range( - mixed $minConstraint, - mixed $maxConstraint, - string $message = 'The {{ name }} value should be between {{ minConstraint }} and {{ maxConstraint }}, {{ value }} given.' + mixed $min, + mixed $max, + string $message = 'The {{ name }} value should be between {{ min }} and {{ max }}, {{ value }} given.' ); ``` @@ -37,18 +37,18 @@ Validator::range(new DateTime('yesterday'), new DateTime('tomorrow'))->validate( > An `UnexpectedValueException` will be thrown when trying to compare incomparable values, like a `string` with an `int`. > [!NOTE] -> An `UnexpectedValueException` will be thrown when the `minConstraint` value is greater than or equal to the `maxConstraint` value. +> An `UnexpectedValueException` will be thrown when the `min` value is greater than or equal to the `max` value. ## Options -### `minConstraint` +### `min` type: `mixed` `required` It defines the minimum range value. Can be a `string`, `int`, `float` or `DateTimeInterface` object. -### `maxConstraint` +### `max` type: `mixed` `required` @@ -57,18 +57,18 @@ Can be a `string`, `int`, `float` or `DateTimeInterface` object. ### `message` -type: `string` default: `The {{ name }} value should be between {{ minConstraint }} and {{ maxConstraint }}, {{ value }} given.` +type: `string` default: `The {{ name }} value should be between {{ min }} and {{ max }}, {{ value }} given.` -Message that will be shown if the value is not between the minimum and maximum constraint values. +Message that will be shown if the value is not between the minimum and maximum values. The following parameters are available: -| Parameter | Description | -|-----------------------|---------------------------| -| `{{ value }}` | The current invalid value | -| `{{ name }}` | Name of the invalid value | -| `{{ minConstraint }}` | The minimum range value | -| `{{ maxConstraint }}` | The maximum range value | +| Parameter | Description | +|---------------|---------------------------| +| `{{ value }}` | The current invalid value | +| `{{ name }}` | Name of the invalid value | +| `{{ min }}` | The minimum range value | +| `{{ max }}` | The maximum range value | ## Changelog diff --git a/src/ChainedValidatorInterface.php b/src/ChainedValidatorInterface.php index 09e3812..d5e59e1 100644 --- a/src/ChainedValidatorInterface.php +++ b/src/ChainedValidatorInterface.php @@ -10,12 +10,12 @@ interface ChainedValidatorInterface public function choice( array $constraints, bool $multiple = false, - ?int $minConstraint = null, - ?int $maxConstraint = null, + ?int $min = null, + ?int $max = null, string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - string $minMessage = 'The {{ name }} value must have at least {{ minConstraint }} choices, {{ numValues }} choices given.', - string $maxMessage = 'The {{ name }} value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given.' + string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', + string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' ): ChainedValidatorInterface&Validator; public function country( @@ -65,9 +65,9 @@ public function notBlank( ): ChainedValidatorInterface&Validator; public function range( - mixed $minConstraint, - mixed $maxConstraint, - string $message = 'The {{ name }} value should be between {{ minConstraint }} and {{ maxConstraint }}, {{ value }} given.' + mixed $min, + mixed $max, + string $message = 'The {{ name }} value should be between {{ min }} and {{ max }}, {{ value }} given.' ): ChainedValidatorInterface&Validator; public function rule( diff --git a/src/Rule/Choice.php b/src/Rule/Choice.php index a578f50..26ecc76 100644 --- a/src/Rule/Choice.php +++ b/src/Rule/Choice.php @@ -11,12 +11,12 @@ class Choice extends AbstractRule implements RuleInterface public function __construct( private readonly array $constraints, private readonly bool $multiple = false, - private readonly ?int $minConstraint = null, - private readonly ?int $maxConstraint = null, + private readonly ?int $min = null, + private readonly ?int $max = null, private readonly string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', private readonly string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - private readonly string $minMessage = 'The {{ name }} value must have at least {{ minConstraint }} choices, {{ numValues }} choices given.', - private readonly string $maxMessage = 'The {{ name }} value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given.' + private readonly string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', + private readonly string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' ) {} public function assert(mixed $value, ?string $name = null): void @@ -27,12 +27,12 @@ public function assert(mixed $value, ?string $name = null): void if ( $this->multiple - && $this->minConstraint !== null - && $this->maxConstraint !== null - && $this->minConstraint > $this->maxConstraint + && $this->min !== null + && $this->max !== null + && $this->min > $this->max ) { throw new UnexpectedValueException( - 'Max constraint value must be greater than or equal to min constraint value.' + 'Maximum value must be greater than or equal to minimum value.' ); } @@ -52,7 +52,7 @@ public function assert(mixed $value, ?string $name = null): void $numValues = \count($value); - if ($this->minConstraint !== null && $numValues < $this->minConstraint) { + if ($this->min !== null && $numValues < $this->min) { throw new ChoiceException( message: $this->minMessage, parameters: [ @@ -60,13 +60,13 @@ public function assert(mixed $value, ?string $name = null): void 'numValues' => $numValues, 'name' => $name, 'constraints' => $this->constraints, - 'minConstraint' => $this->minConstraint, - 'maxConstraint' => $this->maxConstraint + 'min' => $this->min, + 'max' => $this->max ] ); } - if ($this->maxConstraint !== null && $numValues > $this->maxConstraint) { + if ($this->max !== null && $numValues > $this->max) { throw new ChoiceException( message: $this->maxMessage, parameters: [ @@ -74,8 +74,8 @@ public function assert(mixed $value, ?string $name = null): void 'numValues' => $numValues, 'name' => $name, 'constraints' => $this->constraints, - 'minConstraint' => $this->minConstraint, - 'maxConstraint' => $this->maxConstraint + 'min' => $this->min, + 'max' => $this->max ] ); } diff --git a/src/Rule/Range.php b/src/Rule/Range.php index bd9b3ef..bedbca4 100644 --- a/src/Rule/Range.php +++ b/src/Rule/Range.php @@ -13,34 +13,34 @@ class Range extends AbstractRule implements RuleInterface use ComparableTrait; public function __construct( - private readonly mixed $minConstraint, - private readonly mixed $maxConstraint, - private readonly string $message = 'The {{ name }} value should be between {{ minConstraint }} and {{ maxConstraint }}, {{ value }} given.' + private readonly mixed $min, + private readonly mixed $max, + private readonly string $message = 'The {{ name }} value should be between {{ min }} and {{ max }}, {{ value }} given.' ) {} public function assert(mixed $value, ?string $name = null): void { - if (!$this->isComparable($this->minConstraint, $this->maxConstraint)) { + if (!$this->isComparable($this->min, $this->max)) { throw new UnexpectedComparableException( - get_debug_type($this->minConstraint), - get_debug_type($this->maxConstraint) + get_debug_type($this->min), + get_debug_type($this->max) ); } - if (!Validator::greaterThan($this->minConstraint)->validate($this->maxConstraint)) { + if (!Validator::greaterThan($this->min)->validate($this->max)) { throw new UnexpectedValueException( - 'Max constraint value must be greater than min constraint value.' + 'Maximum value must be greater than minimum value.' ); } - if (!Validator::greaterThanOrEqual($this->minConstraint)->lessThanOrEqual($this->maxConstraint)->validate($value)) { + if (!Validator::greaterThanOrEqual($this->min)->lessThanOrEqual($this->max)->validate($value)) { throw new RangeException( message: $this->message, parameters: [ 'value' => $value, 'name' => $name, - 'minConstraint' => $this->minConstraint, - 'maxConstraint' => $this->maxConstraint + 'min' => $this->min, + 'max' => $this->max ] ); } diff --git a/src/StaticValidatorInterface.php b/src/StaticValidatorInterface.php index 7765480..f52f615 100644 --- a/src/StaticValidatorInterface.php +++ b/src/StaticValidatorInterface.php @@ -9,12 +9,12 @@ interface StaticValidatorInterface public static function choice( array $constraints, bool $multiple = false, - ?int $minConstraint = null, - ?int $maxConstraint = null, + ?int $min = null, + ?int $max = null, string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - string $minMessage = 'The {{ name }} value must have at least {{ minConstraint }} choices, {{ numValues }} choices given.', - string $maxMessage = 'The {{ name }} value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given.' + string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', + string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' ): ChainedValidatorInterface&Validator; public static function country( @@ -64,9 +64,9 @@ public static function notBlank( ): ChainedValidatorInterface&Validator; public static function range( - mixed $minConstraint, - mixed $maxConstraint, - string $message = 'The {{ name }} value should be between {{ minConstraint }} and {{ maxConstraint }}, {{ value }} given.' + mixed $min, + mixed $max, + string $message = 'The {{ name }} value should be between {{ min }} and {{ max }}, {{ value }} given.' ): ChainedValidatorInterface&Validator; public static function rule( diff --git a/tests/ChoiceTest.php b/tests/ChoiceTest.php index 1902b3d..adc1f0b 100644 --- a/tests/ChoiceTest.php +++ b/tests/ChoiceTest.php @@ -20,7 +20,7 @@ public static function provideRuleUnexpectedValueData(): \Generator { $constraints = [1, 2, 3, 4, 5]; $multipleMessage = '/Expected value of type "array", "(.*)" given/'; - $constraintMessage = '/Max constraint value must be greater than or equal to min constraint value./'; + $constraintMessage = '/Maximum value must be greater than or equal to minimum value./'; yield 'multiple not array' => [new Choice($constraints, true), 1, $multipleMessage]; yield 'min greater than max constraint' => [new Choice($constraints, true, 3, 2), [1, 2], $constraintMessage]; @@ -82,8 +82,8 @@ public static function provideRuleMessageOptionData(): \Generator new Choice( constraints: $constraints, multiple: true, - minConstraint: 2, - minMessage: 'The {{ name }} value should have at least {{ minConstraint }} choices.' + min: 2, + minMessage: 'The {{ name }} value should have at least {{ min }} choices.' ), [1], 'The test value should have at least 2 choices.' @@ -92,8 +92,8 @@ public static function provideRuleMessageOptionData(): \Generator new Choice( constraints: $constraints, multiple: true, - maxConstraint: 2, - maxMessage: 'The {{ name }} value should have at most {{ maxConstraint }} choices.' + max: 2, + maxMessage: 'The {{ name }} value should have at most {{ max }} choices.' ), [1, 2, 3], 'The test value should have at most 2 choices.' diff --git a/tests/RangeTest.php b/tests/RangeTest.php index 1305250..c98484e 100644 --- a/tests/RangeTest.php +++ b/tests/RangeTest.php @@ -19,7 +19,7 @@ class RangeTest extends AbstractTest public static function provideRuleUnexpectedValueData(): \Generator { $comparableMessage = '/Cannot compare a type "(.*)" with a type "(.*)"/'; - $constraintMessage = '/Max constraint value must be greater than min constraint value./'; + $constraintMessage = '/Maximum value must be greater than minimum value./'; yield 'datetime constraint with int constraint' => [new Range(new \DateTime(), 10), new \DateTime(), $comparableMessage]; yield 'datetime constraint with float constraint' => [new Range(new \DateTime(), 10.0), new \DateTime(), $comparableMessage]; @@ -73,9 +73,9 @@ public static function provideRuleMessageOptionData(): \Generator { yield 'message' => [ new Range( - minConstraint: 10, - maxConstraint: 20, - message: 'The {{ name }} value {{ value }} should be between {{ minConstraint }} and {{ maxConstraint }}.' + min: 10, + max: 20, + message: 'The {{ name }} value {{ value }} should be between {{ min }} and {{ max }}.' ), 30, 'The test value 30 should be between 10 and 20.' From c010641d7598def8378fa1136731347c87c90116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Tue, 19 Mar 2024 15:59:02 +0000 Subject: [PATCH 2/6] chore: changed choice numValues parameter to numElements --- docs/03-rules_choice.md | 40 +++++++++++++++---------------- src/ChainedValidatorInterface.php | 4 ++-- src/Rule/Choice.php | 18 +++++++------- src/StaticValidatorInterface.php | 4 ++-- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/docs/03-rules_choice.md b/docs/03-rules_choice.md index 71ebe5e..a099210 100644 --- a/docs/03-rules_choice.md +++ b/docs/03-rules_choice.md @@ -10,8 +10,8 @@ Choice( ?int $max = null, string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', - string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' + string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numElements }} choices given.', + string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numElements }} choices given.' ); ``` @@ -106,37 +106,37 @@ The following parameters are available: ### `minMessage` -type: `string` default: `The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.` +type: `string` default: `The {{ name }} value must have at least {{ min }} choices, {{ numElements }} choices given.` Message that will be shown when `multiple` is `true` and input array has fewer values than the defined in `min`. The following parameters are available: -| Parameter | Description | -|---------------------|--------------------------------------| -| `{{ value }}` | The current invalid value | -| `{{ numValues }}` | The current invalid number of values | -| `{{ name }}` | Name of the invalid value | -| `{{ constraints }}` | The array of valid choices | -| `{{ min }}` | The minimum number of valid choices | -| `{{ max }}` | The maximum number of valid choices | +| Parameter | Description | +|---------------------|----------------------------------------| +| `{{ value }}` | The current invalid value | +| `{{ name }}` | Name of the invalid value | +| `{{ constraints }}` | The array of valid choices | +| `{{ min }}` | The minimum number of valid choices | +| `{{ max }}` | The maximum number of valid choices | +| `{{ numElements }}` | The current invalid number of elements | ### `maxMessage` -type: `string` default: `The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.` +type: `string` default: `The {{ name }} value must have at most {{ max }} choices, {{ numElements }} choices given.` Message that will be shown when `multiple` is `true` and input array has more values than the defined in `max`. The following parameters are available: -| Parameter | Description | -|---------------------|--------------------------------------| -| `{{ value }}` | The current invalid value | -| `{{ numValues }}` | The current invalid number of values | -| `{{ name }}` | Name of the invalid value | -| `{{ constraints }}` | The array of valid choices | -| `{{ min }}` | The minimum number of valid choices | -| `{{ max }}` | The maximum number of valid choices | +| Parameter | Description | +|---------------------|----------------------------------------| +| `{{ value }}` | The current invalid value | +| `{{ name }}` | Name of the invalid value | +| `{{ constraints }}` | The array of valid choices | +| `{{ min }}` | The minimum number of valid choices | +| `{{ max }}` | The maximum number of valid choices | +| `{{ numElements }}` | The current invalid number of elements | ## Changelog diff --git a/src/ChainedValidatorInterface.php b/src/ChainedValidatorInterface.php index d5e59e1..867754b 100644 --- a/src/ChainedValidatorInterface.php +++ b/src/ChainedValidatorInterface.php @@ -14,8 +14,8 @@ public function choice( ?int $max = null, string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', - string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' + string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numElements }} choices given.', + string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numElements }} choices given.' ): ChainedValidatorInterface&Validator; public function country( diff --git a/src/Rule/Choice.php b/src/Rule/Choice.php index 26ecc76..c8a0ab9 100644 --- a/src/Rule/Choice.php +++ b/src/Rule/Choice.php @@ -15,8 +15,8 @@ public function __construct( private readonly ?int $max = null, private readonly string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', private readonly string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - private readonly string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', - private readonly string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' + private readonly string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numElements }} choices given.', + private readonly string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numElements }} choices given.' ) {} public function assert(mixed $value, ?string $name = null): void @@ -50,32 +50,32 @@ public function assert(mixed $value, ?string $name = null): void } } - $numValues = \count($value); + $numElements = \count($value); - if ($this->min !== null && $numValues < $this->min) { + if ($this->min !== null && $numElements < $this->min) { throw new ChoiceException( message: $this->minMessage, parameters: [ 'value' => $value, - 'numValues' => $numValues, 'name' => $name, 'constraints' => $this->constraints, 'min' => $this->min, - 'max' => $this->max + 'max' => $this->max, + 'numElements' => $numElements ] ); } - if ($this->max !== null && $numValues > $this->max) { + if ($this->max !== null && $numElements > $this->max) { throw new ChoiceException( message: $this->maxMessage, parameters: [ 'value' => $value, - 'numValues' => $numValues, 'name' => $name, 'constraints' => $this->constraints, 'min' => $this->min, - 'max' => $this->max + 'max' => $this->max, + 'numElements' => $numElements ] ); } diff --git a/src/StaticValidatorInterface.php b/src/StaticValidatorInterface.php index f52f615..1cb3f8b 100644 --- a/src/StaticValidatorInterface.php +++ b/src/StaticValidatorInterface.php @@ -13,8 +13,8 @@ public static function choice( ?int $max = null, string $message = 'The {{ name }} value is not a valid choice, {{ value }} given. Accepted values are: {{ constraints }}.', string $multipleMessage = 'The {{ name }} value has one or more invalid choices, {{ value }} given. Accepted values are: {{ constraints }}.', - string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numValues }} choices given.', - string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numValues }} choices given.' + string $minMessage = 'The {{ name }} value must have at least {{ min }} choices, {{ numElements }} choices given.', + string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numElements }} choices given.' ): ChainedValidatorInterface&Validator; public static function country( From 8cd823283b8e376a85dd048d105e1f9cdea38826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Tue, 19 Mar 2024 16:36:58 +0000 Subject: [PATCH 3/6] feat: added Count rule --- src/Exception/CountException.php | 5 ++ src/Rule/Count.php | 70 +++++++++++++++++++++++++++ tests/CountTest.php | 82 ++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 src/Exception/CountException.php create mode 100644 src/Rule/Count.php create mode 100644 tests/CountTest.php diff --git a/src/Exception/CountException.php b/src/Exception/CountException.php new file mode 100644 index 0000000..cfd040e --- /dev/null +++ b/src/Exception/CountException.php @@ -0,0 +1,5 @@ +minMessage = $minMessage ?? $this->minMessage; + $this->maxMessage = $maxMessage ?? $this->maxMessage; + $this->exactMessage = $exactMessage ?? $this->exactMessage; + } + + public function assert(mixed $value, ?string $name = null): void + { + if ($this->min === null && $this->max === null) { + throw new UnexpectedValueException('At least one of the options "min" or "max" must be given.'); + } + + if (!\is_countable($value)) { + throw new UnexpectedTypeException('array|\Countable', get_debug_type($value)); + } + + $numElements = \count($value); + + if ($this->min !== null && $numElements < $this->min) { + $message = $this->min === $this->max ? $this->exactMessage : $this->minMessage; + + throw new CountException( + message: $message, + parameters: [ + 'value' => $value, + 'name' => $name, + 'min' => $this->min, + 'max' => $this->max, + 'numElements' => $numElements + ] + ); + } + + if ($this->max !== null && $numElements > $this->max) { + $message = $this->min === $this->max ? $this->exactMessage : $this->maxMessage; + + throw new CountException( + message: $message, + parameters: [ + 'value' => $value, + 'name' => $name, + 'min' => $this->min, + 'max' => $this->max, + 'numElements' => $numElements + ] + ); + } + } +} \ No newline at end of file diff --git a/tests/CountTest.php b/tests/CountTest.php new file mode 100644 index 0000000..314f104 --- /dev/null +++ b/tests/CountTest.php @@ -0,0 +1,82 @@ + [new Count(), [1, 2, 3], $missingOptionsMessage]; + yield 'invalid type value' => [new Count(min: 5, max: 10), 1, $invalidTypeMessage]; + } + + public static function provideRuleFailureConditionData(): \Generator + { + $value = [1, 2, 3, 4, 5]; + $exception = CountException::class; + $minMessage = '/The (.*) value should contain (.*) elements or more, (.*) elements given./'; + $maxMessage = '/The (.*) value should contain (.*) elements or less, (.*) elements given./'; + $exactMessage = '/The (.*) value should contain exactly (.*) elements, (.*) elements given./'; + + yield 'min constraint' => [new Count(min: 10), $value, $exception, $minMessage]; + yield 'max constraint' => [new Count(max: 2), $value, $exception, $maxMessage]; + yield 'min and max constraint' => [new Count(min: 10, max: 20), $value, $exception, $minMessage]; + yield 'exact constraint' => [new Count(min: 2, max: 2), $value, $exception, $exactMessage]; + } + + public static function provideRuleSuccessConditionData(): \Generator + { + $value = [1, 2, 3, 4, 5]; + + yield 'min constraint' => [new Count(min: 5), $value]; + yield 'max constraint' => [new Count(max: 5), $value]; + yield 'min and max constraint' => [new Count(min: 4, max: 6), $value]; + yield 'exact constraint' => [new Count(min: 5, max: 5), $value]; + } + + public static function provideRuleMessageOptionData(): \Generator + { + $value = [1, 2, 3, 4, 5]; + + yield 'min message' => [ + new Count( + min: 10, + minMessage: 'The {{ name }} value should have at least {{ min }} elements.' + ), + $value, + 'The test value should have at least 10 elements.' + ]; + yield 'max message' => [ + new Count( + max: 2, + maxMessage: 'The {{ name }} value should have at most {{ max }} elements.' + ), + $value, + 'The test value should have at most 2 elements.' + ]; + yield 'exact message' => [ + new Count( + min: 2, + max: 2, + exactMessage: 'The {{ name }} value should have exactly {{ min }} elements.' + ), + $value, + 'The test value should have exactly 2 elements.' + ]; + } +} \ No newline at end of file From 8c081aa983ee9eee2b300b98a9101e5143ec91ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Tue, 19 Mar 2024 17:05:44 +0000 Subject: [PATCH 4/6] chore: added validation when min is greater than max --- docs/03-rules_each-value.md | 2 +- src/ChainedValidatorInterface.php | 8 ++++++++ src/Rule/Count.php | 11 ++++++++++- src/Rule/Range.php | 4 +--- src/StaticValidatorInterface.php | 8 ++++++++ tests/CountTest.php | 2 ++ 6 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/03-rules_each-value.md b/docs/03-rules_each-value.md index afe2fed..cf8bba3 100644 --- a/docs/03-rules_each-value.md +++ b/docs/03-rules_each-value.md @@ -1,6 +1,6 @@ ## EachValue -Validates every element of an `array` or object implementing `\Traversable` with a given set of rules. +Validates every element of an `array`, or object implementing `\Traversable`, with a given set of rules. ```php EachValue( diff --git a/src/ChainedValidatorInterface.php b/src/ChainedValidatorInterface.php index 867754b..56c33a1 100644 --- a/src/ChainedValidatorInterface.php +++ b/src/ChainedValidatorInterface.php @@ -18,6 +18,14 @@ public function choice( string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numElements }} choices given.' ): ChainedValidatorInterface&Validator; + public function count( + ?int $min = null, + ?int $max = null, + ?string $minMessage = null, + ?string $maxMessage = null, + ?string $exactMessage = null + ): ChainedValidatorInterface&Validator; + public function country( string $code = 'alpha-2', string $message = 'The {{ name }} value is not a valid {{ code }} country code, {{ value }} given.' diff --git a/src/Rule/Count.php b/src/Rule/Count.php index 015ea7c..43b34ed 100644 --- a/src/Rule/Count.php +++ b/src/Rule/Count.php @@ -5,12 +5,13 @@ use ProgrammatorDev\Validator\Exception\CountException; use ProgrammatorDev\Validator\Exception\UnexpectedTypeException; use ProgrammatorDev\Validator\Exception\UnexpectedValueException; +use ProgrammatorDev\Validator\Validator; class Count extends AbstractRule implements RuleInterface { private string $minMessage = 'The {{ name }} value should contain {{ min }} elements or more, {{ numElements }} elements given.'; private string $maxMessage = 'The {{ name }} value should contain {{ max }} elements or less, {{ numElements }} elements given.'; - private string $exactMessage = 'The {{ name }} value should contain exactly {{ numElements }} elements, {{ numElements }} elements given.'; + private string $exactMessage = 'The {{ name }} value should contain exactly {{ min }} elements, {{ numElements }} elements given.'; public function __construct( private readonly ?int $min = null, @@ -31,6 +32,14 @@ public function assert(mixed $value, ?string $name = null): void throw new UnexpectedValueException('At least one of the options "min" or "max" must be given.'); } + if ( + $this->min !== null + && $this->max !== null + && !Validator::greaterThanOrEqual($this->min)->validate($this->max) + ) { + throw new UnexpectedValueException('Maximum value must be greater than or equal to minimum value.'); + } + if (!\is_countable($value)) { throw new UnexpectedTypeException('array|\Countable', get_debug_type($value)); } diff --git a/src/Rule/Range.php b/src/Rule/Range.php index bedbca4..a91581f 100644 --- a/src/Rule/Range.php +++ b/src/Rule/Range.php @@ -28,9 +28,7 @@ public function assert(mixed $value, ?string $name = null): void } if (!Validator::greaterThan($this->min)->validate($this->max)) { - throw new UnexpectedValueException( - 'Maximum value must be greater than minimum value.' - ); + throw new UnexpectedValueException('Maximum value must be greater than minimum value.'); } if (!Validator::greaterThanOrEqual($this->min)->lessThanOrEqual($this->max)->validate($value)) { diff --git a/src/StaticValidatorInterface.php b/src/StaticValidatorInterface.php index 1cb3f8b..62b0a98 100644 --- a/src/StaticValidatorInterface.php +++ b/src/StaticValidatorInterface.php @@ -17,6 +17,14 @@ public static function choice( string $maxMessage = 'The {{ name }} value must have at most {{ max }} choices, {{ numElements }} choices given.' ): ChainedValidatorInterface&Validator; + public static function count( + ?int $min = null, + ?int $max = null, + ?string $minMessage = null, + ?string $maxMessage = null, + ?string $exactMessage = null + ): ChainedValidatorInterface&Validator; + public static function country( string $code = 'alpha-2', string $message = 'The {{ name }} value is not a valid {{ code }} country code, {{ value }} given.' diff --git a/tests/CountTest.php b/tests/CountTest.php index 314f104..1436c3e 100644 --- a/tests/CountTest.php +++ b/tests/CountTest.php @@ -20,9 +20,11 @@ public static function provideRuleUnexpectedValueData(): \Generator { $missingOptionsMessage = '/At least one of the options "min" or "max" must be given./'; $invalidTypeMessage = '/Expected value of type "array|\Countable", "(.*)" given./'; + $constraintMessage = '/Maximum value must be greater than or equal to minimum value./'; yield 'missing options' => [new Count(), [1, 2, 3], $missingOptionsMessage]; yield 'invalid type value' => [new Count(min: 5, max: 10), 1, $invalidTypeMessage]; + yield 'min greater than max constraint' => [new Count(min: 10, max: 5), 1, $constraintMessage]; } public static function provideRuleFailureConditionData(): \Generator From c0fc5ebcf1ecf35a1d99717d40109f03cbe0823d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Tue, 19 Mar 2024 17:16:03 +0000 Subject: [PATCH 5/6] docs: added Count rule --- docs/03-rules_count.md | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 docs/03-rules_count.md diff --git a/docs/03-rules_count.md b/docs/03-rules_count.md new file mode 100644 index 0000000..94ae724 --- /dev/null +++ b/docs/03-rules_count.md @@ -0,0 +1,110 @@ +# Count + +Validates that the number of elements of an `array`, or object implementing `\Countable`, is between a minimum and maximum value. + +```php +Count( + ?int $min = null, + ?int $max = null, + ?string $minMessage = null, + ?string $maxMessage = null, + ?string $exactMessage = null +); +``` + +## Basic Usage + +```php +// min value +Validator::count(min: 1)->validate(['a', 'b', 'c']); // true +Validator::count(min: 5)->validate(['a', 'b', 'c']); // false + +// max value +Validator::count(max: 5)->validate(['a', 'b', 'c']); // true +Validator::count(max: 1)->validate(['a', 'b', 'c']); // false + +// min and max value +Validator::count(min: 2, max: 4)->validate(['a', 'b', 'c']); // true + +// exact value +Validator::count(min: 3, max: 3)->validate(['a', 'b', 'c']); // true +``` + +> [!NOTE] +> An `UnexpectedValueException` will be thrown when either `min` or `max` options are not given. + +> [!NOTE] +> An `UnexpectedValueException` will be thrown when the input value is not an `array` or an object implementing `\Countable`. + +> [!NOTE] +> An `UnexpectedValueException` will be thrown when the `min` value is greater than the `max` value. + +## Options + +### `min` + +type: `?int` default: `null` + +It defines the minimum number of elements required. + +For example, if `min` is 2, the input value must have at least 2 elements. + +### `max` + +type: `?int` default: `null` + +It defines the maximum number of elements required. + +For example, if `max` is 2, the input value must have at most 2 elements. + +### `minMessage` + +type: `?string` default: `The {{ name }} value should contain {{ min }} elements or more, {{ numElements }} elements given.` + +Message that will be shown when the input value has fewer elements than the defined in `min`. + +The following parameters are available: + +| Parameter | Description | +|---------------------|----------------------------------------| +| `{{ value }}` | The current invalid value | +| `{{ name }}` | Name of the invalid value | +| `{{ min }}` | The minimum number of valid elements | +| `{{ max }}` | The maximum number of valid elements | +| `{{ numElements }}` | The current invalid number of elements | + +### `maxMessage` + +type: `?string` default: `The {{ name }} value should contain {{ max }} elements or less, {{ numElements }} elements given.` + +Message that will be shown when the input value has more elements than the defined in `max`. + +The following parameters are available: + +| Parameter | Description | +|---------------------|----------------------------------------| +| `{{ value }}` | The current invalid value | +| `{{ name }}` | Name of the invalid value | +| `{{ min }}` | The minimum number of valid elements | +| `{{ max }}` | The maximum number of valid elements | +| `{{ numElements }}` | The current invalid number of elements | + +### `exactMessage` + +type: `?string` default: `The {{ name }} value should contain exactly {{ min }} elements, {{ numElements }} elements given.` + +Message that will be shown when `min` and `max` options have the same value and the input value has a different number of elements. + +The following parameters are available: + +| Parameter | Description | +|---------------------|----------------------------------------| +| `{{ value }}` | The current invalid value | +| `{{ name }}` | Name of the invalid value | +| `{{ min }}` | The minimum number of valid elements | +| `{{ max }}` | The maximum number of valid elements | +| `{{ numElements }}` | The current invalid number of elements | + +## Changelog + +- `0.7.0` Created \ No newline at end of file From 43550c050267eaad166ba2536f1ac19f9b8f7b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Tue, 19 Mar 2024 17:20:45 +0000 Subject: [PATCH 6/6] docs: added Count to rule to list --- docs/03-rules.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/03-rules.md b/docs/03-rules.md index cc68cdd..c0625bc 100644 --- a/docs/03-rules.md +++ b/docs/03-rules.md @@ -9,6 +9,7 @@ ## Basic Rules +- [Count](03-rules_count.md) - [NotBlank](03-rules_not-blank.md) - [Type](03-rules_type.md)