From 7cec22752002871d39cab0c9828a8cb0c8745b3d Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Mon, 9 Dec 2024 15:07:28 +0100 Subject: [PATCH] Create "Attribute" rule With this change, any rule can be used as a PHP attribute. I have wanted to implement this feature for a while, as it allows you to bind the validation to a specific property and just validate the object afterwards. --- bin/create-mixin | 5 +- docs/02-feature-guide.md | 29 ++++--- docs/09-list-of-rules-by-category.md | 3 + docs/rules/Attributes.md | 85 +++++++++++++++++++ docs/rules/Date.md | 2 +- docs/rules/NullOr.md | 1 + docs/rules/ObjectType.md | 1 + docs/rules/Property.md | 1 + docs/rules/PropertyExists.md | 1 + docs/rules/PropertyOptional.md | 1 + library/Mixins/ChainedNullOr.php | 2 + library/Mixins/ChainedValidator.php | 2 + library/Mixins/StaticNullOr.php | 2 + library/Mixins/StaticValidator.php | 2 + library/Rules/AllOf.php | 2 + library/Rules/Alnum.php | 2 + library/Rules/Alpha.php | 2 + library/Rules/AlwaysInvalid.php | 2 + library/Rules/AlwaysValid.php | 2 + library/Rules/AnyOf.php | 2 + library/Rules/ArrayType.php | 2 + library/Rules/ArrayVal.php | 2 + library/Rules/Attributes.php | 54 ++++++++++++ library/Rules/Base.php | 2 + library/Rules/Base64.php | 2 + library/Rules/Between.php | 2 + library/Rules/BetweenExclusive.php | 2 + library/Rules/BoolType.php | 2 + library/Rules/BoolVal.php | 2 + library/Rules/Bsn.php | 2 + library/Rules/Call.php | 2 + library/Rules/CallableType.php | 2 + library/Rules/Callback.php | 2 + library/Rules/Charset.php | 2 + library/Rules/Cnh.php | 2 + library/Rules/Cnpj.php | 2 + library/Rules/Consecutive.php | 2 + library/Rules/Consonant.php | 2 + library/Rules/Contains.php | 2 + library/Rules/ContainsAny.php | 2 + library/Rules/Control.php | 2 + library/Rules/Countable.php | 2 + library/Rules/CountryCode.php | 2 + library/Rules/Cpf.php | 2 + library/Rules/CreditCard.php | 2 + library/Rules/CurrencyCode.php | 2 + library/Rules/Date.php | 2 + library/Rules/DateTime.php | 2 + library/Rules/DateTimeDiff.php | 2 + library/Rules/Decimal.php | 2 + library/Rules/Digit.php | 2 + library/Rules/Directory.php | 2 + library/Rules/Domain.php | 2 + library/Rules/Each.php | 2 + library/Rules/Email.php | 2 + library/Rules/EndsWith.php | 2 + library/Rules/Equals.php | 2 + library/Rules/Equivalent.php | 2 + library/Rules/Even.php | 2 + library/Rules/Executable.php | 2 + library/Rules/Exists.php | 2 + library/Rules/Extension.php | 2 + library/Rules/Factor.php | 2 + library/Rules/FalseVal.php | 2 + library/Rules/Fibonacci.php | 2 + library/Rules/File.php | 2 + library/Rules/FilterVar.php | 2 + library/Rules/Finite.php | 2 + library/Rules/FloatType.php | 2 + library/Rules/FloatVal.php | 2 + library/Rules/Graph.php | 2 + library/Rules/GreaterThan.php | 2 + library/Rules/GreaterThanOrEqual.php | 2 + library/Rules/Hetu.php | 2 + library/Rules/HexRgbColor.php | 2 + library/Rules/Iban.php | 2 + library/Rules/Identical.php | 2 + library/Rules/Image.php | 2 + library/Rules/Imei.php | 2 + library/Rules/In.php | 2 + library/Rules/Infinite.php | 2 + library/Rules/Instance.php | 2 + library/Rules/IntType.php | 2 + library/Rules/IntVal.php | 2 + library/Rules/Ip.php | 2 + library/Rules/Isbn.php | 2 + library/Rules/IterableType.php | 2 + library/Rules/IterableVal.php | 2 + library/Rules/Json.php | 2 + library/Rules/Key.php | 2 + library/Rules/KeyExists.php | 2 + library/Rules/KeyOptional.php | 2 + library/Rules/KeySet.php | 2 + library/Rules/LanguageCode.php | 2 + library/Rules/Lazy.php | 2 + library/Rules/LeapDate.php | 2 + library/Rules/LeapYear.php | 2 + library/Rules/Length.php | 2 + library/Rules/LessThan.php | 2 + library/Rules/LessThanOrEqual.php | 2 + library/Rules/Lowercase.php | 2 + library/Rules/Luhn.php | 2 + library/Rules/MacAddress.php | 2 + library/Rules/Max.php | 2 + library/Rules/Mimetype.php | 2 + library/Rules/Min.php | 2 + library/Rules/Multiple.php | 2 + library/Rules/Negative.php | 2 + library/Rules/NfeAccessKey.php | 2 + library/Rules/Nif.php | 2 + library/Rules/Nip.php | 2 + library/Rules/No.php | 2 + library/Rules/NoWhitespace.php | 2 + library/Rules/NoneOf.php | 2 + library/Rules/Not.php | 2 + library/Rules/NotBlank.php | 2 + library/Rules/NotEmoji.php | 2 + library/Rules/NotEmpty.php | 2 + library/Rules/NotUndef.php | 2 + library/Rules/NullOr.php | 2 + library/Rules/NullType.php | 2 + library/Rules/Number.php | 2 + library/Rules/NumericVal.php | 2 + library/Rules/ObjectType.php | 2 + library/Rules/Odd.php | 2 + library/Rules/OneOf.php | 2 + library/Rules/PerfectSquare.php | 2 + library/Rules/Pesel.php | 2 + library/Rules/Phone.php | 2 + library/Rules/PhpLabel.php | 2 + library/Rules/Pis.php | 2 + library/Rules/PolishIdCard.php | 2 + library/Rules/PortugueseNif.php | 2 + library/Rules/Positive.php | 2 + library/Rules/PostalCode.php | 2 + library/Rules/PrimeNumber.php | 2 + library/Rules/Printable.php | 2 + library/Rules/Property.php | 2 + library/Rules/PropertyExists.php | 2 + library/Rules/PropertyOptional.php | 2 + library/Rules/PublicDomainSuffix.php | 2 + library/Rules/Punct.php | 2 + library/Rules/Readable.php | 2 + library/Rules/Regex.php | 2 + library/Rules/ResourceType.php | 2 + library/Rules/Roman.php | 2 + library/Rules/ScalarVal.php | 2 + library/Rules/Size.php | 2 + library/Rules/Slug.php | 2 + library/Rules/Sorted.php | 2 + library/Rules/Space.php | 2 + library/Rules/StartsWith.php | 2 + library/Rules/StringType.php | 2 + library/Rules/StringVal.php | 2 + library/Rules/SubdivisionCode.php | 2 + library/Rules/Subset.php | 2 + library/Rules/SymbolicLink.php | 2 + library/Rules/Time.php | 2 + library/Rules/Tld.php | 2 + library/Rules/TrueVal.php | 2 + library/Rules/UndefOr.php | 2 + library/Rules/Unique.php | 2 + library/Rules/Uploaded.php | 2 + library/Rules/Uppercase.php | 2 + library/Rules/Url.php | 2 + library/Rules/Uuid.php | 2 + library/Rules/Version.php | 2 + library/Rules/VideoUrl.php | 2 + library/Rules/Vowel.php | 2 + library/Rules/When.php | 2 + library/Rules/Writable.php | 2 + library/Rules/Xdigit.php | 2 + library/Rules/Yes.php | 2 + phpcs.xml.dist | 8 ++ tests/fixtures/data-provider.php | 29 +++++-- ...butes.phpt => assert-with-properties.phpt} | 0 tests/integration/rules/attributes.phpt | 78 +++++++++++++++++ tests/library/Stubs/WithAttributes.php | 34 ++++++++ tests/library/TestCase.php | 10 +++ tests/unit/Rules/AttributesTest.php | 79 +++++++++++++++++ 180 files changed, 720 insertions(+), 25 deletions(-) create mode 100644 docs/rules/Attributes.md create mode 100644 library/Rules/Attributes.php rename tests/integration/{assert-with-attributes.phpt => assert-with-properties.phpt} (100%) create mode 100644 tests/integration/rules/attributes.phpt create mode 100644 tests/library/Stubs/WithAttributes.php create mode 100644 tests/unit/Rules/AttributesTest.php diff --git a/bin/create-mixin b/bin/create-mixin index ad0d80c8b..51e87b4fc 100755 --- a/bin/create-mixin +++ b/bin/create-mixin @@ -170,6 +170,7 @@ function overwriteFile(string $content, string $basename): void 'Property', 'PropertyExists', 'PropertyOptional', + 'Attributes', ]; $mixins = [ @@ -177,10 +178,10 @@ function overwriteFile(string $content, string $basename): void ['Length', 'length', $numberRelatedRules, []], ['Max', 'max', $numberRelatedRules, []], ['Min', 'min', $numberRelatedRules, []], - ['Not', 'not', [], ['Not', 'NotEmpty', 'NotBlank', 'NotEmoji', 'NotUndef', 'NotOptional', 'NullOr', 'UndefOr', 'Optional']], + ['Not', 'not', [], ['Not', 'NotEmpty', 'NotBlank', 'NotEmoji', 'NotUndef', 'NotOptional', 'NullOr', 'UndefOr', 'Optional', 'Attributes']], ['NullOr', 'nullOr', [], ['Nullable', 'NullOr', 'Optional', 'NotOptional', 'NotUndef', 'UndefOr']], ['Property', 'property', [], $structureRelatedRules], - ['UndefOr', 'undefOr', [], ['Nullable', 'NullOr', 'NotOptional', 'NotUndef', 'Optional', 'UndefOr']], + ['UndefOr', 'undefOr', [], ['Nullable', 'NullOr', 'NotOptional', 'NotUndef', 'Optional', 'UndefOr', 'Attributes']], ['Validator', null, [], []], ]; diff --git a/docs/02-feature-guide.md b/docs/02-feature-guide.md index 9f133e958..3758694ea 100644 --- a/docs/02-feature-guide.md +++ b/docs/02-feature-guide.md @@ -29,6 +29,22 @@ The `assert()` method throws an exception when validation fails. You can handle v::intType()->positive()->assert($input); ``` +## Smart validation + +Respect\Validation offers over 150 rules, many of which are designed to address common scenarios. Here’s a quick guide to some specific use cases and the rules that make validation straightforward. + +* Using rules as **PHP Attributes**: [Attributes](rules/Attributes.md). +* Validating **Arrays**: [Key](rules/Key.md), [KeyOptional](rules/KeyOptional.md), [KeyExists](rules/KeyExists.md). +* Validating **Array structures**: [KeySet](rules/KeySet.md). +* Validating **Object properties**: [Property](rules/Property.md), [PropertyOptional](rules/PropertyOptional.md), [PropertyExists](rules/PropertyExists.md). +* Using **Conditional validation**: [NullOr](rules/NullOr.md), [UndefOr](rules/UndefOr.md), [When](rules/When.md). +* Using **Grouped validation**: [AllOf](rules/AllOf.md), [AnyOf](rules/AnyOf.md), [NoneOf](rules/NoneOf.md), [OneOf](rules/OneOf.md) +* Validating **Each** value in the input: [Each](rules/Each.md). +* Validating the **Length** of the input: [Length](rules/Length.md). +* Validating the **Maximum** value in the input: [Max](rules/Max.md). +* Validating the **Minimum** value in the input: [Min](rules/Min.md). +* Handling **Special cases**: [Lazy](rules/Lazy.md), [Consecutive](rules/Consecutive.md), [Call](rules/Call.md). + ### Custom templates Define your own error message when the validation fails: @@ -101,16 +117,3 @@ v::dateTime('Y-m-d') ->setName('Age') ->assert($input); ``` - -## Smart input handling - -Respect\Validation offers over 150 rules, many of which are designed to address common input handling scenarios. Here’s a quick guide to some specific use cases and the rules that make validation straightforward. - -* Validating arrays: [Key](rules/Key.md), [KeyOptional](rules/KeyOptional.md), and [KeyExists](rules/KeyExists.md). -* Validating array structures: [KeySet](rules/KeySet.md). -* Validating object properties: [Property](rules/Property.md), [PropertyOptional](rules/PropertyOptional.md), and [PropertyExists](rules/PropertyExists.md). -* Validating only when input is not `null`: [NullOr](rules/NullOr.md). -* Validating only when input is not `null` or an empty string: [UndefOr](rules/UndefOr.md). -* Validating the length of the input: [Length](rules/Length.md). -* Validating the maximum value of the input: [Max](rules/Max.md). -* Validating the minimum value of the input: [Min](rules/Min.md). diff --git a/docs/09-list-of-rules-by-category.md b/docs/09-list-of-rules-by-category.md index 50f457c40..0e2a6aeab 100644 --- a/docs/09-list-of-rules-by-category.md +++ b/docs/09-list-of-rules-by-category.md @@ -203,6 +203,7 @@ ## Objects +- [Attributes](rules/Attributes.md) - [Instance](rules/Instance.md) - [ObjectType](rules/ObjectType.md) - [Property](rules/Property.md) @@ -248,6 +249,7 @@ ## Structures +- [Attributes](rules/Attributes.md) - [Key](rules/Key.md) - [KeyExists](rules/KeyExists.md) - [KeyOptional](rules/KeyOptional.md) @@ -297,6 +299,7 @@ - [AnyOf](rules/AnyOf.md) - [ArrayType](rules/ArrayType.md) - [ArrayVal](rules/ArrayVal.md) +- [Attributes](rules/Attributes.md) - [Base](rules/Base.md) - [Base64](rules/Base64.md) - [Between](rules/Between.md) diff --git a/docs/rules/Attributes.md b/docs/rules/Attributes.md new file mode 100644 index 000000000..13da19838 --- /dev/null +++ b/docs/rules/Attributes.md @@ -0,0 +1,85 @@ +# Attributes + +- `Attributes()` + +Validates the PHP attributes defined in the properties of the input. + +Example of object: + +```php +use Respect\Validation\Rules; + +final class Person +{ + public function __construct( + #[Rules\NotEmpty] + public readonly string $name, + #[Rules\Email] + public readonly string $email, + #[Rules\Date('Y-m-d')] + #[Rules\DateTimeDiff('years', new Rules\LessThanOrEqual(25))] + public readonly string $birthdate, + #[Rules\Phone] + public readonly ?string $phone + ) { + } +} +``` + +Here is how you can validate the attributes of the object: + +```php +v::attributes()->assert(new Person('John Doe', 'john.doe@gmail.com', '2020-06-23')); +// No exception + +v::attributes()->assert(new Person('John Doe', 'john.doe@gmail.com', '2020-06-23', '+31 20 624 1111')); +// No exception + +v::attributes()->assert(new Person('', 'john.doe@gmail.com', '2020-06-23', '+1234567890')); +// Message: name must not be empty + +v::attributes()->assert(new Person('John Doe', 'not an email', '2020-06-23', '+1234567890')); +// Message: email must be a valid email address + +v::attributes()->assert(new Person('John Doe', 'john.doe@gmail.com', 'not a date', '+1234567890')); +// Message: birthdate must be a valid date in the format "2005-12-30" + +v::attributes()->assert(new Person('John Doe', 'john.doe@gmail.com', '2020-06-23', 'not a phone number')); +// Message: phone must be a valid telephone number or must be null + +v::attributes()->assert(new Person('', 'not an email', 'not a date', 'not a phone number')); +// Full message: +// - All of the required rules must pass for `Person { +$name="" +$email="not an email" +$birthdate="not a date" +$phone="not a phone number" }` +// - name must not be empty +// - email must be a valid email address +// - All of the required rules must pass for birthdate +// - birthdate must be a valid date in the format "2005-12-30" +// - For comparison with now, birthdate must be a valid datetime +// - phone must be a valid telephone number or must be null +``` + +## Caveats + +* If the object has no attributes, the validation will always pass. +* When the property is nullable, this rule will wrap the rule on the property into [NullOr](NullOr.md) rule. +* This rule has no templates because it uses the templates of the rules that are applied to the properties. + +## Categorization + +- Objects +- Structures + +## Changelog + +| Version | Description | +|--------:|-------------| +| 3.0.0 | Created | + +*** +See also: + +- [NullOr](NullOr.md) +- [ObjectType](ObjectType.md) +- [Property](Property.md) +- [PropertyExists](PropertyExists.md) +- [PropertyOptional](PropertyOptional.md) diff --git a/docs/rules/Date.md b/docs/rules/Date.md index 3c64cd241..1a2b8fc55 100644 --- a/docs/rules/Date.md +++ b/docs/rules/Date.md @@ -1,4 +1,4 @@ -[]()# Date +# Date - `Date()` - `Date(string $format)` diff --git a/docs/rules/NullOr.md b/docs/rules/NullOr.md index f502f4b57..41576b77c 100644 --- a/docs/rules/NullOr.md +++ b/docs/rules/NullOr.md @@ -60,5 +60,6 @@ v::not(v::nullOr(v::alpha()))->assert("alpha"); *** See also: +- [Attributes](Attributes.md) - [NullType](NullType.md) - [UndefOr](UndefOr.md) diff --git a/docs/rules/ObjectType.md b/docs/rules/ObjectType.md index 93a57f933..ea8cc2fa5 100644 --- a/docs/rules/ObjectType.md +++ b/docs/rules/ObjectType.md @@ -39,6 +39,7 @@ v::objectType()->isValid(new stdClass); // true See also: - [ArrayType](ArrayType.md) +- [Attributes](Attributes.md) - [BoolType](BoolType.md) - [BoolVal](BoolVal.md) - [CallableType](CallableType.md) diff --git a/docs/rules/Property.md b/docs/rules/Property.md index 8bf1f5f44..30219abd2 100644 --- a/docs/rules/Property.md +++ b/docs/rules/Property.md @@ -69,6 +69,7 @@ This rule will validate public, private, protected, uninitialised, and static pr *** See also: +- [Attributes](Attributes.md) - [Key](Key.md) - [KeyExists](KeyExists.md) - [KeyOptional](KeyOptional.md) diff --git a/docs/rules/PropertyExists.md b/docs/rules/PropertyExists.md index b04406513..df36dcd80 100644 --- a/docs/rules/PropertyExists.md +++ b/docs/rules/PropertyExists.md @@ -50,6 +50,7 @@ This rule will validate public, private, protected, uninitialised, and static pr *** See also: +- [Attributes](Attributes.md) - [Key](Key.md) - [KeyExists](KeyExists.md) - [KeyOptional](KeyOptional.md) diff --git a/docs/rules/PropertyOptional.md b/docs/rules/PropertyOptional.md index 3f2a62004..ff9ae3e10 100644 --- a/docs/rules/PropertyOptional.md +++ b/docs/rules/PropertyOptional.md @@ -62,6 +62,7 @@ v::objectType()->propertyOptional('name', v::notEmpty())->isValid('Not an object *** See also: +- [Attributes](Attributes.md) - [Key](Key.md) - [KeyExists](KeyExists.md) - [KeyOptional](KeyOptional.md) diff --git a/library/Mixins/ChainedNullOr.php b/library/Mixins/ChainedNullOr.php index ab749f4f7..3fec3045a 100644 --- a/library/Mixins/ChainedNullOr.php +++ b/library/Mixins/ChainedNullOr.php @@ -30,6 +30,8 @@ public function nullOrArrayType(): ChainedValidator; public function nullOrArrayVal(): ChainedValidator; + public function nullOrAttributes(): ChainedValidator; + public function nullOrBase( int $base, string $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', diff --git a/library/Mixins/ChainedValidator.php b/library/Mixins/ChainedValidator.php index 565735509..7bd0a03aa 100644 --- a/library/Mixins/ChainedValidator.php +++ b/library/Mixins/ChainedValidator.php @@ -58,6 +58,8 @@ public function arrayType(): ChainedValidator; public function arrayVal(): ChainedValidator; + public function attributes(): ChainedValidator; + public function base( int $base, string $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', diff --git a/library/Mixins/StaticNullOr.php b/library/Mixins/StaticNullOr.php index 4788510c5..f2d9c7ccd 100644 --- a/library/Mixins/StaticNullOr.php +++ b/library/Mixins/StaticNullOr.php @@ -30,6 +30,8 @@ public static function nullOrArrayType(): ChainedValidator; public static function nullOrArrayVal(): ChainedValidator; + public static function nullOrAttributes(): ChainedValidator; + public static function nullOrBase( int $base, string $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', diff --git a/library/Mixins/StaticValidator.php b/library/Mixins/StaticValidator.php index 787e53eaa..3f9ac7893 100644 --- a/library/Mixins/StaticValidator.php +++ b/library/Mixins/StaticValidator.php @@ -38,6 +38,8 @@ public static function arrayType(): ChainedValidator; public static function arrayVal(): ChainedValidator; + public static function attributes(): ChainedValidator; + public static function base( int $base, string $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', diff --git a/library/Rules/AllOf.php b/library/Rules/AllOf.php index 94070d904..af7b41e82 100644 --- a/library/Rules/AllOf.php +++ b/library/Rules/AllOf.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rule; @@ -19,6 +20,7 @@ use function array_reduce; use function count; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'These rules must pass for {{name}}', 'These rules must not pass for {{name}}', diff --git a/library/Rules/Alnum.php b/library/Rules/Alnum.php index dc142eb65..63b7c3a8c 100644 --- a/library/Rules/Alnum.php +++ b/library/Rules/Alnum.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_alnum; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only letters (a-z) and digits (0-9)', '{{name}} must not contain letters (a-z) or digits (0-9)', diff --git a/library/Rules/Alpha.php b/library/Rules/Alpha.php index 21e15d5ad..1eefdb3f6 100644 --- a/library/Rules/Alpha.php +++ b/library/Rules/Alpha.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_alpha; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only letters (a-z)', '{{name}} must not contain letters (a-z)', diff --git a/library/Rules/AlwaysInvalid.php b/library/Rules/AlwaysInvalid.php index c2e6e95c3..791cbe7d3 100644 --- a/library/Rules/AlwaysInvalid.php +++ b/library/Rules/AlwaysInvalid.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be valid', '{{name}} must be invalid', diff --git a/library/Rules/AlwaysValid.php b/library/Rules/AlwaysValid.php index 9e764dfa3..dbca8bd44 100644 --- a/library/Rules/AlwaysValid.php +++ b/library/Rules/AlwaysValid.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be valid', '{{name}} must be invalid', diff --git a/library/Rules/AnyOf.php b/library/Rules/AnyOf.php index 25117563d..adf170587 100644 --- a/library/Rules/AnyOf.php +++ b/library/Rules/AnyOf.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rule; @@ -17,6 +18,7 @@ use function array_map; use function array_reduce; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'At least one of these rules must pass for {{name}}', 'At least one of these rules must not pass for {{name}}', diff --git a/library/Rules/ArrayType.php b/library/Rules/ArrayType.php index 2f5415976..eff84f9d8 100644 --- a/library/Rules/ArrayType.php +++ b/library/Rules/ArrayType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_array; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an array', '{{name}} must not be an array', diff --git a/library/Rules/ArrayVal.php b/library/Rules/ArrayVal.php index 9c1674623..7d2e32686 100644 --- a/library/Rules/ArrayVal.php +++ b/library/Rules/ArrayVal.php @@ -10,12 +10,14 @@ namespace Respect\Validation\Rules; use ArrayAccess; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use SimpleXMLElement; use function is_array; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an array value', '{{name}} must not be an array value', diff --git a/library/Rules/Attributes.php b/library/Rules/Attributes.php new file mode 100644 index 000000000..09f2f2419 --- /dev/null +++ b/library/Rules/Attributes.php @@ -0,0 +1,54 @@ + + * SPDX-License-Identifier: MIT + */ + +declare(strict_types=1); + +namespace Respect\Validation\Rules; + +use Attribute; +use ReflectionAttribute; +use ReflectionObject; +use Respect\Validation\Result; +use Respect\Validation\Rule; +use Respect\Validation\Rules\Core\Binder; +use Respect\Validation\Rules\Core\Reducer; +use Respect\Validation\Rules\Core\Standard; + +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] +final class Attributes extends Standard +{ + public function evaluate(mixed $input): Result + { + $objectType = (new Binder($this, new ObjectType()))->evaluate($input); + if (!$objectType->isValid) { + return $objectType->withId('attributes'); + } + + $rules = []; + foreach ((new ReflectionObject($input))->getProperties() as $property) { + $childrenRules = []; + foreach ($property->getAttributes(Rule::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { + $childrenRules[] = $attribute->newInstance(); + } + + if ($childrenRules === []) { + continue; + } + + $allowsNull = $property->getType()?->allowsNull() ?? false; + + $childRule = new Reducer(...$childrenRules); + $rules[] = new Property($property->getName(), $allowsNull ? new NullOr($childRule) : $childRule); + } + + if ($rules === []) { + return (new AlwaysValid())->evaluate($input)->withId('attributes'); + } + + return (new Binder($this, new Reducer(...$rules)))->evaluate($input)->withId('attributes'); + } +} diff --git a/library/Rules/Base.php b/library/Rules/Base.php index 2d545fa57..700c050ad 100644 --- a/library/Rules/Base.php +++ b/library/Rules/Base.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -18,6 +19,7 @@ use function mb_substr; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a number in base {{base|raw}}', '{{name}} must not be a number in base {{base|raw}}', diff --git a/library/Rules/Base64.php b/library/Rules/Base64.php index 64e5bc02c..ced23218c 100644 --- a/library/Rules/Base64.php +++ b/library/Rules/Base64.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function mb_strlen; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a base64 encoded string', '{{name}} must not be a base64 encoded string', diff --git a/library/Rules/Between.php b/library/Rules/Between.php index 45ddf8ecd..9473ef982 100644 --- a/library/Rules/Between.php +++ b/library/Rules/Between.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Helpers\CanCompareValues; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be between {{minValue}} and {{maxValue}}', '{{name}} must not be between {{minValue}} and {{maxValue}}', diff --git a/library/Rules/BetweenExclusive.php b/library/Rules/BetweenExclusive.php index 73579e5f7..e0efdd84f 100644 --- a/library/Rules/BetweenExclusive.php +++ b/library/Rules/BetweenExclusive.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Helpers\CanCompareValues; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be greater than {{minValue}} and less than {{maxValue}}', '{{name}} must not be greater than {{minValue}} or less than {{maxValue}}', diff --git a/library/Rules/BoolType.php b/library/Rules/BoolType.php index 0b3ed43fc..45049b31e 100644 --- a/library/Rules/BoolType.php +++ b/library/Rules/BoolType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_bool; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a boolean', '{{name}} must not be a boolean', diff --git a/library/Rules/BoolVal.php b/library/Rules/BoolVal.php index cfee7b99a..ee765fec6 100644 --- a/library/Rules/BoolVal.php +++ b/library/Rules/BoolVal.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -18,6 +19,7 @@ use const FILTER_NULL_ON_FAILURE; use const FILTER_VALIDATE_BOOLEAN; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a boolean value', '{{name}} must not be a boolean value', diff --git a/library/Rules/Bsn.php b/library/Rules/Bsn.php index b7d4daf4f..f29c71134 100644 --- a/library/Rules/Bsn.php +++ b/library/Rules/Bsn.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -21,6 +22,7 @@ /** * @see https://nl.wikipedia.org/wiki/Burgerservicenummer */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid BSN', '{{name}} must not be a valid BSN', diff --git a/library/Rules/Call.php b/library/Rules/Call.php index b14c9d580..1d27a58b1 100644 --- a/library/Rules/Call.php +++ b/library/Rules/Call.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use ErrorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -20,6 +21,7 @@ use function restore_error_handler; use function set_error_handler; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{input}} must be a suitable argument for {{callable}}', '{{input}} must not be a suitable argument for {{callable}}', diff --git a/library/Rules/CallableType.php b/library/Rules/CallableType.php index c6ac26baf..253c0993d 100644 --- a/library/Rules/CallableType.php +++ b/library/Rules/CallableType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_callable; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a callable', '{{name}} must not be a callable', diff --git a/library/Rules/Callback.php b/library/Rules/Callback.php index 874ddd408..87e12c5c3 100644 --- a/library/Rules/Callback.php +++ b/library/Rules/Callback.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function call_user_func_array; use function count; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be valid', '{{name}} must be invalid', diff --git a/library/Rules/Charset.php b/library/Rules/Charset.php index 7b07bcf75..430593ef6 100644 --- a/library/Rules/Charset.php +++ b/library/Rules/Charset.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -22,6 +23,7 @@ use function mb_detect_encoding; use function mb_list_encodings; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must only contain characters from the {{charset|raw}} charset', '{{name}} must not contain any characters from the {{charset|raw}} charset', diff --git a/library/Rules/Cnh.php b/library/Rules/Cnh.php index d1af6cde5..c82dd78d4 100644 --- a/library/Rules/Cnh.php +++ b/library/Rules/Cnh.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function mb_strlen; use function preg_replace; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid CNH number', '{{name}} must not be a valid CNH number', diff --git a/library/Rules/Cnpj.php b/library/Rules/Cnpj.php index 8f68230a1..08937e8c3 100644 --- a/library/Rules/Cnpj.php +++ b/library/Rules/Cnpj.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -19,6 +20,7 @@ use function preg_replace; use function str_split; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid CNPJ number', '{{name}} must not be a valid CNPJ number', diff --git a/library/Rules/Consecutive.php b/library/Rules/Consecutive.php index 247d6dd1b..11f2705fa 100644 --- a/library/Rules/Consecutive.php +++ b/library/Rules/Consecutive.php @@ -9,10 +9,12 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Binder; use Respect\Validation\Rules\Core\Composite; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class Consecutive extends Composite { public function evaluate(mixed $input): Result diff --git a/library/Rules/Consonant.php b/library/Rules/Consonant.php index b13fbe151..e046e90c3 100644 --- a/library/Rules/Consonant.php +++ b/library/Rules/Consonant.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must only contain consonants', '{{name}} must not contain consonants', diff --git a/library/Rules/Contains.php b/library/Rules/Contains.php index 5cb5a50cc..9242fd4fc 100644 --- a/library/Rules/Contains.php +++ b/library/Rules/Contains.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -19,6 +20,7 @@ use function mb_stripos; use function mb_strpos; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain {{containsValue}}', '{{name}} must not contain {{containsValue}}', diff --git a/library/Rules/ContainsAny.php b/library/Rules/ContainsAny.php index d5c12f8fa..6681d1b25 100644 --- a/library/Rules/ContainsAny.php +++ b/library/Rules/ContainsAny.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; @@ -16,6 +17,7 @@ use function array_map; use function count; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain at least one value from {{needles}}', '{{name}} must not contain any value from {{needles}}', diff --git a/library/Rules/Control.php b/library/Rules/Control.php index 31a5c2022..df4e288d9 100644 --- a/library/Rules/Control.php +++ b/library/Rules/Control.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_cntrl; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must only contain control characters', '{{name}} must not contain control characters', diff --git a/library/Rules/Countable.php b/library/Rules/Countable.php index 589635997..caa08e1ab 100644 --- a/library/Rules/Countable.php +++ b/library/Rules/Countable.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Countable as CountableInterface; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_array; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a countable value', '{{name}} must not be a countable value', diff --git a/library/Rules/CountryCode.php b/library/Rules/CountryCode.php index bef7e754a..83fd04cf2 100644 --- a/library/Rules/CountryCode.php +++ b/library/Rules/CountryCode.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Exceptions\MissingComposerDependencyException; use Respect\Validation\Message\Template; @@ -20,6 +21,7 @@ use function in_array; use function is_string; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid country code', '{{name}} must not be a valid country code', diff --git a/library/Rules/Cpf.php b/library/Rules/Cpf.php index 287387004..41694ca05 100644 --- a/library/Rules/Cpf.php +++ b/library/Rules/Cpf.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use function preg_match; use function preg_replace; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid CPF number', '{{name}} must not be a valid CPF number', diff --git a/library/Rules/CreditCard.php b/library/Rules/CreditCard.php index aceec7c90..e73a2e2a5 100644 --- a/library/Rules/CreditCard.php +++ b/library/Rules/CreditCard.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -19,6 +20,7 @@ use function preg_match; use function preg_replace; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid credit card number', '{{name}} must not be a valid credit card number', diff --git a/library/Rules/CurrencyCode.php b/library/Rules/CurrencyCode.php index f45eca23d..88a1907eb 100644 --- a/library/Rules/CurrencyCode.php +++ b/library/Rules/CurrencyCode.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Exceptions\MissingComposerDependencyException; use Respect\Validation\Message\Template; @@ -19,6 +20,7 @@ use function class_exists; use function in_array; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid currency code', '{{name}} must not be a valid currency code', diff --git a/library/Rules/Date.php b/library/Rules/Date.php index f5854002c..41c12bbfe 100644 --- a/library/Rules/Date.php +++ b/library/Rules/Date.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Helpers\CanValidateDateTime; use Respect\Validation\Message\Template; @@ -20,6 +21,7 @@ use function preg_match; use function strtotime; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid date in the format {{sample}}', '{{name}} must not be a valid date in the format {{sample}}', diff --git a/library/Rules/DateTime.php b/library/Rules/DateTime.php index ef96a71cb..990b1094b 100644 --- a/library/Rules/DateTime.php +++ b/library/Rules/DateTime.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use DateTimeInterface; use Respect\Validation\Helpers\CanValidateDateTime; use Respect\Validation\Message\Template; @@ -19,6 +20,7 @@ use function is_scalar; use function strtotime; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid date/time', '{{name}} must not be a valid date/time', diff --git a/library/Rules/DateTimeDiff.php b/library/Rules/DateTimeDiff.php index ece203a41..8f92116c0 100644 --- a/library/Rules/DateTimeDiff.php +++ b/library/Rules/DateTimeDiff.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use DateTimeImmutable; use DateTimeInterface; use Respect\Validation\Exceptions\InvalidRuleConstructorException; @@ -23,6 +24,7 @@ use function in_array; use function ucfirst; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'The number of {{type|trans}} between now and', 'The number of {{type|trans}} between now and', diff --git a/library/Rules/Decimal.php b/library/Rules/Decimal.php index 2053bdf45..dfcdbd92c 100644 --- a/library/Rules/Decimal.php +++ b/library/Rules/Decimal.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -19,6 +20,7 @@ use function preg_replace; use function var_export; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must have {{decimals}} decimals', '{{name}} must not have {{decimals}} decimals', diff --git a/library/Rules/Digit.php b/library/Rules/Digit.php index 4c1234904..6740daa2f 100644 --- a/library/Rules/Digit.php +++ b/library/Rules/Digit.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_digit; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only digits (0-9)', '{{name}} must not contain digits (0-9)', diff --git a/library/Rules/Directory.php b/library/Rules/Directory.php index 68b8bf59f..036f305b1 100644 --- a/library/Rules/Directory.php +++ b/library/Rules/Directory.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Directory as NativeDirectory; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use function is_dir; use function is_scalar; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a directory', '{{name}} must not be a directory', diff --git a/library/Rules/Domain.php b/library/Rules/Domain.php index 6ad487809..e35510e90 100644 --- a/library/Rules/Domain.php +++ b/library/Rules/Domain.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rule; @@ -19,6 +20,7 @@ use function explode; use function mb_substr_count; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid domain', '{{name}} must not be a valid domain', diff --git a/library/Rules/Each.php b/library/Rules/Each.php index c4497ba5f..19397c0f0 100644 --- a/library/Rules/Each.php +++ b/library/Rules/Each.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\FilteredNonEmptyArray; @@ -16,6 +17,7 @@ use function array_map; use function array_reduce; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'Each item in {{name}} must be valid', 'Each item in {{name}} must be invalid', diff --git a/library/Rules/Email.php b/library/Rules/Email.php index 8bef9b0ec..34e44a787 100644 --- a/library/Rules/Email.php +++ b/library/Rules/Email.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\RFCValidation; use Respect\Validation\Message\Template; @@ -21,6 +22,7 @@ use const FILTER_VALIDATE_EMAIL; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid email address', '{{name}} must not be an email address', diff --git a/library/Rules/EndsWith.php b/library/Rules/EndsWith.php index 49a10d9fe..5908ae9a3 100644 --- a/library/Rules/EndsWith.php +++ b/library/Rules/EndsWith.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -19,6 +20,7 @@ use function mb_strripos; use function mb_strrpos; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must end with {{endValue}}', '{{name}} must not end with {{endValue}}', diff --git a/library/Rules/Equals.php b/library/Rules/Equals.php index cb795cbf1..b7e8d3dca 100644 --- a/library/Rules/Equals.php +++ b/library/Rules/Equals.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; use function is_scalar; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be equal to {{compareTo}}', '{{name}} must not be equal to {{compareTo}}', diff --git a/library/Rules/Equivalent.php b/library/Rules/Equivalent.php index a3f4f1423..36c1b2b73 100644 --- a/library/Rules/Equivalent.php +++ b/library/Rules/Equivalent.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Comparison; use function is_scalar; use function mb_strtoupper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be equivalent to {{compareTo}}', '{{name}} must not be equivalent to {{compareTo}}', diff --git a/library/Rules/Even.php b/library/Rules/Even.php index 20542dada..3e67c319b 100644 --- a/library/Rules/Even.php +++ b/library/Rules/Even.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use const FILTER_VALIDATE_INT; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an even number', '{{name}} must be an odd number', diff --git a/library/Rules/Executable.php b/library/Rules/Executable.php index e87674e50..93bea4644 100644 --- a/library/Rules/Executable.php +++ b/library/Rules/Executable.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use SplFileInfo; @@ -16,6 +17,7 @@ use function is_executable; use function is_scalar; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an executable file', '{{name}} must not be an executable file', diff --git a/library/Rules/Exists.php b/library/Rules/Exists.php index ddb0b9765..4bef376a8 100644 --- a/library/Rules/Exists.php +++ b/library/Rules/Exists.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use SplFileInfo; @@ -16,6 +17,7 @@ use function file_exists; use function is_string; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an existing file', '{{name}} must not be an existing file', diff --git a/library/Rules/Extension.php b/library/Rules/Extension.php index eb8487b5f..a61d72a50 100644 --- a/library/Rules/Extension.php +++ b/library/Rules/Extension.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -19,6 +20,7 @@ use const PATHINFO_EXTENSION; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must have {{extension}} extension', '{{name}} must not have {{extension}} extension', diff --git a/library/Rules/Factor.php b/library/Rules/Factor.php index 29abb90c7..fe473c62a 100644 --- a/library/Rules/Factor.php +++ b/library/Rules/Factor.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -17,6 +18,7 @@ use function is_integer; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a factor of {{dividend|raw}}', '{{name}} must not be a factor of {{dividend|raw}}', diff --git a/library/Rules/FalseVal.php b/library/Rules/FalseVal.php index 8efcc1215..1cc65cac7 100644 --- a/library/Rules/FalseVal.php +++ b/library/Rules/FalseVal.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use const FILTER_NULL_ON_FAILURE; use const FILTER_VALIDATE_BOOLEAN; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must evaluate to `false`', '{{name}} must not evaluate to `false`', diff --git a/library/Rules/Fibonacci.php b/library/Rules/Fibonacci.php index 275be3c24..705a72f7a 100644 --- a/library/Rules/Fibonacci.php +++ b/library/Rules/Fibonacci.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid Fibonacci number', '{{name}} must not be a valid Fibonacci number', diff --git a/library/Rules/File.php b/library/Rules/File.php index d2e050f9f..b6f892467 100644 --- a/library/Rules/File.php +++ b/library/Rules/File.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use SplFileInfo; @@ -16,6 +17,7 @@ use function is_file; use function is_string; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid file', '{{name}} must be an invalid file', diff --git a/library/Rules/FilterVar.php b/library/Rules/FilterVar.php index 764a70fd8..b035917fc 100644 --- a/library/Rules/FilterVar.php +++ b/library/Rules/FilterVar.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; @@ -27,6 +28,7 @@ use const FILTER_VALIDATE_REGEXP; use const FILTER_VALIDATE_URL; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be valid', '{{name}} must not be valid', diff --git a/library/Rules/Finite.php b/library/Rules/Finite.php index 7723c94c3..20c1fa04f 100644 --- a/library/Rules/Finite.php +++ b/library/Rules/Finite.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_finite; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a finite number', '{{name}} must not be a finite number', diff --git a/library/Rules/FloatType.php b/library/Rules/FloatType.php index 13a5eda99..2ad8ffd17 100644 --- a/library/Rules/FloatType.php +++ b/library/Rules/FloatType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_float; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be float', '{{name}} must not be float', diff --git a/library/Rules/FloatVal.php b/library/Rules/FloatVal.php index 839aa481f..dd9aa907d 100644 --- a/library/Rules/FloatVal.php +++ b/library/Rules/FloatVal.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use const FILTER_VALIDATE_FLOAT; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a float value', '{{name}} must not be a float value', diff --git a/library/Rules/Graph.php b/library/Rules/Graph.php index b5824cd2f..5865fc68b 100644 --- a/library/Rules/Graph.php +++ b/library/Rules/Graph.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_graph; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only graphical characters', '{{name}} must not contain graphical characters', diff --git a/library/Rules/GreaterThan.php b/library/Rules/GreaterThan.php index 75fe67887..8d788d863 100644 --- a/library/Rules/GreaterThan.php +++ b/library/Rules/GreaterThan.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Comparison; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be greater than {{compareTo}}', '{{name}} must not be greater than {{compareTo}}', diff --git a/library/Rules/GreaterThanOrEqual.php b/library/Rules/GreaterThanOrEqual.php index ddbc34941..e0301e9a4 100644 --- a/library/Rules/GreaterThanOrEqual.php +++ b/library/Rules/GreaterThanOrEqual.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Comparison; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be greater than or equal to {{compareTo}}', '{{name}} must be less than {{compareTo}}', diff --git a/library/Rules/Hetu.php b/library/Rules/Hetu.php index 8d50ec479..08211a8af 100644 --- a/library/Rules/Hetu.php +++ b/library/Rules/Hetu.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Helpers\CanValidateDateTime; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -20,6 +21,7 @@ /** * @see https://en.wikipedia.org/wiki/National_identification_number#Finland */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid Finnish personal identity code', '{{name}} must not be a valid Finnish personal identity code', diff --git a/library/Rules/HexRgbColor.php b/library/Rules/HexRgbColor.php index 8809e1007..d6f898fc5 100644 --- a/library/Rules/HexRgbColor.php +++ b/library/Rules/HexRgbColor.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a hex RGB color', '{{name}} must not be a hex RGB color', diff --git a/library/Rules/Iban.php b/library/Rules/Iban.php index 51db37d74..9bb9a749c 100644 --- a/library/Rules/Iban.php +++ b/library/Rules/Iban.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -22,6 +23,7 @@ use function strval; use function substr; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid IBAN', '{{name}} must not be a valid IBAN', diff --git a/library/Rules/Identical.php b/library/Rules/Identical.php index 2d4c3934f..50a5e4c91 100644 --- a/library/Rules/Identical.php +++ b/library/Rules/Identical.php @@ -9,10 +9,12 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be identical to {{compareTo}}', '{{name}} must not be identical to {{compareTo}}', diff --git a/library/Rules/Image.php b/library/Rules/Image.php index 03fcfa56b..27a12320e 100644 --- a/library/Rules/Image.php +++ b/library/Rules/Image.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use finfo; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -20,6 +21,7 @@ use const FILEINFO_MIME_TYPE; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid image file', '{{name}} must not be a valid image file', diff --git a/library/Rules/Imei.php b/library/Rules/Imei.php index c5047f6bc..16d83302d 100644 --- a/library/Rules/Imei.php +++ b/library/Rules/Imei.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function mb_strlen; use function preg_replace; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid IMEI number', '{{name}} must not be a valid IMEI number', diff --git a/library/Rules/In.php b/library/Rules/In.php index ef1818a1c..705858375 100644 --- a/library/Rules/In.php +++ b/library/Rules/In.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -18,6 +19,7 @@ use function mb_stripos; use function mb_strpos; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be in {{haystack}}', '{{name}} must not be in {{haystack}}', diff --git a/library/Rules/Infinite.php b/library/Rules/Infinite.php index c1601d831..f5a7b56f0 100644 --- a/library/Rules/Infinite.php +++ b/library/Rules/Infinite.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_infinite; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an infinite number', '{{name}} must not be an infinite number', diff --git a/library/Rules/Instance.php b/library/Rules/Instance.php index e38b8b909..b62412109 100644 --- a/library/Rules/Instance.php +++ b/library/Rules/Instance.php @@ -9,10 +9,12 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an instance of `{{class|raw}}`', '{{name}} must not be an instance of `{{class|raw}}`', diff --git a/library/Rules/IntType.php b/library/Rules/IntType.php index c2b465983..154d610c1 100644 --- a/library/Rules/IntType.php +++ b/library/Rules/IntType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_int; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an integer', '{{name}} must not be an integer', diff --git a/library/Rules/IntVal.php b/library/Rules/IntVal.php index 285df58de..d2f5d83fd 100644 --- a/library/Rules/IntVal.php +++ b/library/Rules/IntVal.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function is_string; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an integer value', '{{name}} must not be an integer value', diff --git a/library/Rules/Ip.php b/library/Rules/Ip.php index 50ee556e3..0ddd4ce10 100644 --- a/library/Rules/Ip.php +++ b/library/Rules/Ip.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -29,6 +30,7 @@ use const FILTER_VALIDATE_IP; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an IP address', '{{name}} must not be an IP address', diff --git a/library/Rules/Isbn.php b/library/Rules/Isbn.php index fe6a784c8..494087df7 100644 --- a/library/Rules/Isbn.php +++ b/library/Rules/Isbn.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use function preg_match; use function sprintf; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid ISBN', '{{name}} must not be a valid ISBN', diff --git a/library/Rules/IterableType.php b/library/Rules/IterableType.php index 0b3f54553..58b4285e9 100644 --- a/library/Rules/IterableType.php +++ b/library/Rules/IterableType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_iterable; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be iterable', '{{name}} must not iterable', diff --git a/library/Rules/IterableVal.php b/library/Rules/IterableVal.php index 729eb0245..f0ab3feae 100644 --- a/library/Rules/IterableVal.php +++ b/library/Rules/IterableVal.php @@ -9,10 +9,12 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Helpers\CanValidateIterable; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an iterable value', '{{name}} must not be an iterable value', diff --git a/library/Rules/Json.php b/library/Rules/Json.php index dd4f4166f..d68424486 100644 --- a/library/Rules/Json.php +++ b/library/Rules/Json.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -20,6 +21,7 @@ use const JSON_ERROR_NONE; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid JSON string', '{{name}} must not be a valid JSON string', diff --git a/library/Rules/Key.php b/library/Rules/Key.php index 08eaf0758..81b48e267 100644 --- a/library/Rules/Key.php +++ b/library/Rules/Key.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Result; use Respect\Validation\Rule; use Respect\Validation\Rules\Core\Binder; use Respect\Validation\Rules\Core\KeyRelated; use Respect\Validation\Rules\Core\Wrapper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class Key extends Wrapper implements KeyRelated { public function __construct( diff --git a/library/Rules/KeyExists.php b/library/Rules/KeyExists.php index 10620487a..b9b2fda56 100644 --- a/library/Rules/KeyExists.php +++ b/library/Rules/KeyExists.php @@ -10,6 +10,7 @@ namespace Respect\Validation\Rules; use ArrayAccess; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\KeyRelated; @@ -18,6 +19,7 @@ use function array_key_exists; use function is_array; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be present', '{{name}} must not be present', diff --git a/library/Rules/KeyOptional.php b/library/Rules/KeyOptional.php index ae9a7781c..36d030749 100644 --- a/library/Rules/KeyOptional.php +++ b/library/Rules/KeyOptional.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Result; use Respect\Validation\Rule; use Respect\Validation\Rules\Core\Binder; use Respect\Validation\Rules\Core\KeyRelated; use Respect\Validation\Rules\Core\Wrapper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class KeyOptional extends Wrapper implements KeyRelated { public function __construct( diff --git a/library/Rules/KeySet.php b/library/Rules/KeySet.php index eba2865c4..00c9c69c7 100644 --- a/library/Rules/KeySet.php +++ b/library/Rules/KeySet.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -26,6 +27,7 @@ use function array_merge; use function array_slice; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} validation failed', '{{name}} validation passed', diff --git a/library/Rules/LanguageCode.php b/library/Rules/LanguageCode.php index 05cd4e1cb..9b876bf6a 100644 --- a/library/Rules/LanguageCode.php +++ b/library/Rules/LanguageCode.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Exceptions\MissingComposerDependencyException; use Respect\Validation\Message\Template; @@ -21,6 +22,7 @@ use function in_array; use function is_string; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid language code', '{{name}} must not be a valid language code', diff --git a/library/Rules/Lazy.php b/library/Rules/Lazy.php index de39191fa..16e5c980a 100644 --- a/library/Rules/Lazy.php +++ b/library/Rules/Lazy.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\ComponentException; use Respect\Validation\Result; use Respect\Validation\Rule; @@ -17,6 +18,7 @@ use function call_user_func; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class Lazy extends Standard { /** @var callable(mixed): Rule */ diff --git a/library/Rules/LeapDate.php b/library/Rules/LeapDate.php index 0e620a7aa..ffd435b9e 100644 --- a/library/Rules/LeapDate.php +++ b/library/Rules/LeapDate.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use DateTimeImmutable; use DateTimeInterface; use Respect\Validation\Message\Template; @@ -16,6 +17,7 @@ use function is_scalar; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid leap date', '{{name}} must not be a leap date', diff --git a/library/Rules/LeapYear.php b/library/Rules/LeapYear.php index 0276c3e01..73cc65695 100644 --- a/library/Rules/LeapYear.php +++ b/library/Rules/LeapYear.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use DateTimeInterface; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -19,6 +20,7 @@ use function sprintf; use function strtotime; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid leap year', '{{name}} must not be a leap year', diff --git a/library/Rules/Length.php b/library/Rules/Length.php index cbe35ff64..a61704d44 100644 --- a/library/Rules/Length.php +++ b/library/Rules/Length.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Countable as PhpCountable; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -20,6 +21,7 @@ use function mb_strlen; use function ucfirst; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template('The length of', 'The length of')] final class Length extends Wrapper { diff --git a/library/Rules/LessThan.php b/library/Rules/LessThan.php index 28248d99b..4c8519cf6 100644 --- a/library/Rules/LessThan.php +++ b/library/Rules/LessThan.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Comparison; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be less than {{compareTo}}', '{{name}} must not be less than {{compareTo}}', diff --git a/library/Rules/LessThanOrEqual.php b/library/Rules/LessThanOrEqual.php index 5ee71f716..c7b4924f6 100644 --- a/library/Rules/LessThanOrEqual.php +++ b/library/Rules/LessThanOrEqual.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Comparison; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be less than or equal to {{compareTo}}', '{{name}} must be greater than {{compareTo}}', diff --git a/library/Rules/Lowercase.php b/library/Rules/Lowercase.php index 00a72f892..29de040ee 100644 --- a/library/Rules/Lowercase.php +++ b/library/Rules/Lowercase.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_string; use function mb_strtolower; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only lowercase letters', '{{name}} must not contain only lowercase letters', diff --git a/library/Rules/Luhn.php b/library/Rules/Luhn.php index 11abd08a9..70ccf3083 100644 --- a/library/Rules/Luhn.php +++ b/library/Rules/Luhn.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -19,6 +20,7 @@ /** * @see https://en.wikipedia.org/wiki/Luhn_algorithm */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid Luhn number', '{{name}} must not be a valid Luhn number', diff --git a/library/Rules/MacAddress.php b/library/Rules/MacAddress.php index 2ec8a2b1e..9a954c9c1 100644 --- a/library/Rules/MacAddress.php +++ b/library/Rules/MacAddress.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_string; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid MAC address', '{{name}} must not be a valid MAC address', diff --git a/library/Rules/Max.php b/library/Rules/Max.php index 7977bf16a..3f2cf62bc 100644 --- a/library/Rules/Max.php +++ b/library/Rules/Max.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\FilteredNonEmptyArray; use function max; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template('As the maximum of {{name}},', 'As the maximum of {{name}},')] #[Template('The maximum of', 'The maximum of', self::TEMPLATE_NAMED)] final class Max extends FilteredNonEmptyArray diff --git a/library/Rules/Mimetype.php b/library/Rules/Mimetype.php index 40e7c4ef5..71a0ee81e 100644 --- a/library/Rules/Mimetype.php +++ b/library/Rules/Mimetype.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use finfo; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -20,6 +21,7 @@ use const FILEINFO_MIME_TYPE; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must have the {{mimetype}} MIME type', '{{name}} must not have the {{mimetype}} MIME type', diff --git a/library/Rules/Min.php b/library/Rules/Min.php index 8e619a6a3..2180da2c6 100644 --- a/library/Rules/Min.php +++ b/library/Rules/Min.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\FilteredNonEmptyArray; use function min; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template('As the minimum from {{name}},', 'As the minimum from {{name}},')] #[Template('The minimum from', 'The minimum from', self::TEMPLATE_NAMED)] final class Min extends FilteredNonEmptyArray diff --git a/library/Rules/Multiple.php b/library/Rules/Multiple.php index f5866112e..725f17b70 100644 --- a/library/Rules/Multiple.php +++ b/library/Rules/Multiple.php @@ -9,10 +9,12 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a multiple of {{multipleOf}}', '{{name}} must not be a multiple of {{multipleOf}}', diff --git a/library/Rules/Negative.php b/library/Rules/Negative.php index 12b70d7a6..fb2183e4b 100644 --- a/library/Rules/Negative.php +++ b/library/Rules/Negative.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a negative number', '{{name}} must not be a negative number', diff --git a/library/Rules/NfeAccessKey.php b/library/Rules/NfeAccessKey.php index 09d834664..f991dbdd7 100644 --- a/library/Rules/NfeAccessKey.php +++ b/library/Rules/NfeAccessKey.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -20,6 +21,7 @@ /** * @see (pt-br) Manual de Integração do Contribuinte v4.0.1 em http://www.nfe.fazenda.gov.br */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid NFe access key', '{{name}} must not be a valid NFe access key', diff --git a/library/Rules/Nif.php b/library/Rules/Nif.php index 7670158c2..ce58e8c5c 100644 --- a/library/Rules/Nif.php +++ b/library/Rules/Nif.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -23,6 +24,7 @@ /** * @see https://es.wikipedia.org/wiki/N%C3%BAmero_de_identificaci%C3%B3n_fiscal */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid NIF', '{{name}} must not be a valid NIF', diff --git a/library/Rules/Nip.php b/library/Rules/Nip.php index 7043d84b0..f75da0bc0 100644 --- a/library/Rules/Nip.php +++ b/library/Rules/Nip.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -20,6 +21,7 @@ /** * @see https://en.wikipedia.org/wiki/VAT_identification_number */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid Polish VAT identification number', '{{name}} must not be a valid Polish VAT identification number', diff --git a/library/Rules/No.php b/library/Rules/No.php index ccad57cd4..ae363c060 100644 --- a/library/Rules/No.php +++ b/library/Rules/No.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; @@ -16,6 +17,7 @@ use const NOEXPR; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be similar to "No"', '{{name}} must not be similar to "No"', diff --git a/library/Rules/NoWhitespace.php b/library/Rules/NoWhitespace.php index 4fbc5da25..fb4d7de26 100644 --- a/library/Rules/NoWhitespace.php +++ b/library/Rules/NoWhitespace.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function is_scalar; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must not contain whitespaces', '{{name}} must contain at least one whitespace', diff --git a/library/Rules/NoneOf.php b/library/Rules/NoneOf.php index 7e749efdc..953a4d1b8 100644 --- a/library/Rules/NoneOf.php +++ b/library/Rules/NoneOf.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rule; @@ -17,6 +18,7 @@ use function array_map; use function array_reduce; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'None of these rules must pass for {{name}}', 'All of these rules must pass for {{name}}', diff --git a/library/Rules/Not.php b/library/Rules/Not.php index 21f3a4d64..33cb3cc0a 100644 --- a/library/Rules/Not.php +++ b/library/Rules/Not.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Wrapper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class Not extends Wrapper { public function evaluate(mixed $input): Result diff --git a/library/Rules/NotBlank.php b/library/Rules/NotBlank.php index 093467100..f268c3bd8 100644 --- a/library/Rules/NotBlank.php +++ b/library/Rules/NotBlank.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -20,6 +21,7 @@ use function is_string; use function trim; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'The value must not be blank', 'The value must be blank', diff --git a/library/Rules/NotEmoji.php b/library/Rules/NotEmoji.php index 9dcce0ffc..9e3d6d70f 100644 --- a/library/Rules/NotEmoji.php +++ b/library/Rules/NotEmoji.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function is_string; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must not contain an emoji', '{{name}} must contain an emoji', diff --git a/library/Rules/NotEmpty.php b/library/Rules/NotEmpty.php index a5ed3eff4..3e351c6f8 100644 --- a/library/Rules/NotEmpty.php +++ b/library/Rules/NotEmpty.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -16,6 +17,7 @@ use function is_string; use function trim; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'The value must not be empty', 'The value must be empty', diff --git a/library/Rules/NotUndef.php b/library/Rules/NotUndef.php index f23da883c..6a61c3cec 100644 --- a/library/Rules/NotUndef.php +++ b/library/Rules/NotUndef.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Helpers\CanValidateUndefined; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'The value must be defined', 'The value must be undefined', diff --git a/library/Rules/NullOr.php b/library/Rules/NullOr.php index 9faa2f4c7..91af36c9d 100644 --- a/library/Rules/NullOr.php +++ b/library/Rules/NullOr.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Wrapper; use function array_map; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'or must be null', 'and must not be null', diff --git a/library/Rules/NullType.php b/library/Rules/NullType.php index 9fd7c27c0..ad5322d71 100644 --- a/library/Rules/NullType.php +++ b/library/Rules/NullType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_null; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be null', '{{name}} must not be null', diff --git a/library/Rules/Number.php b/library/Rules/Number.php index 228911451..816697f0c 100644 --- a/library/Rules/Number.php +++ b/library/Rules/Number.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_nan; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid number', '{{name}} must not be a number', diff --git a/library/Rules/NumericVal.php b/library/Rules/NumericVal.php index bab493584..223b8dee6 100644 --- a/library/Rules/NumericVal.php +++ b/library/Rules/NumericVal.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a numeric value', '{{name}} must not be a numeric value', diff --git a/library/Rules/ObjectType.php b/library/Rules/ObjectType.php index 3f18e8e1b..9dd4ba9e9 100644 --- a/library/Rules/ObjectType.php +++ b/library/Rules/ObjectType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_object; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an object', '{{name}} must not be an object', diff --git a/library/Rules/Odd.php b/library/Rules/Odd.php index ea615d8a6..2842a57d3 100644 --- a/library/Rules/Odd.php +++ b/library/Rules/Odd.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use const FILTER_VALIDATE_INT; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an odd number', '{{name}} must be an even number', diff --git a/library/Rules/OneOf.php b/library/Rules/OneOf.php index f0442b8dd..567d5c0bf 100644 --- a/library/Rules/OneOf.php +++ b/library/Rules/OneOf.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rule; @@ -17,6 +18,7 @@ use function array_map; use function array_reduce; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'Only one of these rules must pass for {{name}}', 'Only one of these rules must not pass for {{name}}', diff --git a/library/Rules/PerfectSquare.php b/library/Rules/PerfectSquare.php index 353c0f37b..53b806661 100644 --- a/library/Rules/PerfectSquare.php +++ b/library/Rules/PerfectSquare.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function is_numeric; use function sqrt; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a perfect square number', '{{name}} must not be a perfect square number', diff --git a/library/Rules/Pesel.php b/library/Rules/Pesel.php index be145726c..6095ff8ba 100644 --- a/library/Rules/Pesel.php +++ b/library/Rules/Pesel.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_scalar; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid PESEL', '{{name}} must not be a valid PESEL', diff --git a/library/Rules/Phone.php b/library/Rules/Phone.php index ec02dea62..03e57d08a 100644 --- a/library/Rules/Phone.php +++ b/library/Rules/Phone.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use libphonenumber\NumberParseException; use libphonenumber\PhoneNumberUtil; use Respect\Validation\Exceptions\InvalidRuleConstructorException; @@ -21,6 +22,7 @@ use function class_exists; use function is_scalar; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid telephone number', '{{name}} must not be a valid telephone number', diff --git a/library/Rules/PhpLabel.php b/library/Rules/PhpLabel.php index b9e2cd3b4..21298dd13 100644 --- a/library/Rules/PhpLabel.php +++ b/library/Rules/PhpLabel.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_string; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid PHP label', '{{name}} must not be a valid PHP label', diff --git a/library/Rules/Pis.php b/library/Rules/Pis.php index 5dd58a8b1..b9ccd78fd 100644 --- a/library/Rules/Pis.php +++ b/library/Rules/Pis.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use function preg_match; use function preg_replace; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid PIS number', '{{name}} must not be a valid PIS number', diff --git a/library/Rules/PolishIdCard.php b/library/Rules/PolishIdCard.php index a510fdd06..791f020a0 100644 --- a/library/Rules/PolishIdCard.php +++ b/library/Rules/PolishIdCard.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -19,6 +20,7 @@ /** * @see https://en.wikipedia.org/wiki/Polish_identity_card */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid Polish Identity Card number', '{{name}} must not be a valid Polish Identity Card number', diff --git a/library/Rules/PortugueseNif.php b/library/Rules/PortugueseNif.php index 1f265d67e..5df64abb2 100644 --- a/library/Rules/PortugueseNif.php +++ b/library/Rules/PortugueseNif.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -25,6 +26,7 @@ /** * @see https://pt.wikipedia.org/wiki/N%C3%BAmero_de_identifica%C3%A7%C3%A3o_fiscal */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a Portuguese NIF', '{{name}} must not be a Portuguese NIF', diff --git a/library/Rules/Positive.php b/library/Rules/Positive.php index 8f7254207..626b47039 100644 --- a/library/Rules/Positive.php +++ b/library/Rules/Positive.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_numeric; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a positive number', '{{name}} must not be a positive number', diff --git a/library/Rules/PostalCode.php b/library/Rules/PostalCode.php index cc4afa1f0..495801102 100644 --- a/library/Rules/PostalCode.php +++ b/library/Rules/PostalCode.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; @@ -16,6 +17,7 @@ /** * @see http://download.geonames.org/export/dump/countryInfo.txt */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid postal code on {{countryCode}}', '{{name}} must not be a valid postal code on {{countryCode}}', diff --git a/library/Rules/PrimeNumber.php b/library/Rules/PrimeNumber.php index a26f050f6..7edb0269e 100644 --- a/library/Rules/PrimeNumber.php +++ b/library/Rules/PrimeNumber.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function is_numeric; use function sqrt; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a prime number', '{{name}} must not be a prime number', diff --git a/library/Rules/Printable.php b/library/Rules/Printable.php index bd2ad4784..e2fdce137 100644 --- a/library/Rules/Printable.php +++ b/library/Rules/Printable.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_print; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only printable characters', '{{name}} must not contain printable characters', diff --git a/library/Rules/Property.php b/library/Rules/Property.php index 90b1180c9..ea057540c 100644 --- a/library/Rules/Property.php +++ b/library/Rules/Property.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Helpers\CanExtractPropertyValue; use Respect\Validation\Result; use Respect\Validation\Rule; use Respect\Validation\Rules\Core\Binder; use Respect\Validation\Rules\Core\Wrapper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class Property extends Wrapper { use CanExtractPropertyValue; diff --git a/library/Rules/PropertyExists.php b/library/Rules/PropertyExists.php index b517df961..438b8a20f 100644 --- a/library/Rules/PropertyExists.php +++ b/library/Rules/PropertyExists.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use ReflectionObject; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -16,6 +17,7 @@ use function is_object; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be present', '{{name}} must not be present', diff --git a/library/Rules/PropertyOptional.php b/library/Rules/PropertyOptional.php index 27a9e2c6b..88cd90eda 100644 --- a/library/Rules/PropertyOptional.php +++ b/library/Rules/PropertyOptional.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Helpers\CanExtractPropertyValue; use Respect\Validation\Result; use Respect\Validation\Rule; use Respect\Validation\Rules\Core\Binder; use Respect\Validation\Rules\Core\Wrapper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class PropertyOptional extends Wrapper { use CanExtractPropertyValue; diff --git a/library/Rules/PublicDomainSuffix.php b/library/Rules/PublicDomainSuffix.php index e6442cb00..c46a503bd 100644 --- a/library/Rules/PublicDomainSuffix.php +++ b/library/Rules/PublicDomainSuffix.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Helpers\CanValidateUndefined; use Respect\Validation\Helpers\DomainInfo; use Respect\Validation\Message\Template; @@ -20,6 +21,7 @@ use function is_scalar; use function strtoupper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a public domain suffix', '{{name}} must not be a public domain suffix', diff --git a/library/Rules/Punct.php b/library/Rules/Punct.php index 9a2767585..28b30cb8a 100644 --- a/library/Rules/Punct.php +++ b/library/Rules/Punct.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_punct; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only punctuation characters', '{{name}} must not contain punctuation characters', diff --git a/library/Rules/Readable.php b/library/Rules/Readable.php index 4baa60094..5cdb25b20 100644 --- a/library/Rules/Readable.php +++ b/library/Rules/Readable.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Psr\Http\Message\StreamInterface; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use function is_readable; use function is_string; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be readable', '{{name}} must not be readable', diff --git a/library/Rules/Regex.php b/library/Rules/Regex.php index 2870358e3..1364d6739 100644 --- a/library/Rules/Regex.php +++ b/library/Rules/Regex.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -16,6 +17,7 @@ use function is_scalar; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must match the pattern `{{regex|raw}}`', '{{name}} must not match the pattern `{{regex|raw}}`', diff --git a/library/Rules/ResourceType.php b/library/Rules/ResourceType.php index 99268b001..2b545e187 100644 --- a/library/Rules/ResourceType.php +++ b/library/Rules/ResourceType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_resource; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a resource', '{{name}} must not be a resource', diff --git a/library/Rules/Roman.php b/library/Rules/Roman.php index d7400fc0c..7f9f421ca 100644 --- a/library/Rules/Roman.php +++ b/library/Rules/Roman.php @@ -9,9 +9,11 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid Roman numeral', '{{name}} must not be a valid Roman numeral', diff --git a/library/Rules/ScalarVal.php b/library/Rules/ScalarVal.php index 8cd8c9dd3..50524404b 100644 --- a/library/Rules/ScalarVal.php +++ b/library/Rules/ScalarVal.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_scalar; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a scalar value', '{{name}} must not be a scalar value', diff --git a/library/Rules/Size.php b/library/Rules/Size.php index 03605c11e..53d10479a 100644 --- a/library/Rules/Size.php +++ b/library/Rules/Size.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; use Respect\Validation\Exceptions\InvalidRuleConstructorException; @@ -23,6 +24,7 @@ use function is_string; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be between {{minSize}} and {{maxSize}}', '{{name}} must not be between {{minSize}} and {{maxSize}}', diff --git a/library/Rules/Slug.php b/library/Rules/Slug.php index f61e1622f..c47f618d5 100644 --- a/library/Rules/Slug.php +++ b/library/Rules/Slug.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function mb_strstr; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid slug', '{{name}} must not be a valid slug', diff --git a/library/Rules/Sorted.php b/library/Rules/Sorted.php index 2f6824efe..5979083e1 100644 --- a/library/Rules/Sorted.php +++ b/library/Rules/Sorted.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -20,6 +21,7 @@ use function is_string; use function str_split; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be sorted in ascending order', '{{name}} must not be sorted in ascending order', diff --git a/library/Rules/Space.php b/library/Rules/Space.php index c94a71fdf..c4831b8d2 100644 --- a/library/Rules/Space.php +++ b/library/Rules/Space.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_space; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only space characters', '{{name}} must not contain space characters', diff --git a/library/Rules/StartsWith.php b/library/Rules/StartsWith.php index b0f800f2c..500131b11 100644 --- a/library/Rules/StartsWith.php +++ b/library/Rules/StartsWith.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -19,6 +20,7 @@ use function mb_strpos; use function reset; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must start with {{startValue}}', '{{name}} must not start with {{startValue}}', diff --git a/library/Rules/StringType.php b/library/Rules/StringType.php index 879112bf9..de112cdad 100644 --- a/library/Rules/StringType.php +++ b/library/Rules/StringType.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_string; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a string', '{{name}} must not be a string', diff --git a/library/Rules/StringVal.php b/library/Rules/StringVal.php index 6685d2e80..6058987e7 100644 --- a/library/Rules/StringVal.php +++ b/library/Rules/StringVal.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function is_scalar; use function method_exists; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a string value', '{{name}} must not be a string value', diff --git a/library/Rules/SubdivisionCode.php b/library/Rules/SubdivisionCode.php index 5efb796f6..fdc810f3f 100644 --- a/library/Rules/SubdivisionCode.php +++ b/library/Rules/SubdivisionCode.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Exceptions\MissingComposerDependencyException; use Respect\Validation\Helpers\CanValidateUndefined; @@ -20,6 +21,7 @@ use function class_exists; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a subdivision code of {{countryName|trans}}', '{{name}} must not be a subdivision code of {{countryName|trans}}', diff --git a/library/Rules/Subset.php b/library/Rules/Subset.php index 801c4d777..3d7069aee 100644 --- a/library/Rules/Subset.php +++ b/library/Rules/Subset.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Result; use Respect\Validation\Rules\Core\Standard; @@ -16,6 +17,7 @@ use function array_diff; use function is_array; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be subset of {{superset}}', '{{name}} must not be subset of {{superset}}', diff --git a/library/Rules/SymbolicLink.php b/library/Rules/SymbolicLink.php index b7deaea64..59f2a7500 100644 --- a/library/Rules/SymbolicLink.php +++ b/library/Rules/SymbolicLink.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use SplFileInfo; @@ -16,6 +17,7 @@ use function is_link; use function is_string; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a symbolic link', '{{name}} must not be a symbolic link', diff --git a/library/Rules/Time.php b/library/Rules/Time.php index 886c87de7..161e65f67 100644 --- a/library/Rules/Time.php +++ b/library/Rules/Time.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Helpers\CanValidateDateTime; use Respect\Validation\Message\Template; @@ -20,6 +21,7 @@ use function preg_match; use function strtotime; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid time in the format {{sample}}', '{{name}} must not be a valid time in the format {{sample}}', diff --git a/library/Rules/Tld.php b/library/Rules/Tld.php index b117be5ec..0d7512253 100644 --- a/library/Rules/Tld.php +++ b/library/Rules/Tld.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -16,6 +17,7 @@ use function is_scalar; use function mb_strtoupper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid top-level domain name', '{{name}} must not be a valid top-level domain name', diff --git a/library/Rules/TrueVal.php b/library/Rules/TrueVal.php index 01d79146c..b70681070 100644 --- a/library/Rules/TrueVal.php +++ b/library/Rules/TrueVal.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use const FILTER_NULL_ON_FAILURE; use const FILTER_VALIDATE_BOOLEAN; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must evaluate to `true`', '{{name}} must not evaluate to `true`', diff --git a/library/Rules/UndefOr.php b/library/Rules/UndefOr.php index 8c2bae7d2..2938e2b08 100644 --- a/library/Rules/UndefOr.php +++ b/library/Rules/UndefOr.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Helpers\CanValidateUndefined; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -16,6 +17,7 @@ use function array_map; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( 'or must be undefined', 'and must not be undefined', diff --git a/library/Rules/Unique.php b/library/Rules/Unique.php index 13dd4342e..e3c047722 100644 --- a/library/Rules/Unique.php +++ b/library/Rules/Unique.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use const SORT_REGULAR; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must not contain duplicates', '{{name}} must contain duplicates', diff --git a/library/Rules/Uploaded.php b/library/Rules/Uploaded.php index 64a58373c..ee49c98b0 100644 --- a/library/Rules/Uploaded.php +++ b/library/Rules/Uploaded.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Psr\Http\Message\UploadedFileInterface; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use function is_scalar; use function is_uploaded_file; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be an uploaded file', '{{name}} must not be an uploaded file', diff --git a/library/Rules/Uppercase.php b/library/Rules/Uppercase.php index bc4e8f5fe..1b9c25e97 100644 --- a/library/Rules/Uppercase.php +++ b/library/Rules/Uppercase.php @@ -9,12 +9,14 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; use function is_string; use function mb_strtoupper; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must contain only uppercase letters', '{{name}} must not contain only uppercase letters', diff --git a/library/Rules/Url.php b/library/Rules/Url.php index 74dd38e53..16c9c4be8 100644 --- a/library/Rules/Url.php +++ b/library/Rules/Url.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Envelope; use const FILTER_VALIDATE_URL; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a URL', '{{name}} must not be a URL', diff --git a/library/Rules/Uuid.php b/library/Rules/Uuid.php index 8957a65c9..38ee6924a 100644 --- a/library/Rules/Uuid.php +++ b/library/Rules/Uuid.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -18,6 +19,7 @@ use function preg_match; use function sprintf; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid UUID', '{{name}} must not be a valid UUID', diff --git a/library/Rules/Version.php b/library/Rules/Version.php index 35d084497..d1750c59f 100644 --- a/library/Rules/Version.php +++ b/library/Rules/Version.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -18,6 +19,7 @@ /** * @see http://semver.org/ */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a version', '{{name}} must not be a version', diff --git a/library/Rules/VideoUrl.php b/library/Rules/VideoUrl.php index 7ed7c9de2..758f48594 100644 --- a/library/Rules/VideoUrl.php +++ b/library/Rules/VideoUrl.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Exceptions\InvalidRuleConstructorException; use Respect\Validation\Message\Template; use Respect\Validation\Result; @@ -19,6 +20,7 @@ use function mb_strtolower; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be a valid video URL', '{{name}} must not be a valid video URL', diff --git a/library/Rules/Vowel.php b/library/Rules/Vowel.php index dc220edc5..47cf969d6 100644 --- a/library/Rules/Vowel.php +++ b/library/Rules/Vowel.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function preg_match; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must consist of vowels only', '{{name}} must not consist of vowels only', diff --git a/library/Rules/When.php b/library/Rules/When.php index f9a356ff6..558bb6987 100644 --- a/library/Rules/When.php +++ b/library/Rules/When.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Result; use Respect\Validation\Rule; use Respect\Validation\Rules\Core\Binder; use Respect\Validation\Rules\Core\Standard; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class When extends Standard { private readonly Rule $else; diff --git a/library/Rules/Writable.php b/library/Rules/Writable.php index 7d00b06c9..d9a1f78e3 100644 --- a/library/Rules/Writable.php +++ b/library/Rules/Writable.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Psr\Http\Message\StreamInterface; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -17,6 +18,7 @@ use function is_string; use function is_writable; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be writable', '{{name}} must not be writable', diff --git a/library/Rules/Xdigit.php b/library/Rules/Xdigit.php index 30a8ed94f..9cf828c0f 100644 --- a/library/Rules/Xdigit.php +++ b/library/Rules/Xdigit.php @@ -9,11 +9,13 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\FilteredString; use function ctype_xdigit; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must only contain hexadecimal digits', '{{name}} must not only contain hexadecimal digits', diff --git a/library/Rules/Yes.php b/library/Rules/Yes.php index 8e6c6d885..75b45a135 100644 --- a/library/Rules/Yes.php +++ b/library/Rules/Yes.php @@ -9,6 +9,7 @@ namespace Respect\Validation\Rules; +use Attribute; use Respect\Validation\Message\Template; use Respect\Validation\Rules\Core\Simple; @@ -18,6 +19,7 @@ use const YESEXPR; +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( '{{name}} must be similar to "Yes"', '{{name}} must not be similar to "Yes"', diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 73346a727..3257a8c0d 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -18,6 +18,14 @@ tests/integration/ + + + + + + + + tests/integration/ diff --git a/tests/fixtures/data-provider.php b/tests/fixtures/data-provider.php index 607a8de15..80d3df00d 100644 --- a/tests/fixtures/data-provider.php +++ b/tests/fixtures/data-provider.php @@ -7,6 +7,7 @@ declare(strict_types=1); +use Respect\Validation\Test\Stubs\WithAttributes; use Respect\Validation\Test\Stubs\WithProperties; use Respect\Validation\Test\Stubs\WithStaticProperties; use Respect\Validation\Test\Stubs\WithUninitialized; @@ -98,45 +99,55 @@ // Array values 'ArrayObject' => [ 'value' => [new ArrayObject([1, 2, 3])], - 'tags' => ['objectType', 'iterableType', 'ArrayObject', 'countable'], + 'tags' => ['objectType', 'iterableType', 'ArrayObject', 'countable', 'withoutAttributes'], ], 'empty ArrayObject' => [ 'value' => [new ArrayObject([])], - 'tags' => ['objectType', 'iterableType', 'ArrayObject', 'countable', 'empty'], + 'tags' => ['objectType', 'iterableType', 'ArrayObject', 'countable', 'empty', 'withoutAttributes'], ], // Iterable types 'generator' => [ 'value' => [(static fn() => yield 7)()], // phpcs:ignore - 'tags' => ['objectType', 'iterableType', 'generator'], + 'tags' => ['objectType', 'iterableType', 'generator', 'withoutAttributes'], ], 'empty generator' => [ 'value' => [(static fn() => yield from [])()], - 'tags' => ['objectType', 'iterableType', 'generator', 'empty'], + 'tags' => ['objectType', 'iterableType', 'generator', 'empty', 'withoutAttributes'], ], // Callable types 'closure' => [ 'value' => [static fn() => 'foo'], - 'tags' => ['objectType', 'callable'], + 'tags' => ['objectType', 'callable', 'withoutAttributes'], ], // Object types 'object' => [ 'value' => [new stdClass()], - 'tags' => ['objectType'], + 'tags' => ['objectType', 'withoutAttributes'], ], 'object with properties' => [ 'value' => [new WithProperties()], - 'tags' => ['objectType'], + 'tags' => ['objectType', 'withoutAttributes'], ], 'object with uninitialized properties' => [ 'value' => [new WithUninitialized()], - 'tags' => ['objectType'], + 'tags' => ['objectType', 'withoutAttributes'], ], 'object with static properties' => [ 'value' => [new WithStaticProperties()], - 'tags' => ['objectType'], + 'tags' => ['objectType', 'withoutAttributes'], + ], + 'object with Rule attributes' => [ + 'value' => [new WithAttributes('John Doe', 'john.doe@gmail.com', '1912-06-23')], + 'tags' => ['objectType', 'withAttributes'], + ], + 'anonymous class' => [ + 'value' => [new class { + }, + ], + 'tags' => ['objectType', 'withoutAttributes'], ], // Resource types diff --git a/tests/integration/assert-with-attributes.phpt b/tests/integration/assert-with-properties.phpt similarity index 100% rename from tests/integration/assert-with-attributes.phpt rename to tests/integration/assert-with-properties.phpt diff --git a/tests/integration/rules/attributes.phpt b/tests/integration/rules/attributes.phpt new file mode 100644 index 000000000..236d1aeb8 --- /dev/null +++ b/tests/integration/rules/attributes.phpt @@ -0,0 +1,78 @@ +--FILE-- + [v::attributes(), new WithAttributes('', 'john.doe@gmail.com', '2024-06-23')], + 'Inverted' => [v::attributes(), new WithAttributes('John Doe', 'john.doe@gmail.com', '2024-06-23', '+1234567890')], + 'Not an object' => [v::attributes(), []], + 'Nullable' => [v::attributes(), new WithAttributes('John Doe', 'john.doe@gmail.com', '2024-06-23', 'not a phone number')], + 'Multiple attributes, all failed' => [v::attributes(), new WithAttributes('', 'not an email', 'not a date', 'not a phone number')], + 'Multiple attributes, one failed' => [v::attributes(), new WithAttributes('John Doe', 'john.doe@gmail.com', '22 years ago')], +]); +?> +--EXPECTF-- +Default +⎺⎺⎺⎺⎺⎺⎺ +name must not be empty +- name must not be empty +[ + 'name' => 'name must not be empty', +] + +Inverted +⎺⎺⎺⎺⎺⎺⎺⎺ +phone must be a valid telephone number or must be null +- phone must be a valid telephone number or must be null +[ + 'phone' => 'phone must be a valid telephone number or must be null', +] + +Not an object +⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ +`[]` must be an object +- `[]` must be an object +[ + 'attributes' => '`[]` must be an object', +] + +Nullable +⎺⎺⎺⎺⎺⎺⎺⎺ +phone must be a valid telephone number or must be null +- phone must be a valid telephone number or must be null +[ + 'phone' => 'phone must be a valid telephone number or must be null', +] + +Multiple attributes, all failed +⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ +name must not be empty +- All of the required rules must pass for `Respect\Validation\Test\Stubs\WithAttributes { +$name="" +$email="not an email" +$birthdate="not a date" +$phone ... }` + - name must not be empty + - email must be a valid email address + - All of the required rules must pass for birthdate + - birthdate must be a valid date in the format "%d-%d-%d" + - For comparison with now, birthdate must be a valid datetime + - phone must be a valid telephone number or must be null +[ + '__root__' => 'All of the required rules must pass for `Respect\\Validation\\Test\\Stubs\\WithAttributes { +$name="" +$email="not an email" +$birthdate="not a date" +$phone ... }`', + 'name' => 'name must not be empty', + 'email' => 'email must be a valid email address', + 'birthdate' => [ + '__root__' => 'All of the required rules must pass for birthdate', + 'date' => 'birthdate must be a valid date in the format "%d-%d-%d"', + 'dateTimeDiffLessThanOrEqual' => 'For comparison with now, birthdate must be a valid datetime', + ], + 'phone' => 'phone must be a valid telephone number or must be null', +] + +Multiple attributes, one failed +⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ +birthdate must be a valid date in the format "%d-%d-%d" +- birthdate must be a valid date in the format "%d-%d-%d" +[ + 'birthdate' => 'birthdate must be a valid date in the format "%d-%d-%d"', +] diff --git a/tests/library/Stubs/WithAttributes.php b/tests/library/Stubs/WithAttributes.php new file mode 100644 index 000000000..19f49a6fe --- /dev/null +++ b/tests/library/Stubs/WithAttributes.php @@ -0,0 +1,34 @@ + + * SPDX-License-Identifier: MIT + */ + +declare(strict_types=1); + +namespace Respect\Validation\Test\Stubs; + +use Respect\Validation\Rules\Date; +use Respect\Validation\Rules\DateTimeDiff; +use Respect\Validation\Rules\Email; +use Respect\Validation\Rules\LessThanOrEqual; +use Respect\Validation\Rules\NotEmpty; +use Respect\Validation\Rules\Phone; + +final class WithAttributes +{ + public function __construct( + #[NotEmpty] + public string $name, + #[Email] + public string $email, + #[Date('Y-m-d')] + #[DateTimeDiff('years', new LessThanOrEqual(25))] + public string $birthdate, + #[Phone] + public ?string $phone = null, + public ?string $address = null, + ) { + } +} diff --git a/tests/library/TestCase.php b/tests/library/TestCase.php index e1a3281d3..6ed17877c 100644 --- a/tests/library/TestCase.php +++ b/tests/library/TestCase.php @@ -146,6 +146,16 @@ public static function providerForNonArrayTypes(): DataProvider return self::providerForAnyValues()->without('arrayType'); } + public static function providerForNonObjectTypes(): DataProvider + { + return self::providerForAnyValues()->without('objectType'); + } + + public static function providerForObjectTypesWithoutAttributes(): DataProvider + { + return self::providerForAnyValues()->with('objectType')->without('withAttributes'); + } + public static function providerForNonArrayValues(): DataProvider { return self::providerForAnyValues()->without('arrayType', 'ArrayObject'); diff --git a/tests/unit/Rules/AttributesTest.php b/tests/unit/Rules/AttributesTest.php new file mode 100644 index 000000000..f52b5728e --- /dev/null +++ b/tests/unit/Rules/AttributesTest.php @@ -0,0 +1,79 @@ + + * SPDX-License-Identifier: MIT + */ + +declare(strict_types=1); + +namespace Respect\Validation\Rules; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Test; +use Respect\Validation\Test\Stubs\WithAttributes; +use Respect\Validation\Test\TestCase; + +#[Group(' rule')] +#[CoversClass(Attributes::class)] +final class AttributesTest extends TestCase +{ + #[Test] + #[DataProvider('providerForNonObjectTypes')] + public function shouldNotEvaluateNonObjects(mixed $input): void + { + self::assertInvalidInput(new Attributes(), $input); + } + + #[Test] + #[DataProvider('providerForObjectTypesWithoutAttributes')] + public function shouldEvaluateObjectsWithoutPhpAttributes(object $input): void + { + self::assertValidInput(new Attributes(), $input); + } + + #[Test] + #[DataProvider('providerForObjectsWithValidPropertyValues')] + public function shouldNotEvaluateObjectsWithValidPropertyValues(object $input): void + { + self::assertValidInput(new Attributes(), $input); + } + + #[Test] + #[DataProvider('providerForObjectsWithInvalidPropertyValues')] + public function shouldNotEvaluateObjectsWithInvalidPropertyValues(object $input): void + { + self::assertInvalidInput(new Attributes(), $input); + } + + /** @return array */ + public static function providerForObjectsWithValidPropertyValues(): array + { + return [ + 'All' => [ + new WithAttributes( + 'John Doe', + 'john.doe@gmail.com', + '2020-06-23', + '+31206241111', + 'Amstel 1 1011 PN AMSTERDAM Noord-Holland' + ), + ], + 'Only required' => [new WithAttributes('Jane Doe', 'janedoe@yahoo.com', '2017-11-30')], + ]; + } + + /** @return array */ + public static function providerForObjectsWithInvalidPropertyValues(): array + { + return [ + [new WithAttributes('', 'not an email', 'not a date', 'not a phone number')], + [new WithAttributes('', 'john.doe@gmail.com', '1912-06-23', '+1234567890')], + [new WithAttributes('John Doe', 'not an email', '1912-06-23', '+1234567890')], + [new WithAttributes('John Doe', 'john.doe@gmail.com', 'not a date', '+1234567890')], + [new WithAttributes('John Doe', 'john.doe@gmail.com', '1912-06-23', 'not a phone number')], + ]; + } +}