Skip to content

Commit

Permalink
Remove duplication and improve naming of adjacent results
Browse files Browse the repository at this point in the history
I identified a pattern among rules that create results with adjacent
results, so I created a method that abstracts that. I did have to
compromise with the DateTimeDiff, having to escape the input instead of
using the name itself, but that seems like a good trade-off.

I've also renamed "Subsequent" to "Adjacent" because it sounded better.
This is the second time I've renamed this concept, and I hope it will be
the last.
  • Loading branch information
henriquemoody committed Dec 20, 2024
1 parent 873be39 commit 18d8246
Show file tree
Hide file tree
Showing 17 changed files with 131 additions and 208 deletions.
4 changes: 2 additions & 2 deletions library/Message/StandardRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ function (array $matches) use ($parameters, $translator) {
$translator->translate($template ?? $this->getTemplateMessage($result))
);

if (!$result->hasCustomTemplate() && $result->subsequent !== null) {
$rendered .= ' ' . $this->render($result->subsequent, $translator);
if (!$result->hasCustomTemplate() && $result->adjacent !== null) {
$rendered .= ' ' . $this->render($result->adjacent, $translator);
}

return $rendered;
Expand Down
45 changes: 34 additions & 11 deletions library/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function __construct(
public readonly Mode $mode = Mode::DEFAULT,
?string $name = null,
?string $id = null,
public readonly ?Result $subsequent = null,
public readonly ?Result $adjacent = null,
public readonly bool $unchangeableId = false,
Result ...$children,
) {
Expand Down Expand Up @@ -69,6 +69,29 @@ public static function passed(
return new self(true, $input, $rule, $parameters, $template);
}

/** @param array<string, mixed> $parameters */
public static function fromAdjacent(
mixed $input,
string $prefix,
Rule $rule,
Result $adjacent,
array $parameters = [],
string $template = Rule::TEMPLATE_STANDARD
): Result {
if ($adjacent->allowsAdjacent()) {
return (new Result($adjacent->isValid, $input, $rule, $parameters, $template, id: $adjacent->id))
->withPrefixedId($prefix)
->withAdjacent($adjacent->withInput($input));
}

$childrenAsAdjacent = array_map(
static fn(Result $child) => self::fromAdjacent($input, $prefix, $rule, $child, $parameters, $template),
$adjacent->children
);

return $adjacent->withInput($input)->withChildren(...$childrenAsAdjacent);
}

public function withTemplate(string $template): self
{
return $this->clone(template: $template);
Expand Down Expand Up @@ -123,16 +146,16 @@ public function withInput(mixed $input): self
);
}

public function withSubsequent(Result $subsequent): self
public function withAdjacent(Result $adjacent): self
{
return $this->clone(subsequent: $subsequent);
return $this->clone(adjacent: $adjacent);
}

public function withInvertedValidation(): self
{
return $this->clone(
isValid: !$this->isValid,
subsequent: $this->subsequent?->withInvertedValidation(),
adjacent: $this->adjacent?->withInvertedValidation(),
children: array_map(static fn (Result $child) => $child->withInvertedValidation(), $this->children),
);
}
Expand All @@ -142,7 +165,7 @@ public function withInvertedMode(): self
return $this->clone(
isValid: !$this->isValid,
mode: $this->mode == Mode::DEFAULT ? Mode::INVERTED : Mode::DEFAULT,
subsequent: $this->subsequent?->withInvertedMode(),
adjacent: $this->adjacent?->withInvertedMode(),
children: array_map(static fn (Result $child) => $child->withInvertedMode(), $this->children),
);
}
Expand All @@ -152,18 +175,18 @@ public function hasCustomTemplate(): bool
return preg_match('/__[0-9a-z_]+_/', $this->template) === 0;
}

