Skip to content

Commit

Permalink
Handle names via the Named rule
Browse files Browse the repository at this point in the history
Because of how the validation engine works now [1], there's no reason to
keep adding names to each rule. Instead, create a single rule that
handles naming rules with a few other accessories. This change is not
necessarily simple, but it shrinks the `Rule` interface, and it's more
aligned with how the library works right now.

Personally, I think this API is much more straightforward than the
`setName()` method, as it's way more explicit about which rule we're
naming. Because of this change, the behaviour changed slightly, but it's
for the best.

Because of this change, I managed to remove a lot of code, but
unfortunately, it's quite a big-bang commit. It would be too complicated
to make it atomic since names are an intrinsic part of the library.

[1]: 238f2d5
  • Loading branch information
henriquemoody committed Dec 26, 2024
1 parent 9dac855 commit a3c197f
Show file tree
Hide file tree
Showing 48 changed files with 394 additions and 538 deletions.
7 changes: 4 additions & 3 deletions bin/create-mixin
Original file line number Diff line number Diff line change
Expand Up @@ -172,17 +172,18 @@ function overwriteFile(string $content, string $basename): void
'PropertyOptional',
'Attributes',
'Templated',
'Named',
];

$mixins = [
['Key', 'key', [], $structureRelatedRules],
['Length', 'length', $numberRelatedRules, []],
['Max', 'max', $numberRelatedRules, []],
['Min', 'min', $numberRelatedRules, []],
['Not', 'not', [], ['Not', 'NotEmpty', 'NotBlank', 'NotEmoji', 'NotUndef', 'NotOptional', 'NullOr', 'UndefOr', 'Optional', 'Attributes', 'Templated']],
['NullOr', 'nullOr', [], ['Nullable', 'NullOr', 'Optional', 'NotOptional', 'NotUndef', 'UndefOr', 'Templated']],
['Not', 'not', [], ['Not', 'NotEmpty', 'NotBlank', 'NotEmoji', 'NotUndef', 'NotOptional', 'NullOr', 'UndefOr', 'Optional', 'Attributes', 'Templated', 'Named']],
['NullOr', 'nullOr', [], ['Nullable', 'NullOr', 'Optional', 'NotOptional', 'NotUndef', 'UndefOr', 'Templated', 'Named']],
['Property', 'property', [], $structureRelatedRules],
['UndefOr', 'undefOr', [], ['Nullable', 'NullOr', 'NotOptional', 'NotUndef', 'Optional', 'UndefOr', 'Attributes', 'Templated']],
['UndefOr', 'undefOr', [], ['Nullable', 'NullOr', 'NotOptional', 'NotUndef', 'Optional', 'UndefOr', 'Attributes', 'Templated', 'Named']],
['', null, [], []],
];

Expand Down
4 changes: 4 additions & 0 deletions docs/09-list-of-rules-by-category.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@

## Core

- [Named](rules/Named.md)
- [Not](rules/Not.md)
- [Templated](rules/Templated.md)

Expand Down Expand Up @@ -159,6 +160,7 @@
## Miscellaneous

