Skip to content

Commit a0d6355

Browse files
committed
Update some templates and improve tests
Some templates were a bit confusing, and I would like to favour adding the `{{name}}` at the beginning of the templates as it helps when reading nested messages. I also deleted the regression tests for issue #1348, because it's a non-issue, actually. The best approach to that problem is indeed using `When` insteaf of `OneOf`.
1 parent a8ae57f commit a0d6355

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+435
-240
lines changed

docs/03-handling-exceptions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ try {
1919
The code above generates the following output:
2020

2121
```no-highlight
22-
- All the required rules must pass for "The Respect Panda"
22+
- "The Respect Panda" must pass all the rules
2323
- "The Respect Panda" must contain only letters (a-z) and digits (0-9)
2424
- "The Respect Panda" must contain only lowercase letters
2525
```
@@ -44,7 +44,7 @@ The code above generates the following output:
4444
```no-highlight
4545
Array
4646
(
47-
[__root__] => All the required rules must pass for "The Respect Panda"
47+
[__root__] => "The Respect Panda" must pass all the rules
4848
[alnum] => "The Respect Panda" must contain only letters (a-z) and digits (0-9)
4949
[lowercase] => "The Respect Panda" must contain only lowercase letters
5050
)

docs/rules/AllOf.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,21 @@ v::allOf(v::intVal(), v::positive())->isValid(15); // true
1212

1313
### `AllOf::TEMPLATE_SOME`
1414

15-
| Mode | Template |
16-
|------------|----------------------------------------|
17-
| `default` | These rules must pass for {{name}} |
18-
| `inverted` | These rules must not pass for {{name}} |
15+
Used when some rules must be failed.
1916

20-
### `AllOf::TEMPLATE_NONE`
17+
| Mode | Template |
18+
|------------|------------------------------|
19+
| `default` | {{name}} must pass the rules |
20+
| `inverted` | {{name}} must pass the rules |
2121

22-
| Mode | Template |
23-
|------------|-----------------------------------------------|
24-
| `default` | All the required rules must pass for {{name}} |
25-
| `inverted` | None of these rules must pass for {{name}} |
22+
### `AllOf::TEMPLATE_ALL`
23+
24+
Used when all rules have failed.
25+
26+
| Mode | Template |
27+
|------------|----------------------------------|
28+
| `default` | {{name}} must pass all the rules |
29+
| `inverted` | {{name}} must pass all the rules |
2630

2731
## Template placeholders
2832

docs/rules/AnyOf.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ so `AnyOf()` returns true.
1717

1818
### `AnyOf::TEMPLATE_STANDARD`
1919

20-
| Mode | Template |
21-
|------------|--------------------------------------------------------|
22-
| `default` | At least one of these rules must pass for {{name}} |
23-
| `inverted` | At least one of these rules must not pass for {{name}} |
20+
| Mode | Template |
21+
|------------|----------------------------------------------|
22+
| `default` | {{name}} must pass at least one of the rules |
23+
| `inverted` | {{name}} must pass at least one of the rules |
2424

2525
## Template placeholders
2626

docs/rules/Attributes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ v::attributes()->assert(new Person('John Doe', '[email protected]', '2020-06-23
4949

5050
v::attributes()->assert(new Person('', 'not an email', 'not a date', 'not a phone number'));
5151
// Full message:
52-
// - All the required rules must pass for `Person { +$name="" +$email="not an email" +$birthdate="not a date" +$phone="not a phone number" }`
52+
// - `Person { +$name="" +$email="not an email" +$birthdate="not a date" +$phone="not a phone number" }` must pass all the rules
5353
// - name must not be empty
5454
// - email must be a valid email address
55-
// - All the required rules must pass for birthdate
55+
// - birthdate must pass all the rules
5656
// - birthdate must be a valid date in the format "2005-12-30"
5757
// - For comparison with now, birthdate must be a valid datetime
5858
// - phone must be a valid telephone number or must be null

docs/rules/NoneOf.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,23 @@ In the sample above, 'foo' isn't a integer nor a float, so noneOf returns true.
1515

1616
## Templates
1717

18-
### `NoneOf::TEMPLATE_STANDARD`
18+
### `NoneOf::TEMPLATE_SOME`
1919

20-
| Mode | Template |
21-
|------------|--------------------------------------------|
22-
| `default` | None of these rules must pass for {{name}} |
23-
| `inverted` | All of these rules must pass for {{name}} |
20+
Used when some rules have passed.
21+
22+
| Mode | Template |
23+
|------------|------------------------------|
24+
| `default` | {{name}} must pass the rules |
25+
| `inverted` | {{name}} must pass the rules |
26+
27+
### `NoneOf::TEMPLATE_ALL`
28+
29+
Used when all rules have passed.
30+
31+
| Mode | Template |
32+
|------------|----------------------------------|
33+
| `default` | {{name}} must pass all the rules |
34+
| `inverted` | {{name}} must pass all the rules |
2435

2536
## Template placeholders
2637

docs/rules/OneOf.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@ character, one or the other, but not neither nor both.
1616

1717
## Templates
1818

19-
### `OneOf::TEMPLATE_STANDARD`
19+
### `OneOf::TEMPLATE_NONE`
2020

21-
| Mode | Template |
22-
|------------|----------------------------------------------------|
23-
| `default` | Only one of these rules must pass for {{name}} |
24-
| `inverted` | Only one of these rules must not pass for {{name}} |
21+
Used when none of the rules have passed.
22+
23+
| Mode | Template |
24+
|------------|-------------------------------------|
25+
| `default` | {{name}} must pass one of the rules |
26+
| `inverted` | {{name}} must pass one of the rules |
27+
28+
### `OneOf::TEMPLATE_MORE_THAN_ONE`
29+
30+
Used when more than one rule has passed.
31+
32+
| Mode | Template |
33+
|------------|------------------------------------------|
34+
| `default` | {{name}} must pass only one of the rules |
35+
| `inverted` | {{name}} must pass only one of the rules |
2536

2637
## Template placeholders
2738

library/Rules/AllOf.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@
2222

2323
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
2424
#[Template(
25-
'These rules must pass for {{name}}',
26-
'These rules must not pass for {{name}}',
25+
'{{name}} must pass the rules',
26+
'{{name}} must pass the rules',
2727
self::TEMPLATE_SOME,
2828
)]
2929
#[Template(
30-
'All the required rules must pass for {{name}}',
31-
'None of these rules must pass for {{name}}',
32-
self::TEMPLATE_NONE,
30+
'{{name}} must pass all the rules',
31+
'{{name}} must pass all the rules',
32+
self::TEMPLATE_ALL,
3333
)]
3434
final class AllOf extends Composite
3535
{
36-
public const TEMPLATE_NONE = '__none__';
36+
public const TEMPLATE_ALL = '__all__';
3737
public const TEMPLATE_SOME = '__some__';
3838

3939
public function evaluate(mixed $input): Result
@@ -43,7 +43,7 @@ public function evaluate(mixed $input): Result
4343
$failed = array_filter($children, static fn (Result $result): bool => !$result->isValid);
4444
$template = self::TEMPLATE_SOME;
4545
if (count($children) === count($failed)) {
46-
$template = self::TEMPLATE_NONE;
46+
$template = self::TEMPLATE_ALL;
4747
}
4848

4949
return (new Result($valid, $input, $this, [], $template))->withChildren(...$children);

library/Rules/AnyOf.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020

2121
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
2222
#[Template(
23-
'At least one of these rules must pass for {{name}}',
24-
'At least one of these rules must not pass for {{name}}',
23+
'{{name}} must pass at least one of the rules',
24+
'{{name}} must pass at least one of the rules',
2525
)]
2626
final class AnyOf extends Composite
2727
{

library/Rules/NoneOf.php

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,37 @@
1515
use Respect\Validation\Rule;
1616
use Respect\Validation\Rules\Core\Composite;
1717

18+
use function array_filter;
1819
use function array_map;
1920
use function array_reduce;
21+
use function count;
2022

2123
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
2224
#[Template(
23-
'None of these rules must pass for {{name}}',
24-
'All of these rules must pass for {{name}}',
25+
'{{name}} must pass the rules',
26+
'{{name}} must pass the rules',
27+
self::TEMPLATE_SOME,
28+
)]
29+
#[Template(
30+
'{{name}} must pass all the rules',
31+
'{{name}} must pass all the rules',
32+
self::TEMPLATE_ALL,
2533
)]
2634
final class NoneOf extends Composite
2735
{
36+
public const TEMPLATE_ALL = '__all__';
37+
public const TEMPLATE_SOME = '__some__';
38+
2839
public function evaluate(mixed $input): Result
2940
{
30-
$children = array_map(
31-
static fn (Rule $rule) => $rule->evaluate($input)->withInvertedMode(),
32-
$this->rules
33-
);
41+
$children = array_map(static fn (Rule $rule) => $rule->evaluate($input)->withInvertedMode(), $this->rules);
3442
$valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry && $result->isValid, true);
43+
$failed = array_filter($children, static fn (Result $result): bool => !$result->isValid);
44+
$template = self::TEMPLATE_SOME;
45+
if (count($children) === count($failed)) {
46+
$template = self::TEMPLATE_ALL;
47+
}
3548

36-
return (new Result($valid, $input, $this))->withChildren(...$children);
49+
return (new Result($valid, $input, $this, [], $template))->withChildren(...$children);
3750
}
3851
}

library/Rules/OneOf.php

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,45 @@
1515
use Respect\Validation\Rule;
1616
use Respect\Validation\Rules\Core\Composite;
1717

18+
use function array_filter;
1819
use function array_map;
1920
use function array_reduce;
21+
use function count;
22+
use function usort;
2023

2124
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
2225
#[Template(
23-
'Only one of these rules must pass for {{name}}',
24-
'Only one of these rules must not pass for {{name}}',
26+
'{{name}} must pass one of the rules',
27+
'{{name}} must pass one of the rules',
28+
self::TEMPLATE_NONE,
29+
)]
30+
#[Template(
31+
'{{name}} must pass only one of the rules',
32+
'{{name}} must pass only one of the rules',
33+
self::TEMPLATE_MORE_THAN_ONE,
2534
)]
2635
final class OneOf extends Composite
2736
{
37+
public const TEMPLATE_NONE = '__none__';
38+
public const TEMPLATE_MORE_THAN_ONE = '__more_than_one__';
39+
2840
public function evaluate(mixed $input): Result
2941
{
3042
$children = array_map(static fn (Rule $rule) => $rule->evaluate($input), $this->rules);
3143
$valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry xor $result->isValid, false);
44+
$validChildren = array_filter($children, static fn (Result $result): bool => $result->isValid);
45+
$template = self::TEMPLATE_NONE;
46+
if (count($validChildren) > 1) {
47+
// Put the failed children at the top, so it makes sense in the main error message
48+
usort($children, static fn (Result $a, Result $b): int => $a->isValid <=> $b->isValid);
49+
50+
$template = self::TEMPLATE_MORE_THAN_ONE;
51+
$children = array_map(
52+
static fn (Result $child) => $child->isValid ? $child->withInvertedValidation() : $child,
53+
$children
54+
);
55+
}
3256

33-
return (new Result($valid, $input, $this))->withChildren(...$children);
57+
return (new Result($valid, $input, $this, [], $template))->withChildren(...$children);
3458
}
3559
}

tests/feature/AssertWithKeysTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@
3737
],
3838
]),
3939
<<<'FULL_MESSAGE'
40-
- All the required rules must pass for the given data
41-
- All the required rules must pass for mysql
40+
- the given data must pass all the rules
41+
- mysql must pass all the rules
4242
- host must be a string
4343
- user must be present
4444
- password must be present
4545
- schema must be a string
46-
- All the required rules must pass for postgresql
46+
- postgresql must pass all the rules
4747
- host must be present
4848
- user must be a string
4949
- password must be a string

tests/feature/AssertWithPropertiesTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ function (): void {
4545
->assert($object);
4646
},
4747
<<<'FULL_MESSAGE'
48-
- All the required rules must pass for the given data
49-
- These rules must pass for mysql
48+
- the given data must pass all the rules
49+
- mysql must pass the rules
5050
- host must be a string
51-
- These rules must pass for postgresql
51+
- postgresql must pass the rules
5252
- user must be a string
5353
FULL_MESSAGE,
5454
));

tests/feature/GetFullMessageShouldIncludeAllValidationMessagesInAChainTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
test('Scenario #1', expectFullMessage(
1313
fn() => Validator::stringType()->lengthBetween(2, 15)->assert(0),
1414
<<<'FULL_MESSAGE'
15-
- All the required rules must pass for 0
15+
- 0 must pass all the rules
1616
- 0 must be a string
1717
- 0 must be a countable value or a string
1818
FULL_MESSAGE,

tests/feature/GetMessagesShouldIncludeAllValidationMessagesInAChainTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function (): void {
2020
->assert(['username' => 'u', 'birthdate' => 'Not a date', 'password' => '']);
2121
},
2222
[
23-
'__root__' => 'All the required rules must pass for `["username": "u", "birthdate": "Not a date", "password": ""]`',
23+
'__root__' => '`["username": "u", "birthdate": "Not a date", "password": ""]` must pass all the rules',
2424
'username' => 'The length of username must be between 2 and 32',
2525
'birthdate' => 'birthdate must be a valid date/time',
2626
'password' => 'password must not be empty',

tests/feature/GetMessagesTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@
2020
->key('schema', v::stringType()))
2121
->assert(['mysql' => ['host' => 42, 'schema' => 42], 'postgresql' => ['user' => 42, 'password' => 42]]),
2222
[
23-
'__root__' => 'All the required rules must pass for `["mysql": ["host": 42, "schema": 42], "postgresql": ["user": 42, "password": 42]]`',
23+
'__root__' => '`["mysql": ["host": 42, "schema": 42], "postgresql": ["user": 42, "password": 42]]` must pass all the rules',
2424
'mysql' => [
25-
'__root__' => 'All the required rules must pass for mysql',
25+
'__root__' => 'mysql must pass all the rules',
2626
'host' => 'host must be a string',
2727
'user' => 'user must be present',
2828
'password' => 'password must be present',
2929
'schema' => 'schema must be a string',
3030
],
3131
'postgresql' => [
32-
'__root__' => 'All the required rules must pass for postgresql',
32+
'__root__' => 'postgresql must pass all the rules',
3333
'host' => 'host must be present',
3434
'user' => 'user must be a string',
3535
'password' => 'password must be a string',

tests/feature/GetMessagesWithReplacementsTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,16 @@ function (): void {
4949
);
5050
},
5151
[
52-
'__root__' => 'All the required rules must pass for `["mysql": ["host": 42, "schema": 42], "postgresql": ["user": 42, "password": 42]]`',
52+
'__root__' => '`["mysql": ["host": 42, "schema": 42], "postgresql": ["user": 42, "password": 42]]` must pass all the rules',
5353
'mysql' => [
54-
'__root__' => 'All the required rules must pass for mysql',
54+
'__root__' => 'mysql must pass all the rules',
5555
'host' => '`host` should be a MySQL host',
5656
'user' => 'Value should be a MySQL username',
5757
'password' => 'password must be present',
5858
'schema' => 'schema must be a string',
5959
],
6060
'postgresql' => [
61-
'__root__' => 'All the required rules must pass for postgresql',
61+
'__root__' => 'postgresql must pass all the rules',
6262
'host' => 'host must be present',
6363
'user' => 'user must be a string',
6464
'password' => 'password must be a string',

tests/feature/Issues/Issue1289Test.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@
4747
]),
4848
'default must be a string',
4949
<<<'FULL_MESSAGE'
50-
- These rules must pass for `["default": 2, "description": [], "children": ["nope"]]`
51-
- Only one of these rules must pass for default
50+
- `["default": 2, "description": [], "children": ["nope"]]` must pass the rules
51+
- default must pass one of the rules
5252
- default must be a string
5353
- default must be a boolean
5454
- description must be a string value
5555
FULL_MESSAGE,
5656
[
5757
0 => [
58-
'__root__' => 'These rules must pass for `["default": 2, "description": [], "children": ["nope"]]`',
58+
'__root__' => '`["default": 2, "description": [], "children": ["nope"]]` must pass the rules',
5959
'default' => [
60-
'__root__' => 'Only one of these rules must pass for default',
60+
'__root__' => 'default must pass one of the rules',
6161
'stringType' => 'default must be a string',
6262
'boolType' => 'default must be a boolean',
6363
],

tests/feature/Issues/Issue1333Test.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
fn() => v::noWhitespace()->email()->setName('User Email')->assert('not email'),
1212
'User Email must not contain whitespaces',
1313
<<<'FULL_MESSAGE'
14-
- All the required rules must pass for User Email
14+
- User Email must pass all the rules
1515
- User Email must not contain whitespaces
1616
- User Email must be a valid email address
1717
FULL_MESSAGE,
1818
[
19-
'__root__' => 'All the required rules must pass for User Email',
19+
'__root__' => 'User Email must pass all the rules',
2020
'noWhitespace' => 'User Email must not contain whitespaces',
2121
'email' => 'User Email must be a valid email address',
2222
],

0 commit comments

Comments
 (0)