public function allowsSubsequent(): bool
public function allowsAdjacent(): bool
{
if ($this->children === [] && !$this->hasCustomTemplate()) {
return true;
}

$childrenThatAllowSubsequent = array_filter(
$childrenThatAllowAdjacent = array_filter(
$this->children,
static fn (Result $child) => $child->allowsSubsequent()
static fn (Result $child) => $child->allowsAdjacent()
);

return count($childrenThatAllowSubsequent) === 1;
return count($childrenThatAllowAdjacent) === 1;
}

/**
Expand All @@ -176,7 +199,7 @@ private function clone(
?Mode $mode = null,
?string $name = null,
?string $id = null,
?Result $subsequent = null,
?Result $adjacent = null,
?bool $unchangeableId = null,
?array $children = null
): self {
Expand All @@ -189,7 +212,7 @@ private function clone(
$mode ?? $this->mode,
$name ?? $this->name,
$id ?? $this->id,
$subsequent ?? $this->subsequent,
$adjacent ?? $this->adjacent,
$unchangeableId ?? $this->unchangeableId,
...($children ?? $this->children)
);
Expand Down
49 changes: 0 additions & 49 deletions library/Rules/Core/ArrayAggregateFunction.php

This file was deleted.

36 changes: 10 additions & 26 deletions library/Rules/DateTimeDiff.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Respect\Validation\Rules\Core\Standard;
use Throwable;

use function array_map;
use function in_array;
use function ucfirst;

Expand All @@ -31,8 +30,8 @@
self::TEMPLATE_STANDARD
)]
#[Template(
'The number of {{type|trans}} between {{now|raw}} and',
'The number of {{type|trans}} between {{now|raw}} and',
'The number of {{type|trans}} between {{now}} and',
'The number of {{type|trans}} between {{now}} and',
self::TEMPLATE_CUSTOMIZED
)]
#[Template(
Expand Down Expand Up @@ -82,33 +81,18 @@ public function evaluate(mixed $input): Result
->withId('dateTimeDiff' . ucfirst($this->rule->evaluate($input)->id));
}

return $this->enrichResult(
$this->nowParameter($now),
$nowPlaceholder = $this->nowParameter($now);

return Result::fromAdjacent(
$input,
$this->rule->evaluate($this->comparisonValue($now, $compareTo))
'dateTimeDiff',
$this,
$this->rule->evaluate($this->comparisonValue($now, $compareTo)),
['type' => $this->type, 'now' => $nowPlaceholder],
$nowPlaceholder === 'now' ? self::TEMPLATE_STANDARD : self::TEMPLATE_CUSTOMIZED
);
}

private function enrichResult(string $now, mixed $input, Result $result): Result
{
$name = $input instanceof DateTimeInterface ? $input->format('c') : $input;

if (!$result->allowsSubsequent()) {
return $result
->withNameIfMissing($name)
->withChildren(
...array_map(fn(Result $child) => $this->enrichResult($now, $input, $child), $result->children)
);
}

$parameters = ['type' => $this->type, 'now' => $now];
$template = $now === 'now' ? self::TEMPLATE_STANDARD : self::TEMPLATE_CUSTOMIZED;

return (new Result($result->isValid, $input, $this, $parameters, $template, id: $result->id))
->withPrefixedId('dateTimeDiff')
->withSubsequent($result->withNameIfMissing($name));
}

private function comparisonValue(DateTimeInterface $now, DateTimeInterface $compareTo): int|float
{
return match ($this->type) {
Expand Down
18 changes: 1 addition & 17 deletions library/Rules/Length.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use Respect\Validation\Result;
use Respect\Validation\Rules\Core\Wrapper;

use function array_map;
use function count;
use function is_array;
use function is_string;
Expand Down Expand Up @@ -45,22 +44,7 @@ public function evaluate(mixed $input): Result
->withId('length' . ucfirst($this->rule->evaluate($input)->id));
}

return $this->enrichResult($input, $this->rule->evaluate($length));
}

private function enrichResult(mixed $input, Result $result): Result
{
if (!$result->allowsSubsequent()) {
return $result
->withInput($input)
->withChildren(
...array_map(fn(Result $child) => $this->enrichResult($input, $child), $result->children)
);
}

return (new Result($result->isValid, $input, $this, id: $result->id))
->withPrefixedId('length')
->withSubsequent($result->withInput($input));
return Result::fromAdjacent($input, 'length', $this, $this->rule->evaluate($length));
}

private function extractLength(mixed $input): ?int
Expand Down
11 changes: 5 additions & 6 deletions library/Rules/Max.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@

use Attribute;
use Respect\Validation\Message\Template;
use Respect\Validation\Rules\Core\ArrayAggregateFunction;
use Respect\Validation\Result;
use Respect\Validation\Rules\Core\FilteredNonEmptyArray;

use function max;

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
#[Template('The maximum of', 'The maximum of')]
final class Max extends ArrayAggregateFunction
final class Max extends FilteredNonEmptyArray
{
protected string $idPrefix = 'max';

/** @param non-empty-array<mixed> $input */
protected function extractAggregate(array $input): mixed
protected function evaluateNonEmptyArray(array $input): Result
{
return max($input);
return Result::fromAdjacent($input, 'max', $this, $this->rule->evaluate(max($input)));
}
}
11 changes: 5 additions & 6 deletions library/Rules/Min.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@

