From 490e2a132f3eb6d20462f0d4dcebfc0ec4f7611a Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Fri, 12 Apr 2024 13:32:41 +0500 Subject: [PATCH 01/17] Change type of `$skipOnEmpty` argument in rules' constructors from `mixed` to `bool|callable|null` --- CHANGELOG.md | 2 ++ src/Rule/Integer.php | 2 +- src/Rule/Number.php | 2 +- tests/Helper/SkipOnEmptyNormalizerTest.php | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bd5299fe..c96edde77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ (@arogachev) - Chg #679: Change type of `$rule` argument in `RuleHandlerInterface::validate()` from `object` to `RuleInterface` (@arogachev) +- Chg #660: Change type of `$skipOnEmpty` argument in rules' constructors from `mixed` to `bool|callable|null` + (@arogachev) ## 1.3.0 April 04, 2024 diff --git a/src/Rule/Integer.php b/src/Rule/Integer.php index bd13bbc06..e3d36344e 100644 --- a/src/Rule/Integer.php +++ b/src/Rule/Integer.php @@ -74,7 +74,7 @@ public function __construct( string $lessThanMinMessage = self::DEFAULT_LESS_THAN_MIN_MESSAGE, string $greaterThanMaxMessage = self::DEFAULT_GREATER_THAN_MAX_MESSAGE, string $pattern = '/^\s*[+-]?\d+\s*$/', - mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, bool $skipOnError = false, Closure|null $when = null, ) { diff --git a/src/Rule/Number.php b/src/Rule/Number.php index c4e2a3c24..e2e6596a5 100644 --- a/src/Rule/Number.php +++ b/src/Rule/Number.php @@ -74,7 +74,7 @@ public function __construct( string $lessThanMinMessage = '{Attribute} must be no less than {min}.', string $greaterThanMaxMessage = '{Attribute} must be no greater than {max}.', string $pattern = '/^\s*[-+]?\d*\.?\d+([eE][-+]?\d+)?\s*$/', - mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, bool $skipOnError = false, Closure|null $when = null, ) { diff --git a/tests/Helper/SkipOnEmptyNormalizerTest.php b/tests/Helper/SkipOnEmptyNormalizerTest.php index 42bd59082..354eefd1b 100644 --- a/tests/Helper/SkipOnEmptyNormalizerTest.php +++ b/tests/Helper/SkipOnEmptyNormalizerTest.php @@ -25,7 +25,7 @@ public function normalizeData(): array /** * @dataProvider normalizeData */ - public function testNormalize(mixed $skipOnEmpty, string $expectedClassName): void + public function testNormalize(bool|callable|null $skipOnEmpty, string $expectedClassName): void { $this->assertInstanceOf($expectedClassName, SkipOnEmptyNormalizer::normalize($skipOnEmpty)); } From de1aca982107e7e264335ae6ab2efb294b34f561 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Fri, 12 Apr 2024 14:57:48 +0500 Subject: [PATCH 02/17] Revert "Revert "Change type of `$escape` argument in `Error::getValuePath()` from `bool|string|null` to `string|null`"" This reverts commit c5a2b49187e1d8f5de26711b2884b0692833c370. --- CHANGELOG.md | 2 ++ UPGRADE.md | 3 +++ src/Error.php | 14 +++----------- tests/ErrorTest.php | 13 ++----------- 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bd5299fe..11611fef9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ (@arogachev) - Chg #679: Change type of `$rule` argument in `RuleHandlerInterface::validate()` from `object` to `RuleInterface` (@arogachev) +- Chg #613: Change type of `$escape` argument in `Error::getValuePath()` from `bool|string|null` to `string|null` + (@arogachev) ## 1.3.0 April 04, 2024 diff --git a/UPGRADE.md b/UPGRADE.md index 799648742..548c9bb55 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -27,3 +27,6 @@ for both A and B. public function validate(mixed $value, RuleInterface $rule, ValidationContext $context): Result; ``` + +* The type of `$escape` argument in `Yiisoft\Validator\Error::getValuePath()` changed from `bool|string|null` to + `string|null`. If you used `bool`, replace `false` with `null` and `true` with dot (`.`). diff --git a/src/Error.php b/src/Error.php index 1b960be03..e8dd692de 100644 --- a/src/Error.php +++ b/src/Error.php @@ -106,26 +106,18 @@ public function getParameters(): array * A getter for {@see $valuePath} property. Returns a sequence of keys determining where a value caused the * validation error is located within a nested structure. * - * @param bool|string|null $escape Symbol that will be escaped with a backslash char (`\`) in path elements. + * @param string|null $escape Symbol that will be escaped with a backslash char (`\`) in path elements. * When it's null path is returned without escaping. - * Boolean value is deprecated and will be removed in the next major release. Boolean value processed in the following way: - * - `false` as null, - * - `true` as dot (`.`). * * @return array A list of keys for nested structures or an empty array otherwise. - * * @psalm-return list */ - public function getValuePath(bool|string|null $escape = false): array + public function getValuePath(string|null $escape = null): array { - if ($escape === false || $escape === null) { + if ($escape === null) { return $this->valuePath; } - if ($escape === true) { - $escape = '.'; - } - if (mb_strlen($escape) !== 1) { throw new InvalidArgumentException('Escape symbol must be exactly one character.'); } diff --git a/tests/ErrorTest.php b/tests/ErrorTest.php index 649228d6d..6e2c2af0c 100644 --- a/tests/ErrorTest.php +++ b/tests/ErrorTest.php @@ -28,19 +28,10 @@ public function dataGetValuePath(): array ['user', 'the.data😎age'], '😎', ], - - // deprecated - 'true' => [ + 'dot' => [ ['user', 'data\.age'], ['user', 'data.age'], - true, - ], - - // deprecated - 'false' => [ - ['user', 'data.age'], - ['user', 'data.age'], - false, + '.', ], ]; } From a05b750c6a2f434f0048f95fbf9d7c5379f6d689 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 15 Apr 2024 14:46:18 +0500 Subject: [PATCH 03/17] Apply change for remaining rules --- src/Rule/AbstractCompare.php | 4 +++- src/Rule/AbstractNumber.php | 3 ++- src/Rule/AtLeast.php | 4 +++- src/Rule/BooleanValue.php | 3 ++- src/Rule/Callback.php | 4 +++- src/Rule/Composite.php | 9 +-------- src/Rule/Count.php | 3 ++- src/Rule/Date/BaseDate.php | 3 ++- src/Rule/Date/Date.php | 2 +- src/Rule/Date/DateTime.php | 2 +- src/Rule/Date/Time.php | 2 +- src/Rule/DateTime.php | 3 ++- src/Rule/Each.php | 3 ++- src/Rule/Email.php | 4 +++- src/Rule/Image/Image.php | 4 +++- src/Rule/In.php | 3 ++- src/Rule/Ip.php | 3 ++- src/Rule/Json.php | 3 ++- src/Rule/Length.php | 3 ++- src/Rule/Nested.php | 3 ++- src/Rule/OneOf.php | 3 ++- src/Rule/Regex.php | 3 ++- src/Rule/StopOnError.php | 3 ++- src/Rule/StringValue.php | 3 ++- src/Rule/Subset.php | 3 ++- src/Rule/Trait/SkipOnEmptyTrait.php | 9 ++++++++- src/Rule/TrueValue.php | 3 ++- src/Rule/Url.php | 4 +++- tests/Rule/CompositeTest.php | 18 +++++++++++++++--- 29 files changed, 79 insertions(+), 38 deletions(-) diff --git a/src/Rule/AbstractCompare.php b/src/Rule/AbstractCompare.php index e05997c72..7d2891c2a 100644 --- a/src/Rule/AbstractCompare.php +++ b/src/Rule/AbstractCompare.php @@ -151,7 +151,7 @@ public function __construct( private string|null $message = null, private string $type = CompareType::NUMBER, private string $operator = '==', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -169,6 +169,8 @@ public function __construct( throw new InvalidArgumentException($message); } + + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/AbstractNumber.php b/src/Rule/AbstractNumber.php index 4ce69b38a..629528984 100644 --- a/src/Rule/AbstractNumber.php +++ b/src/Rule/AbstractNumber.php @@ -104,7 +104,7 @@ public function __construct( private string $lessThanMinMessage, private string $greaterThanMaxMessage, string $pattern, - private mixed $skipOnEmpty, + bool|callable|null $skipOnEmpty, private bool $skipOnError, private Closure|null $when, ) { @@ -113,6 +113,7 @@ public function __construct( } $this->pattern = $pattern; + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/AtLeast.php b/src/Rule/AtLeast.php index 4997d19ef..56ea44fb9 100644 --- a/src/Rule/AtLeast.php +++ b/src/Rule/AtLeast.php @@ -65,13 +65,15 @@ public function __construct( private string $incorrectInputMessage = '{Attribute} must be an array or an object.', private string $message = 'At least {min, number} {min, plural, one{attribute} other{attributes}} from this ' . 'list must be filled: {attributes}.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null ) { if ($min > count($this->attributes)) { throw new InvalidArgumentException('$min must be no greater than amount of $attributes.'); } + + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/BooleanValue.php b/src/Rule/BooleanValue.php index e1be9fe2f..c7cf40e54 100644 --- a/src/Rule/BooleanValue.php +++ b/src/Rule/BooleanValue.php @@ -85,10 +85,11 @@ public function __construct( private bool $strict = false, private string $incorrectInputMessage = 'The allowed types are integer, float, string, boolean. {type} given.', private string $message = '{Attribute} must be either "{true}" or "{false}".', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Callback.php b/src/Rule/Callback.php index 26e945611..ca9267c38 100644 --- a/src/Rule/Callback.php +++ b/src/Rule/Callback.php @@ -58,7 +58,7 @@ final class Callback implements public function __construct( private mixed $callback = null, private string|null $method = null, - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -69,6 +69,8 @@ public function __construct( if ($this->callback !== null && $this->method !== null) { throw new InvalidArgumentException('"$callback" and "$method" are mutually exclusive.'); } + + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Composite.php b/src/Rule/Composite.php index e4f6be88c..e7dd1874c 100644 --- a/src/Rule/Composite.php +++ b/src/Rule/Composite.php @@ -92,13 +92,6 @@ class Composite implements */ protected iterable $rules = []; - /** - * @var bool|callable|null Whether to skip this rule group if the validated value is empty / not passed. See - * {@see SkipOnEmptyInterface}. - * @psalm-var SkipOnEmptyValue - */ - private mixed $skipOnEmpty = null; - /** * @var bool Whether to skip this rule group if any of the previous rules gave an error. See * {@see SkipOnErrorInterface}. @@ -133,8 +126,8 @@ public function __construct( bool $skipOnError = false, Closure|null $when = null, ) { - $this->rules = RulesNormalizer::normalizeList($rules); $this->skipOnEmpty = $skipOnEmpty; + $this->rules = RulesNormalizer::normalizeList($rules); $this->skipOnError = $skipOnError; $this->when = $when; } diff --git a/src/Rule/Count.php b/src/Rule/Count.php index e3dbc317f..0580d04ec 100644 --- a/src/Rule/Count.php +++ b/src/Rule/Count.php @@ -95,7 +95,7 @@ public function __construct( 'other{items}}.', string $notExactlyMessage = '{Attribute} must contain exactly {exactly, number} {exactly, plural, one{item} ' . 'other{items}}.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -107,6 +107,7 @@ public function __construct( $greaterThanMaxMessage, $notExactlyMessage ); + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Date/BaseDate.php b/src/Rule/Date/BaseDate.php index cbf324de6..6fe4933de 100644 --- a/src/Rule/Date/BaseDate.php +++ b/src/Rule/Date/BaseDate.php @@ -43,10 +43,11 @@ public function __construct( private ?string $incorrectInputMessage, private ?string $tooEarlyMessage, private ?string $tooLateMessage, - private mixed $skipOnEmpty, + bool|callable|null $skipOnEmpty, private bool $skipOnError, private Closure|null $when, ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getFormat(): ?string diff --git a/src/Rule/Date/Date.php b/src/Rule/Date/Date.php index 505aa49ed..5d09fb47b 100644 --- a/src/Rule/Date/Date.php +++ b/src/Rule/Date/Date.php @@ -130,7 +130,7 @@ public function __construct( ?string $incorrectInputMessage = null, ?string $tooEarlyMessage = null, ?string $tooLateMessage = null, - mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, bool $skipOnError = false, Closure|null $when = null, ) { diff --git a/src/Rule/Date/DateTime.php b/src/Rule/Date/DateTime.php index 773f55034..6d62f2e72 100644 --- a/src/Rule/Date/DateTime.php +++ b/src/Rule/Date/DateTime.php @@ -140,7 +140,7 @@ public function __construct( ?string $incorrectInputMessage = null, ?string $tooEarlyMessage = null, ?string $tooLateMessage = null, - mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, bool $skipOnError = false, Closure|null $when = null, ) { diff --git a/src/Rule/Date/Time.php b/src/Rule/Date/Time.php index ec86b870a..f5d4c3490 100644 --- a/src/Rule/Date/Time.php +++ b/src/Rule/Date/Time.php @@ -130,7 +130,7 @@ public function __construct( ?string $incorrectInputMessage = null, ?string $tooEarlyMessage = null, ?string $tooLateMessage = null, - mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, bool $skipOnError = false, Closure|null $when = null, ) { diff --git a/src/Rule/DateTime.php b/src/Rule/DateTime.php index 5aba6e146..56d85d4c6 100644 --- a/src/Rule/DateTime.php +++ b/src/Rule/DateTime.php @@ -90,7 +90,7 @@ public function __construct( string $format = 'Y-m-d', private string $incorrectInputMessage = '{Attribute} must be a date.', private string $message = '{Attribute} is not a valid date.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private ?Closure $when = null, ) { @@ -99,6 +99,7 @@ public function __construct( } $this->format = $format; + $this->skipOnEmpty = $skipOnEmpty; } /** diff --git a/src/Rule/Each.php b/src/Rule/Each.php index b9e709914..fadcc23f0 100644 --- a/src/Rule/Each.php +++ b/src/Rule/Each.php @@ -121,11 +121,12 @@ public function __construct( callable|iterable|object|string $rules = [], private string $incorrectInputMessage = '{Attribute} must be array or iterable.', private string $incorrectInputKeyMessage = 'Every iterable key must have an integer or a string type.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { $this->rules = RulesNormalizer::normalize($rules); + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Email.php b/src/Rule/Email.php index ebb187496..961006e7a 100644 --- a/src/Rule/Email.php +++ b/src/Rule/Email.php @@ -96,7 +96,7 @@ public function __construct( private bool $enableIdn = false, private string $incorrectInputMessage = '{Attribute} must be a string.', private string $message = '{Attribute} is not a valid email address.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -124,6 +124,8 @@ public function __construct( throw new RuntimeException('In order to use IDN validation intl extension must be installed and enabled.'); // @codeCoverageIgnoreEnd } + + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Image/Image.php b/src/Rule/Image/Image.php index 476b4e354..4bf532fc0 100644 --- a/src/Rule/Image/Image.php +++ b/src/Rule/Image/Image.php @@ -130,7 +130,7 @@ public function __construct( private string $tooLargeWidthMessage = 'The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.', private string $tooLargeHeightMessage = 'The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.', private string $invalidAspectRatioMessage = 'The aspect ratio must be {aspectRatioWidth, number}:{aspectRatioHeight, number} with margin {aspectRatioMargin, number}%.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -141,6 +141,8 @@ public function __construct( if ($this->height !== null && ($this->minHeight !== null || $this->maxHeight !== null)) { throw new InvalidArgumentException('Exact width and min / max height can\'t be specified together.'); } + + $this->skipOnEmpty = $skipOnEmpty; } public function getWidth(): ?int diff --git a/src/Rule/In.php b/src/Rule/In.php index d841a45e6..c275c2787 100644 --- a/src/Rule/In.php +++ b/src/Rule/In.php @@ -74,10 +74,11 @@ public function __construct( private bool $strict = false, private bool $not = false, private string $message = '{Attribute} is not in the list of acceptable values.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Ip.php b/src/Rule/Ip.php index 2a66f5738..b738cc748 100644 --- a/src/Rule/Ip.php +++ b/src/Rule/Ip.php @@ -193,7 +193,7 @@ public function __construct( private string $hasSubnetMessage = '{Attribute} must not be a subnet.', private string $notInRangeMessage = '{Attribute} is not in the allowed range.', private array $ranges = [], - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -217,6 +217,7 @@ public function __construct( } $this->ranges = $this->prepareRanges($ranges); + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Json.php b/src/Rule/Json.php index 10c68f321..96024b247 100644 --- a/src/Rule/Json.php +++ b/src/Rule/Json.php @@ -58,10 +58,11 @@ final class Json implements DumpedRuleInterface, SkipOnErrorInterface, WhenInter public function __construct( private string $incorrectInputMessage = '{Attribute} must be a string.', private string $message = '{Attribute} is not JSON.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Length.php b/src/Rule/Length.php index 7c7e49f19..70385b676 100644 --- a/src/Rule/Length.php +++ b/src/Rule/Length.php @@ -97,7 +97,7 @@ public function __construct( string $notExactlyMessage = '{Attribute} must contain exactly {exactly, number} {exactly, plural, ' . 'one{character} other{characters}}.', private string $encoding = 'UTF-8', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null ) { @@ -109,6 +109,7 @@ public function __construct( $greaterThanMaxMessage, $notExactlyMessage ); + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Nested.php b/src/Rule/Nested.php index 20fcf93d1..075c9bd66 100644 --- a/src/Rule/Nested.php +++ b/src/Rule/Nested.php @@ -221,10 +221,11 @@ public function __construct( private string $noPropertyPathMessage = 'Property "{path}" is not found.', private bool $handleEachShortcut = true, private bool $propagateOptions = false, - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { + $this->skipOnEmpty = $skipOnEmpty; $this->prepareRules($rules); } diff --git a/src/Rule/OneOf.php b/src/Rule/OneOf.php index a48fa7707..bfc8c8a20 100644 --- a/src/Rule/OneOf.php +++ b/src/Rule/OneOf.php @@ -58,10 +58,11 @@ public function __construct( private array $attributes, private string $incorrectInputMessage = '{Attribute} must be an array or an object.', private string $message = 'Exactly 1 attribute from this list must be filled: {attributes}.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Regex.php b/src/Rule/Regex.php index feb4977cf..43ae97eec 100644 --- a/src/Rule/Regex.php +++ b/src/Rule/Regex.php @@ -71,7 +71,7 @@ public function __construct( private bool $not = false, private string $incorrectInputMessage = '{Attribute} must be a string.', private string $message = '{Attribute} is invalid.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -80,6 +80,7 @@ public function __construct( } $this->pattern = $pattern; + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/StopOnError.php b/src/Rule/StopOnError.php index 09df93ca5..4f2a1a3d6 100644 --- a/src/Rule/StopOnError.php +++ b/src/Rule/StopOnError.php @@ -83,11 +83,12 @@ final class StopOnError implements */ public function __construct( iterable $rules, - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { $this->rules = RulesNormalizer::normalizeList($rules); + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/StringValue.php b/src/Rule/StringValue.php index 7f65fe6cb..f2c5e26d9 100644 --- a/src/Rule/StringValue.php +++ b/src/Rule/StringValue.php @@ -55,10 +55,11 @@ final class StringValue implements */ public function __construct( private string $message = '{Attribute} must be a string.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Subset.php b/src/Rule/Subset.php index deb97e7c3..59fdeae26 100644 --- a/src/Rule/Subset.php +++ b/src/Rule/Subset.php @@ -76,10 +76,11 @@ public function __construct( private bool $strict = false, private string $incorrectInputMessage = '{Attribute} must be iterable.', private string $message = '{Attribute} is not a subset of acceptable values.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Trait/SkipOnEmptyTrait.php b/src/Rule/Trait/SkipOnEmptyTrait.php index a7239bbfb..8f8fff92e 100644 --- a/src/Rule/Trait/SkipOnEmptyTrait.php +++ b/src/Rule/Trait/SkipOnEmptyTrait.php @@ -16,7 +16,7 @@ * ```php * public function __construct( * // ... - * private mixed $skipOnEmpty = null, + * bool|callable|null $skipOnEmpty = null, * // ... * ) { * } @@ -26,6 +26,13 @@ */ trait SkipOnEmptyTrait { + /** + * @var bool|callable|null $skipOnEmpty Whether to skip this rule if the validated value is empty / not passed. + * See {@see SkipOnEmptyInterface}. + * @psalm-var SkipOnEmptyValue $skipOnEmpty + */ + private mixed $skipOnEmpty; + /** * An immutable setter to change `$skipOnEmpty` property. * diff --git a/src/Rule/TrueValue.php b/src/Rule/TrueValue.php index 277afc576..1ab013d49 100644 --- a/src/Rule/TrueValue.php +++ b/src/Rule/TrueValue.php @@ -80,10 +80,11 @@ public function __construct( private bool $strict = false, private string $incorrectInputMessage = 'The allowed types are integer, float, string, boolean. {type} given.', private string $message = '{Attribute} must be "{true}".', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/src/Rule/Url.php b/src/Rule/Url.php index 71ce8be86..c64230b00 100644 --- a/src/Rule/Url.php +++ b/src/Rule/Url.php @@ -83,7 +83,7 @@ public function __construct( private bool $enableIdn = false, private string $incorrectInputMessage = '{Attribute} must be a string.', private string $message = '{Attribute} is not a valid URL.', - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, private bool $skipOnError = false, private Closure|null $when = null, ) { @@ -103,6 +103,8 @@ public function __construct( throw new RuntimeException('In order to use IDN validation intl extension must be installed and enabled.'); // @codeCoverageIgnoreEnd } + + $this->skipOnEmpty = $skipOnEmpty; } public function getName(): string diff --git a/tests/Rule/CompositeTest.php b/tests/Rule/CompositeTest.php index 71bf3e0c0..856575e93 100644 --- a/tests/Rule/CompositeTest.php +++ b/tests/Rule/CompositeTest.php @@ -4,6 +4,7 @@ namespace Yiisoft\Validator\Tests\Rule; +use Closure; use Yiisoft\Validator\Result; use Yiisoft\Validator\Rule\Callback; use Yiisoft\Validator\Rule\Composite; @@ -219,8 +220,14 @@ public function dataValidationPassed(): array 20, [ new class () extends Composite { - public function __construct() + public function __construct( + iterable $rules = [], + bool|callable|null $skipOnEmpty = null, + bool $skipOnError = false, + Closure|null $when = null, + ) { + parent::__construct($rules, $skipOnEmpty, $skipOnError, $when); } }, ], @@ -316,9 +323,14 @@ public function dataValidationFailed(): array null, [ new class () extends Composite { - public function __construct() + public function __construct( + iterable $rules = [], + bool|callable|null $skipOnEmpty = null, + bool $skipOnError = false, + Closure|null $when = null, + ) { - $this->rules = [new Required()]; + parent::__construct([new Required()], $skipOnEmpty, $skipOnError, $when); } }, ], From da3e51a8414cc58678b5d85fb0fecb57637bdfd0 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 15 Apr 2024 09:49:45 +0000 Subject: [PATCH 04/17] Apply fixes from StyleCI --- tests/Rule/CompositeTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/Rule/CompositeTest.php b/tests/Rule/CompositeTest.php index 856575e93..bf737c740 100644 --- a/tests/Rule/CompositeTest.php +++ b/tests/Rule/CompositeTest.php @@ -225,8 +225,7 @@ public function __construct( bool|callable|null $skipOnEmpty = null, bool $skipOnError = false, Closure|null $when = null, - ) - { + ) { parent::__construct($rules, $skipOnEmpty, $skipOnError, $when); } }, @@ -328,8 +327,7 @@ public function __construct( bool|callable|null $skipOnEmpty = null, bool $skipOnError = false, Closure|null $when = null, - ) - { + ) { parent::__construct([new Required()], $skipOnEmpty, $skipOnError, $when); } }, From 52dc5a5011ff6c6fc96190e01cae6e7ddb7e39ca Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 29 Apr 2024 20:25:01 +0500 Subject: [PATCH 05/17] Update src/Rule/Trait/SkipOnEmptyTrait.php Co-authored-by: Sergei Predvoditelev --- src/Rule/Trait/SkipOnEmptyTrait.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Rule/Trait/SkipOnEmptyTrait.php b/src/Rule/Trait/SkipOnEmptyTrait.php index 8f8fff92e..c7a54a0c2 100644 --- a/src/Rule/Trait/SkipOnEmptyTrait.php +++ b/src/Rule/Trait/SkipOnEmptyTrait.php @@ -19,6 +19,7 @@ * bool|callable|null $skipOnEmpty = null, * // ... * ) { + $this->skipOnEmpty = $skipOnEmpty; * } * ``` * From b5fdcaa77ee0646fd788bee020c86d1e05951dc7 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 29 Apr 2024 20:25:35 +0500 Subject: [PATCH 06/17] Fix PHPDoc [skip ci] --- src/Rule/Trait/SkipOnEmptyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rule/Trait/SkipOnEmptyTrait.php b/src/Rule/Trait/SkipOnEmptyTrait.php index c7a54a0c2..c64fc1589 100644 --- a/src/Rule/Trait/SkipOnEmptyTrait.php +++ b/src/Rule/Trait/SkipOnEmptyTrait.php @@ -19,7 +19,7 @@ * bool|callable|null $skipOnEmpty = null, * // ... * ) { - $this->skipOnEmpty = $skipOnEmpty; + * $this->skipOnEmpty = $skipOnEmpty; * } * ``` * From bf18566a29be15f7c0446d19ac89d3a10f76a781 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 29 Apr 2024 20:25:51 +0500 Subject: [PATCH 07/17] Update src/Rule/Trait/SkipOnEmptyTrait.php Co-authored-by: Sergei Predvoditelev --- src/Rule/Trait/SkipOnEmptyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rule/Trait/SkipOnEmptyTrait.php b/src/Rule/Trait/SkipOnEmptyTrait.php index c64fc1589..a32f9bd1e 100644 --- a/src/Rule/Trait/SkipOnEmptyTrait.php +++ b/src/Rule/Trait/SkipOnEmptyTrait.php @@ -32,7 +32,7 @@ trait SkipOnEmptyTrait * See {@see SkipOnEmptyInterface}. * @psalm-var SkipOnEmptyValue $skipOnEmpty */ - private mixed $skipOnEmpty; + private mixed $skipOnEmpty = null; /** * An immutable setter to change `$skipOnEmpty` property. From 71d11eae29915070c475c27fea79dc07583b38d4 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 29 Apr 2024 20:36:42 +0500 Subject: [PATCH 08/17] More specific type [skip ci] --- tests/Rule/CompositeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Rule/CompositeTest.php b/tests/Rule/CompositeTest.php index bf737c740..6f3b6f325 100644 --- a/tests/Rule/CompositeTest.php +++ b/tests/Rule/CompositeTest.php @@ -160,7 +160,7 @@ public function dataOptions(): array ], 'inheritance' => [ new class () extends Composite { - public function getRules(): iterable + public function getRules(): array { return [ new Required(), From 90648ba41955d7938ad353e6896ad88fc44e78f1 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 29 Apr 2024 20:44:51 +0500 Subject: [PATCH 09/17] More review fixes --- tests/Rule/CompositeTest.php | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tests/Rule/CompositeTest.php b/tests/Rule/CompositeTest.php index 6f3b6f325..7f0ca9b7b 100644 --- a/tests/Rule/CompositeTest.php +++ b/tests/Rule/CompositeTest.php @@ -220,13 +220,8 @@ public function dataValidationPassed(): array 20, [ new class () extends Composite { - public function __construct( - iterable $rules = [], - bool|callable|null $skipOnEmpty = null, - bool $skipOnError = false, - Closure|null $when = null, - ) { - parent::__construct($rules, $skipOnEmpty, $skipOnError, $when); + public function __construct() + { } }, ], @@ -318,17 +313,13 @@ public function dataValidationFailed(): array ], ['' => ['Custom error']], ], - 'override constructor' => [ + 'override rules' => [ null, [ new class () extends Composite { - public function __construct( - iterable $rules = [], - bool|callable|null $skipOnEmpty = null, - bool $skipOnError = false, - Closure|null $when = null, - ) { - parent::__construct([new Required()], $skipOnEmpty, $skipOnError, $when); + public function getRules(): array + { + return [new Required()]; } }, ], From 26057c820deda6cf0266c34997dd1d8457ae0b2a Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 29 Apr 2024 15:45:04 +0000 Subject: [PATCH 10/17] Apply fixes from StyleCI --- tests/Rule/CompositeTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Rule/CompositeTest.php b/tests/Rule/CompositeTest.php index 7f0ca9b7b..83235d98e 100644 --- a/tests/Rule/CompositeTest.php +++ b/tests/Rule/CompositeTest.php @@ -4,7 +4,6 @@ namespace Yiisoft\Validator\Tests\Rule; -use Closure; use Yiisoft\Validator\Result; use Yiisoft\Validator\Rule\Callback; use Yiisoft\Validator\Rule\Composite; From cbc1958b4ec1d582019cc963b1763e5ec887cf67 Mon Sep 17 00:00:00 2001 From: Alexey Rogachev Date: Mon, 29 Apr 2024 20:59:58 +0500 Subject: [PATCH 11/17] Update upgrade instructions [review fix] --- UPGRADE.md | 33 +++++++++++++++++++++++++++++ src/Rule/Trait/SkipOnEmptyTrait.php | 3 ++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/UPGRADE.md b/UPGRADE.md index 548c9bb55..a4d37226b 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -30,3 +30,36 @@ for both A and B. * The type of `$escape` argument in `Yiisoft\Validator\Error::getValuePath()` changed from `bool|string|null` to `string|null`. If you used `bool`, replace `false` with `null` and `true` with dot (`.`). + +* For custom rules using `Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait`, apply the following changes for `$skipOnEmpty` + property in the constructor: + + - Turn in it into argument (remove `private` visibility). + - Change type from `mixed` to more specific `bool|callable|null` + - Add manual initialization of property value. + + For example: + + ```php + public function __construct( + // ... + private mixed $skipOnEmpty = null, + // ... + ) + { + // ... + } + ``` + + Change to: + + ```php + public function __construct( + // ... + private mixed $skipOnEmpty = null, + // ... + ) + { + $this->skipOnEmpty = $this->skipOnEmpty; + } + ``` diff --git a/src/Rule/Trait/SkipOnEmptyTrait.php b/src/Rule/Trait/SkipOnEmptyTrait.php index a32f9bd1e..174f9834b 100644 --- a/src/Rule/Trait/SkipOnEmptyTrait.php +++ b/src/Rule/Trait/SkipOnEmptyTrait.php @@ -18,7 +18,8 @@ * // ... * bool|callable|null $skipOnEmpty = null, * // ... - * ) { + * ) + * { * $this->skipOnEmpty = $skipOnEmpty; * } * ``` From 90e928ab61fdaf4af27e61c44e5d0415f4cad489 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 30 Apr 2024 16:10:36 +0300 Subject: [PATCH 12/17] Update UPGRADE.md --- UPGRADE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE.md b/UPGRADE.md index a4d37226b..ddfa663a3 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -56,7 +56,7 @@ for both A and B. ```php public function __construct( // ... - private mixed $skipOnEmpty = null, + bool|callable|null $skipOnEmpty = null, // ... ) { From aa68b856bf8907fe623585a58b1c9f226753779d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 30 Apr 2024 16:10:41 +0300 Subject: [PATCH 13/17] Update UPGRADE.md --- UPGRADE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index ddfa663a3..ffd491898 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -58,8 +58,7 @@ for both A and B. // ... bool|callable|null $skipOnEmpty = null, // ... - ) - { + ) { $this->skipOnEmpty = $this->skipOnEmpty; } ``` From 6e0a60358f68f1d44c13f35c124a667b73997b15 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 30 Apr 2024 16:10:46 +0300 Subject: [PATCH 14/17] Update UPGRADE.md --- UPGRADE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index ffd491898..b29d1d163 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -45,8 +45,7 @@ for both A and B. // ... private mixed $skipOnEmpty = null, // ... - ) - { + ) { // ... } ``` From 6d89182a3dd478b934b7dbd66914ba6baa9e1cdc Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 30 Apr 2024 16:10:52 +0300 Subject: [PATCH 15/17] Update src/Rule/Trait/SkipOnEmptyTrait.php --- src/Rule/Trait/SkipOnEmptyTrait.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Rule/Trait/SkipOnEmptyTrait.php b/src/Rule/Trait/SkipOnEmptyTrait.php index 174f9834b..a32f9bd1e 100644 --- a/src/Rule/Trait/SkipOnEmptyTrait.php +++ b/src/Rule/Trait/SkipOnEmptyTrait.php @@ -18,8 +18,7 @@ * // ... * bool|callable|null $skipOnEmpty = null, * // ... - * ) - * { + * ) { * $this->skipOnEmpty = $skipOnEmpty; * } * ``` From ca1aa71dd669e6d3a7769d4006d155b4bc9e1d00 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 30 Apr 2024 16:10:58 +0300 Subject: [PATCH 16/17] Update src/Rule/Trait/SkipOnEmptyTrait.php --- src/Rule/Trait/SkipOnEmptyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rule/Trait/SkipOnEmptyTrait.php b/src/Rule/Trait/SkipOnEmptyTrait.php index a32f9bd1e..989b74e51 100644 --- a/src/Rule/Trait/SkipOnEmptyTrait.php +++ b/src/Rule/Trait/SkipOnEmptyTrait.php @@ -29,7 +29,7 @@ trait SkipOnEmptyTrait { /** * @var bool|callable|null $skipOnEmpty Whether to skip this rule if the validated value is empty / not passed. - * See {@see SkipOnEmptyInterface}. + * See {@see SkipOnEmptyInterface}. * @psalm-var SkipOnEmptyValue $skipOnEmpty */ private mixed $skipOnEmpty = null; From a6352a491f90a6b6d99553d5c4c3b856d108bbcb Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 30 Apr 2024 16:11:51 +0300 Subject: [PATCH 17/17] Update UPGRADE.md --- UPGRADE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE.md b/UPGRADE.md index b29d1d163..f41042700 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -58,6 +58,6 @@ for both A and B. bool|callable|null $skipOnEmpty = null, // ... ) { - $this->skipOnEmpty = $this->skipOnEmpty; + $this->skipOnEmpty = $skipOnEmpty; } ```