Skip to content

Commit

Permalink
Create "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 0a5418d
Show file tree
Hide file tree
Showing 43 changed files with 339 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
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.

27 changes: 1 addition & 26 deletions library/Rules/Core/Composite.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@

namespace Respect\Validation\Rules\Core;

use Respect\Validation\Helpers\DeprecatedValidatableMethods;
use Respect\Validation\Rule;

use function array_merge;

abstract class Composite implements Rule
abstract class Composite extends Standard
{
use DeprecatedValidatableMethods;

/** @var non-empty-array<Rule> */
protected readonly array $rules;

private ?string $name = null;

public function __construct(Rule $rule1, Rule $rule2, Rule ...$rules)
{
$this->rules = array_merge([$rule1, $rule2], $rules);
Expand All @@ -33,24 +28,4 @@ public function getRules(): array
{
return $this->rules;
}

public function setName(string $name): static
{
foreach ($this->rules as $rule) {
if ($rule->getName() && $this->name !== $rule->getName()) {
continue;
}

$rule->setName($name);
}

$this->name = $name;

return $this;
}

public function getName(): ?string
{
return $this->name;
}
}
12 changes: 4 additions & 8 deletions library/Rules/Core/FilteredNonEmptyArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@

use function is_array;
use function iterator_to_array;
use function lcfirst;
use function strrchr;
use function substr;

abstract class FilteredNonEmptyArray extends Wrapper
{
Expand All @@ -26,16 +23,15 @@ abstract protected function evaluateNonEmptyArray(array $input): Result;

public function evaluate(mixed $input): Result
{
$id = $this->rule->getName() ?? $this->getName() ?? lcfirst(substr((string) strrchr(static::class, '\\'), 1));
$iterableResult = (new Binder($this, new IterableType()))->evaluate($input);
$iterableResult = (new IterableType())->evaluate($input);
if (!$iterableResult->isValid) {
return $iterableResult->withId($id);
return $iterableResult->withIdFrom($this)->withNameFrom($this->rule);
}

$array = $this->toArray($input);
$notEmptyResult = (new Binder($this, new NotEmpty()))->evaluate($array);
$notEmptyResult = (new NotEmpty())->evaluate($array);
if (!$notEmptyResult->isValid) {
return $notEmptyResult->withId($id);
return $notEmptyResult->withIdFrom($this)->withNameFrom($this->rule);
}

// @phpstan-ignore-next-line
Expand Down
15 changes: 15 additions & 0 deletions library/Rules/Core/Nameable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

/*
* Copyright (c) Alexandre Gomes Gaigalas <[email protected]>
* SPDX-License-Identifier: MIT
*/

declare(strict_types=1);

namespace Respect\Validation\Rules\Core;

interface Nameable
{
public function getName(): ?string;
}
19 changes: 19 additions & 0 deletions library/Rules/Core/Reducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use Respect\Validation\Rule;
use Respect\Validation\Rules\AllOf;
use Respect\Validation\Rules\Named;
use Respect\Validation\Rules\Templated;

final class Reducer extends Wrapper
Expand All @@ -28,4 +29,22 @@ public function withTemplate(?string $template): self

return new self(new Templated($this->rule, $template));
}

public function withName(?string $name): self
{
if ($name === null) {
return $this;
}

return new self(new Named($this->rule, $name));
}

public function getName(): ?string
{
if ($this->rule instanceof Nameable) {
return $this->rule->getName();
}

return null;
}
}
Loading

0 comments on commit 0a5418d

Please sign in to comment.