use Attribute;
use Respect\Validation\Message\Template;
use Respect\Validation\Rules\Core\ArrayAggregateFunction;
use Respect\Validation\Result;
use Respect\Validation\Rules\Core\FilteredNonEmptyArray;

use function min;

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
#[Template('The minimum of', 'The minimum of')]
final class Min extends ArrayAggregateFunction
final class Min extends FilteredNonEmptyArray
{
protected string $idPrefix = 'min';

/** @param non-empty-array<mixed> $input */
protected function extractAggregate(array $input): mixed
protected function evaluateNonEmptyArray(array $input): Result
{
return min($input);
return Result::fromAdjacent($input, 'min', $this, $this->rule->evaluate(min($input)));
}
}
4 changes: 2 additions & 2 deletions library/Rules/NullOr.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ public function evaluate(mixed $input): Result

private function enrichResult(Result $result): Result
{
if ($result->allowsSubsequent()) {
if ($result->allowsAdjacent()) {
return $result
->withPrefixedId('nullOr')
->withSubsequent(new Result($result->isValid, $result->input, $this));
->withAdjacent(new Result($result->isValid, $result->input, $this));
}

return $result->withChildren(...array_map(fn(Result $child) => $this->enrichResult($child), $result->children));
Expand Down
21 changes: 2 additions & 19 deletions library/Rules/Size.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
use Respect\Validation\Rules\Core\Wrapper;
use SplFileInfo;

use function array_map;
use function filesize;
use function is_string;
use function ucfirst;
Expand Down Expand Up @@ -72,8 +71,9 @@ public function evaluate(mixed $input): Result
}

$result = $this->rule->evaluate($this->getSize($input) / self::DATA_STORAGE_UNITS[$this->unit]['bytes']);
$parameters = ['unit' => self::DATA_STORAGE_UNITS[$this->unit]['name']];

return $this->enrichResult($input, $result);
return Result::fromAdjacent($input, 'size', $this, $result, $parameters);
}

private function getSize(mixed $input): ?int
Expand All @@ -96,21 +96,4 @@ private function getSize(mixed $input): ?int

return null;
}

private function enrichResult(mixed $input, Result $result): Result
{
if (!$result->allowsSubsequent()) {
return $result
->withInput($input)
->withChildren(
...array_map(fn(Result $child) => $this->enrichResult($input, $child), $result->children)
);
}

$parameters = ['unit' => self::DATA_STORAGE_UNITS[$this->unit]['name']];

return (new Result($result->isValid, $input, $this, $parameters, id: $result->id))
->withPrefixedId('size')
->withSubsequent($result->withInput($input));
}
}
4 changes: 2 additions & 2 deletions library/Rules/UndefOr.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ public function evaluate(mixed $input): Result

private function enrichResult(Result $result): Result
{
if ($result->allowsSubsequent()) {
if ($result->allowsAdjacent()) {
return $result
->withPrefixedId('undefOr')
->withSubsequent(new Result($result->isValid, $result->input, $this));
->withAdjacent(new Result($result->isValid, $result->input, $this));
}

return $result->withChildren(...array_map(fn(Result $child) => $this->enrichResult($child), $result->children));
Expand Down
Loading

0 comments on commit 18d8246

Please sign in to comment.