-
Notifications
You must be signed in to change notification settings - Fork 773
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow to use certain rules as class attributes
There are a few cases in which we want to validate the object as a whole, and that validation could be attached to the class as a PHP attribute. This commit enables that capability and changes a few rules to be class attributes.
- Loading branch information
1 parent
848724e
commit 94d53df
Showing
17 changed files
with
100 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,20 +7,24 @@ Validates the PHP attributes defined in the properties of the input. | |
Example of object: | ||
|
||
```php | ||
use Respect\Validation\Rules; | ||
use Respect\Validation\Rules as Rule; | ||
|
||
#[Rule\AnyOf( | ||
new Rule\Property('email', new Rule\NotUndef()), | ||
new Rule\Property('phone', new Rule\NotUndef()), | ||
)] | ||
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 | ||
#[Rule\NotEmpty] | ||
public string $name, | ||
#[Rule\Date('Y-m-d')] | ||
#[Rule\DateTimeDiff('years', new Rule\LessThanOrEqual(25))] | ||
public string $birthdate, | ||
#[Rule\Email] | ||
public ?string $email = null, | ||
#[Rule\Phone] | ||
public ?string $phone = null, | ||
) { | ||
} | ||
} | ||
|
@@ -29,33 +33,39 @@ final class Person | |
Here is how you can validate the attributes of the object: | ||
|
||
```php | ||
v::attributes()->assert(new Person('John Doe', '[email protected]', '2020-06-23')); | ||
v::attributes()->assert(new Person('John Doe', '2020-06-23', '[email protected]')); | ||
// No exception | ||
|
||
v::attributes()->assert(new Person('John Doe', '[email protected]', '2020-06-23', '+31 20 624 1111')); | ||
v::attributes()->assert(new Person('John Doe', '2020-06-23', '[email protected]', '+12024561111')); | ||
// No exception | ||
|
||
v::attributes()->assert(new Person('', '[email protected]', '2020-06-23', '+1234567890')); | ||
// Message: name must not be empty | ||
v::attributes()->assert(new Person('', '2020-06-23', '[email protected]', '+12024561111')); | ||
// 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', 'not a date', '[email protected]', '+12024561111')); | ||
// Message: `.birthdate` must be a valid date in the format "2005-12-30" | ||
|
||
v::attributes()->assert(new Person('John Doe', '[email protected]', 'not a date', '+1234567890')); | ||
// Message: birthdate must be a valid date in the format "2005-12-30" | ||
v::attributes()->assert(new Person('John Doe', '2020-06-23', 'not an email', '+12024561111')); | ||
// Message: `.email` must be a valid email address or must be null | ||
|
||
v::attributes()->assert(new Person('John Doe', '[email protected]', '2020-06-23', 'not a phone number')); | ||
// Message: phone must be a valid telephone number or must be null | ||
v::attributes()->assert(new Person('John Doe', '2020-06-23', '[email protected]', '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')); | ||
v::attributes()->assert(new Person('John Doe', '2020-06-23')); | ||
// Full message: | ||
// - `Person { +$name="" +$email="not an email" +$birthdate="not a date" +$phone="not a phone number" }` must pass all the rules | ||
// - name must not be empty | ||
// - email must be a valid email address | ||
// - birthdate must pass all the rules | ||
// - 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 | ||
// - `Person { +$name="John Doe" +$birthdate="2020-06-23" +$email=null +$phone=null +$address=null }` must pass at least one of the rules | ||
// - `.email` must be defined | ||
// - `.phone` must be defined | ||
|
||
v::attributes()->assert(new Person('', 'not a date', 'not an email', 'not a phone number')); | ||
// Full message: | ||
// - `Person { +$name="" +$birthdate="not a date" +$email="not an email" +$phone="not a phone number" +$address=null }` must pass the rules | ||
// - `.name` must not be empty | ||
// - `.birthdate` must pass all the rules | ||
// - `.birthdate` must be a valid date in the format "2005-12-30" | ||
// - For comparison with now, `.birthdate` must be a valid datetime | ||
// - `.email` must be a valid email address or must be null | ||
// - `.phone` must be a valid telephone number or must be null | ||
``` | ||
|
||
## Caveats | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,14 +10,14 @@ | |
use Respect\Validation\Test\Stubs\WithAttributes; | ||
|
||
test('Default', expectAll( | ||
fn() => v::attributes()->assert(new WithAttributes('', '[email protected]', '2024-06-23')), | ||
fn() => v::attributes()->assert(new WithAttributes('', '2024-06-23', '[email protected]')), | ||
'`.name` must not be empty', | ||
'- `.name` must not be empty', | ||
['name' => '`.name` must not be empty'], | ||
)); | ||
|
||
test('Inverted', expectAll( | ||
fn() => v::attributes()->assert(new WithAttributes('John Doe', '[email protected]', '2024-06-23', '+1234567890')), | ||
fn() => v::attributes()->assert(new WithAttributes('John Doe', '2024-06-23', '[email protected]', '+1234567890')), | ||
'`.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'], | ||
|
@@ -31,39 +31,56 @@ | |
)); | ||
|
||
test('Nullable', expectAll( | ||
fn() => v::attributes()->assert(new WithAttributes('John Doe', '[email protected]', '2024-06-23', 'not a phone number')), | ||
fn() => v::attributes()->assert(new WithAttributes('John Doe', '2024-06-23', '[email protected]', 'not a phone number')), | ||
'`.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'], | ||
)); | ||
|
||
test('Multiple attributes, all failed', expectAll( | ||
fn() => v::attributes()->assert(new WithAttributes('', 'not an email', 'not a date', 'not a phone number')), | ||
fn() => v::attributes()->assert(new WithAttributes('', 'not a date', 'not an email', 'not a phone number')), | ||
'`.name` must not be empty', | ||
<<<'FULL_MESSAGE' | ||
- `Respect\Validation\Test\Stubs\WithAttributes { +$name="" +$email="not an email" +$birthdate="not a date" +$phone ... }` must pass all the rules | ||
- `Respect\Validation\Test\Stubs\WithAttributes { +$name="" +$birthdate="not a date" +$email="not an email" +$phone ... }` must pass the rules | ||
- `.name` must not be empty | ||
- `.email` must be a valid email address | ||
- `.birthdate` must pass all the rules | ||
- `.birthdate` must be a valid date in the format "2005-12-30" | ||
- For comparison with now, `.birthdate` must be a valid datetime | ||
- `.email` must be a valid email address or must be null | ||
- `.phone` must be a valid telephone number or must be null | ||
FULL_MESSAGE, | ||
[ | ||
'__root__' => '`Respect\Validation\Test\Stubs\WithAttributes { +$name="" +$email="not an email" +$birthdate="not a date" +$phone ... }` must pass all the rules', | ||
'__root__' => '`Respect\Validation\Test\Stubs\WithAttributes { +$name="" +$birthdate="not a date" +$email="not an email" +$phone ... }` must pass the rules', | ||
'name' => '`.name` must not be empty', | ||
'email' => '`.email` must be a valid email address', | ||
'birthdate' => [ | ||
'__root__' => '`.birthdate` must pass all the rules', | ||
'date' => '`.birthdate` must be a valid date in the format "2005-12-30"', | ||
'dateTimeDiffLessThanOrEqual' => 'For comparison with now, `.birthdate` must be a valid datetime', | ||
], | ||
'email' => '`.email` must be a valid email address or must be null', | ||
'phone' => '`.phone` must be a valid telephone number or must be null', | ||
], | ||
)); | ||
|
||
test('Failed attributes on the class', expectAll( | ||
fn() => v::attributes()->assert(new WithAttributes('John Doe', '2024-06-23')), | ||
'`.email` must be defined', | ||
<<<'FULL_MESSAGE' | ||
- `Respect\Validation\Test\Stubs\WithAttributes { +$name="John Doe" +$birthdate="2024-06-23" +$email=null +$phone=n ... }` must pass at least one of the rules | ||
- `.email` must be defined | ||
- `.phone` must be defined | ||
FULL_MESSAGE, | ||
[ | ||
'anyOf' => [ | ||
'__root__' => '`Respect\Validation\Test\Stubs\WithAttributes { +$name="John Doe" +$birthdate="2024-06-23" +$email=null +$phone=n ... }` must pass at least one of the rules', | ||
'email' => '`.email` must be defined', | ||
'phone' => '`.phone` must be defined', | ||
], | ||
], | ||
)); | ||
|
||
test('Multiple attributes, one failed', expectAll( | ||
fn() => v::attributes()->assert(new WithAttributes('John Doe', '[email protected]', '22 years ago')), | ||
fn() => v::attributes()->assert(new WithAttributes('John Doe', '22 years ago', '[email protected]')), | ||
'`.birthdate` must be a valid date in the format "2005-12-30"', | ||
'- `.birthdate` must be a valid date in the format "2005-12-30"', | ||
['birthdate' => '`.birthdate` must be a valid date in the format "2005-12-30"'], | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,7 +140,7 @@ | |
'tags' => ['objectType', 'withoutAttributes'], | ||
], | ||
'object with Rule attributes' => [ | ||
'value' => [new WithAttributes('John Doe', '[email protected]', '1912-06-23')], | ||
'value' => [new WithAttributes('John Doe', '1912-06-23', '[email protected]')], | ||
'tags' => ['objectType', 'withAttributes'], | ||
], | ||
'anonymous class' => [ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,25 +55,26 @@ public static function providerForObjectsWithValidPropertyValues(): array | |
'All' => [ | ||
new WithAttributes( | ||
'John Doe', | ||
'[email protected]', | ||
'2020-06-23', | ||
'[email protected]', | ||
'+31206241111', | ||
'Amstel 1 1011 PN AMSTERDAM Noord-Holland' | ||
), | ||
], | ||
'Only required' => [new WithAttributes('Jane Doe', '[email protected]', '2017-11-30')], | ||
'Only required' => [new WithAttributes('Jane Doe', '2017-11-30', '[email protected]')], | ||
]; | ||
} | ||
|
||
/** @return array<array{object}> */ | ||
public static function providerForObjectsWithInvalidPropertyValues(): array | ||
{ | ||
return [ | ||
[new WithAttributes('', 'not an email', 'not a date', 'not a phone number')], | ||
[new WithAttributes('', '[email protected]', '1912-06-23', '+1234567890')], | ||
[new WithAttributes('John Doe', 'not an email', '1912-06-23', '+1234567890')], | ||
[new WithAttributes('John Doe', '[email protected]', 'not a date', '+1234567890')], | ||
[new WithAttributes('John Doe', '[email protected]', '1912-06-23', 'not a phone number')], | ||
[new WithAttributes('Jane Doe', '2017-11-30')], | ||
[new WithAttributes('', 'not a date', 'not an email', 'not a phone number')], | ||
[new WithAttributes('', '1912-06-23', '[email protected]', '+1234567890')], | ||
[new WithAttributes('John Doe', '1912-06-23', 'not an email', '+1234567890')], | ||
[new WithAttributes('John Doe', 'not a date', '[email protected]', '+1234567890')], | ||
[new WithAttributes('John Doe', '1912-06-23', '[email protected]', 'not a phone number')], | ||
]; | ||
} | ||
} |