- [FilterVar](rules/FilterVar.md)
- [Named](rules/Named.md)
- [NotBlank](rules/NotBlank.md)
- [NotEmpty](rules/NotEmpty.md)
- [NotUndef](rules/NotUndef.md)
Expand Down Expand Up @@ -260,6 +262,7 @@
- [KeyExists](rules/KeyExists.md)
- [KeyOptional](rules/KeyOptional.md)
- [KeySet](rules/KeySet.md)
- [Named](rules/Named.md)
- [Property](rules/Property.md)
- [PropertyExists](rules/PropertyExists.md)
- [PropertyOptional](rules/PropertyOptional.md)
Expand Down Expand Up @@ -392,6 +395,7 @@
- [Mimetype](rules/Mimetype.md)
- [Min](rules/Min.md)
- [Multiple](rules/Multiple.md)
- [Named](rules/Named.md)
- [Negative](rules/Negative.md)
- [NfeAccessKey](rules/NfeAccessKey.md)
- [Nif](rules/Nif.md)
Expand Down
1 change: 1 addition & 0 deletions docs/rules/Attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ v::attributes()->assert(new Person('', 'not an email', 'not a date', 'not a phon
***
See also:

- [Named](Named.md)
- [NullOr](NullOr.md)
- [ObjectType](ObjectType.md)
- [Property](Property.md)
Expand Down
48 changes: 48 additions & 0 deletions docs/rules/Named.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Named

- `Named(Rule $rule, string $name)`

Validates the input with the given rule, and uses the custom name in the error message.

```php
v::named(v::email(), 'Your email')->assert('not an email');
// Message: Your email must be a valid email address
```

Here's an example of a similar code, but without using the `Named` rule:

```php
v::email()->assert('not an email');
// Message: "not an email" must be a valid email address
```

The `Named` rule can be also useful when you're using [Attributes](Attributes.md) and want a custom name for a specific property.

## Templates

This rule does not have any templates, as it will use the template of the given rule.

## Template placeholders

| Placeholder | Description |
|-------------|---------------------------------------|
| `name` | The value that you define as `$name`. |

## Categorization

- Core
- Structures
- Miscellaneous

## Changelog

| Version | Description |
|--------:|-------------|
| 3.0.0 | Created |

***
See also:

- [Attributes](Attributes.md)
- [Not](Not.md)
- [Templated](Templated.md)
1 change: 1 addition & 0 deletions docs/rules/Not.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ Each other validation has custom messages for negated rules.
***
See also:

- [Named](Named.md)
- [NoneOf](NoneOf.md)
- [Templated](Templated.md)
1 change: 1 addition & 0 deletions docs/rules/Templated.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ This rule does not have any templates, as you must define the templates yourself
See also:

- [Attributes](Attributes.md)
- [Named](Named.md)
- [Not](Not.md)
23 changes: 0 additions & 23 deletions library/Helpers/CanExtractPropertyValue.php

This file was deleted.

39 changes: 0 additions & 39 deletions library/Helpers/DeprecatedValidatableMethods.php

This file was deleted.

2 changes: 2 additions & 0 deletions library/Mixins/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ public static function min(Rule $rule): Chain;

public static function multiple(int $multipleOf): Chain;

public static function named(Rule $rule, string $name): Chain;

public static function negative(): Chain;

public static function nfeAccessKey(): Chain;
Expand Down
2 changes: 2 additions & 0 deletions library/Mixins/Chain.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ public function min(Rule $rule): Chain;

public function multiple(int $multipleOf): Chain;

public function named(Rule $rule, string $name): Chain;

public function negative(): Chain;

public function nfeAccessKey(): Chain;
Expand Down
32 changes: 25 additions & 7 deletions library/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace Respect\Validation;

use Respect\Validation\Rules\Core\Nameable;
use Respect\Validation\Rules\Core\Renameable;

use function array_filter;
use function array_map;
use function count;
Expand All @@ -25,8 +28,6 @@ final class Result

public readonly string $id;

public readonly ?string $name;

/** @param array<string, mixed> $parameters */
public function __construct(
public readonly bool $isValid,
Expand All @@ -35,13 +36,12 @@ public function __construct(
public readonly array $parameters = [],
public readonly string $template = Rule::TEMPLATE_STANDARD,
public readonly Mode $mode = Mode::DEFAULT,
?string $name = null,
public readonly ?string $name = null,
?string $id = null,
public readonly ?Result $adjacent = null,
public readonly bool $unchangeableId = false,
Result ...$children,
) {
$this->name = $rule->getName() ?? $name;
$this->id = $id ?? lcfirst(substr((string) strrchr($rule::class, '\\'), 1));
$this->children = $children;
}
Expand Down Expand Up @@ -109,6 +109,11 @@ public function withId(string $id): self
return $this->clone(id: $id);
}

public function withIdFrom(Rule $rule): self
{
return $this->clone(id: lcfirst(substr((string) strrchr($rule::class, '\\'), 1)));
}

public function withUnchangeableId(string $id): self
{
return $this->clone(id: $id, unchangeableId: true);
Expand All @@ -128,14 +133,27 @@ public function withChildren(Result ...$children): self
return $this->clone(children: $children);
}

public function withNameIfMissing(string $name): self
public function withName(string $name): self
{
return $this->clone(
name: $this->name ?? $name,
children: array_map(static fn (Result $child) => $child->withNameIfMissing($name), $this->children),
name: $this->rule instanceof Renameable ? $name : ($this->name ?? $name),
adjacent: $this->adjacent?->withName($name),
children: array_map(
static fn (Result $child) => $child->withName($child->name ?? $name),
$this->children
),
);
}

public function withNameFrom(Rule $rule): self
{
if ($rule instanceof Nameable && $rule->getName() !== null) {
return $this->withName($rule->getName());
}

return $this;
}

public function withInput(mixed $input): self
{
$currentInput = $this->input;
Expand Down
4 changes: 0 additions & 4 deletions library/Rule.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,4 @@ interface Rule
public const TEMPLATE_STANDARD = '__standard__';

public function evaluate(mixed $input): Result;

public function getName(): ?string;

public function setName(string $name): static;
}
5 changes: 2 additions & 3 deletions library/Rules/Attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
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;

Expand All @@ -23,7 +22,7 @@ final class Attributes extends Standard
{
public function evaluate(mixed $input): Result
{
$objectType = (new Binder($this, new ObjectType()))->evaluate($input);
$objectType = (new ObjectType())->evaluate($input);
if (!$objectType->isValid) {
return $objectType->withId('attributes');
}
Expand All @@ -49,6 +48,6 @@ public function evaluate(mixed $input): Result
return (new AlwaysValid())->evaluate($input)->withId('attributes');
}

return (new Binder($this, new Reducer(...$rules)))->evaluate($input)->withId('attributes');
return (new Reducer(...$rules))->evaluate($input)->withId('attributes');
}
}
3 changes: 1 addition & 2 deletions library/Rules/Circuit.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

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)]
Expand All @@ -20,7 +19,7 @@ final class Circuit extends Composite
public function evaluate(mixed $input): Result
{
foreach ($this->rules as $rule) {
$result = (new Binder($this, $rule))->evaluate($input);
$result = $rule->evaluate($input);
if (!$result->isValid) {
return $result;
}
Expand Down
31 changes: 0 additions & 31 deletions library/Rules/Core/Binder.php

This file was deleted.

Loading

0 comments on commit a3c197f

Please sign in to comment.