Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions library/Message/Formatter/FirstResultStringFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,19 @@

use Respect\Validation\Message\Renderer;
use Respect\Validation\Message\StringFormatter;
use Respect\Validation\Name;
use Respect\Validation\Result;

final readonly class FirstResultStringFormatter implements StringFormatter
{
/** @param array<string|int, mixed> $templates */
public function format(Result $result, Renderer $renderer, array $templates): string
{
return $this->formatResult($result, $renderer, $templates, null);
}

/** @param array<string|int, mixed> $templates */
private function formatResult(Result $result, Renderer $renderer, array $templates, Name|null $parentName): string
{
if (!$result->hasCustomTemplate()) {
foreach ($result->children as $child) {
return $this->formatResult($child, $renderer, $templates, $result->name ?? $parentName);
return $this->format($child, $renderer, $templates);
}
}

if ($parentName !== null) {
$result = $result->withName($parentName);
}

return $renderer->render($result, $templates);
}
}
19 changes: 14 additions & 5 deletions library/Message/Formatter/NestedListStringFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use Respect\Validation\Message\Renderer;
use Respect\Validation\Message\StringFormatter;
use Respect\Validation\Name;
use Respect\Validation\Result;

use function array_filter;
Expand All @@ -27,7 +28,7 @@
/** @param array<string|int, mixed> $templates */
public function format(Result $result, Renderer $renderer, array $templates): string
{
return $this->formatRecursively($result, $renderer, $templates, 0);
return $this->formatRecursively($result, $renderer, $templates, 0, null);
}

/** @param array<string|int, mixed> $templates */
Expand All @@ -36,23 +37,31 @@ private function formatRecursively(
Renderer $renderer,
array $templates,
int $depth,
Name|null $lastVisibleName,
Result ...$siblings,
): string {
$formatted = '';
$displayedName = null;
if ($this->isVisible($result, ...$siblings)) {
$indentation = str_repeat(' ', $depth * 2);
$displayedName = $result->name;
$formatted .= sprintf('%s- %s' . PHP_EOL, $indentation, $renderer->render($result, $templates));
$formatted .= sprintf(
'%s- %s' . PHP_EOL,
$indentation,
$renderer->render(
$lastVisibleName === $result->name ? $result->withoutName() : $result,
$templates,
),
);
$lastVisibleName ??= $result->name;
$depth++;
}

foreach ($result->children as $child) {
$formatted .= $this->formatRecursively(
$displayedName === $child->name ? $child->withoutName() : $child,
$child,
$renderer,
$templates,
$depth,
$lastVisibleName,
...array_filter($result->children, static fn(Result $sibling) => $sibling !== $child),
);
$formatted .= PHP_EOL;
Expand Down
25 changes: 2 additions & 23 deletions library/Message/InterpolationRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Respect\Validation\Message;

use Respect\Validation\Message\Formatter\TemplateResolver;
use Respect\Validation\Name;
use Respect\Validation\Message\Placeholder\Subject;
use Respect\Validation\Result;

use function array_key_exists;
Expand All @@ -31,7 +31,7 @@ public function __construct(
/** @param array<string|int, mixed> $templates */
public function render(Result $result, array $templates): string
{
$parameters = ['path' => $result->path, 'input' => $result->input, 'subject' => $this->getName($result)];
$parameters = ['path' => $result->path, 'input' => $result->input, 'subject' => Subject::fromResult($result)];
$parameters += $result->parameters;

$givenTemplate = $this->templateResolver->getGivenTemplate($result, $templates);
Expand Down Expand Up @@ -65,25 +65,4 @@ private function processPlaceholder(array $parameters, array $matches): string

return $this->modifier->modify($parameters[$name], $pipe);
}

private function getName(Result $result): mixed
{
if (array_key_exists('name', $result->parameters) && is_string($result->parameters['name'])) {
return new Name($result->parameters['name']);
}

if (array_key_exists('name', $result->parameters)) {
return $result->parameters['name'];
}

if ($result->name !== null) {
return $result->name;
}

if ($result->path?->value !== null) {
return $result->path;
}

return $result->input;
}
}
30 changes: 30 additions & 0 deletions library/Message/Placeholder/Subject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Message\Placeholder;

use Respect\Validation\Name;
use Respect\Validation\Path;
use Respect\Validation\Result;

final readonly class Subject
{
public function __construct(
public mixed $input,
public Path|null $path = null,
public Name|null $name = null,
public bool $hasPrecedentName = true,
) {
}

public static function fromResult(Result $result): self
{
return new self($result->input, $result->path, $result->name, $result->hasPrecedentName);
}
}
17 changes: 1 addition & 16 deletions library/Message/Stringifier/NameStringifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,14 @@
use Respect\Stringifier\Stringifier;
use Respect\Validation\Name;

use function sprintf;

final readonly class NameStringifier implements Stringifier
{
public function __construct(
private Stringifier $stringifier,
) {
}

public function stringify(mixed $raw, int $depth): string|null
{
if (!$raw instanceof Name) {
return null;
}

if ($raw->path === null) {
return $raw->value;
}

return sprintf(
'%s (<- %s)',
$this->stringifier->stringify($raw->path, $depth),
$raw->value,
);
return $raw->value;
}
}
48 changes: 48 additions & 0 deletions library/Message/Stringifier/SubjectStringifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Message\Stringifier;

use Respect\Stringifier\Stringifier;
use Respect\Validation\Message\Placeholder\Subject;

use function sprintf;

final readonly class SubjectStringifier implements Stringifier
{
public function __construct(
private Stringifier $stringifier,
) {
}

public function stringify(mixed $raw, int $depth): string|null
{
if (!$raw instanceof Subject) {
return null;
}

if ($raw->path === null && $raw->name === null) {
return $this->stringifier->stringify($raw->input, $depth);
}

if ($raw->name === null) {
return $this->stringifier->stringify($raw->path, $depth);
}

if ($raw->path === null || $raw->hasPrecedentName) {
return $this->stringifier->stringify($raw->name, $depth);
}

return sprintf(
'%s (<- %s)',
$this->stringifier->stringify($raw->path, $depth),
$this->stringifier->stringify($raw->name, $depth),
);
}
}
4 changes: 3 additions & 1 deletion library/Message/ValidationStringifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use Respect\Validation\Message\Stringifier\NameStringifier;
use Respect\Validation\Message\Stringifier\PathStringifier;
use Respect\Validation\Message\Stringifier\QuotedStringifier;
use Respect\Validation\Message\Stringifier\SubjectStringifier;

final readonly class ValidationStringifier implements Stringifier
{
Expand Down Expand Up @@ -95,7 +96,8 @@ private function createStringifier(Quoter $quoter): Stringifier
$stringifier->prependStringifier(new PathStringifier($quoter));
$stringifier->prependStringifier(new QuotedStringifier($quoter));
$stringifier->prependStringifier(new ListedStringifier($stringifier));
$stringifier->prependStringifier(new NameStringifier($stringifier));
$stringifier->prependStringifier(new NameStringifier());
$stringifier->prependStringifier(new SubjectStringifier($stringifier));

return $stringifier;
}
Expand Down
5 changes: 0 additions & 5 deletions library/Name.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,4 @@ public function __construct(
public Path|null $path = null,
) {
}

public function withPath(Path $path): Name
{
return new self($this->value, $path);
}
}
37 changes: 18 additions & 19 deletions library/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public function __construct(
public array $parameters = [],
public string $template = Rule::TEMPLATE_STANDARD,
public bool $hasInvertedMode = false,
public bool $hasPrecedentName = true,
public Name|null $name = null,
public Result|null $adjacent = null,
public Path|null $path = null,
Expand Down Expand Up @@ -124,6 +125,7 @@ public function withPath(Path $path): self
return clone($this, [
'path' => $path,
'adjacent' => $this->adjacent?->withPath($path),
'hasPrecedentName' => $this->name !== null,
'children' => array_map(
static fn(Result $child) => $child->withPath($path),
$this->children,
Expand All @@ -149,43 +151,40 @@ public function withoutName(): self

public function withChildren(Result ...$children): self
{
if ($this->path === null) {
return clone($this, ['children' => $children]);
}

return clone($this, ['children' => array_map(fn(Result $child) => $child->withPath($this->path), $children)]);
return clone($this, ['children' => $children]);
}

public function withName(Name $name): self
{
if ($this->path !== null && $this->name?->path !== $this->path) {
$name = $name->withPath($this->path);
if ($this->name !== null) {
return $this;
}

return clone($this, [
'name' => $this->name ?? $name,
'name' => $name,
'adjacent' => $this->adjacent?->withName($name),
'children' => array_map(
static fn(Result $child) => $child->path === null ? $child->withName($child->name ?? $name) : $child,
static fn(Result $child) => $child->withName($name),
$this->children,
),
]);
}

public function withNameFrom(Rule $rule): self
{
if ($rule instanceof Nameable && $rule->getName() !== null) {
return clone($this, [
'name' => $this->name ?? $rule->getName(),
'adjacent' => $this->adjacent?->withNameFrom($rule),
'children' => array_map(
static fn(Result $child) => $child->withNameFrom($rule),
$this->children,
),
]);
if (!$rule instanceof Nameable || $rule->getName() === null) {
return $this;
}

return $this;
return clone($this, [
'name' => $this->name ?? $rule->getName(),
'hasPrecedentName' => true,
'adjacent' => $this->adjacent?->withNameFrom($rule),
'children' => array_map(
static fn(Result $child) => $child->withNameFrom($rule),
$this->children,
),
]);
}

public function withInput(mixed $input): self
Expand Down
2 changes: 1 addition & 1 deletion library/Rules/Key.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ public function evaluate(mixed $input): Result
return $keyExistsResult->withNameFrom($this->rule);
}

return $this->rule->evaluate($input[$this->key])->withPath(new Path($this->key));
return $this->rule->evaluate($input[$this->key])->withPath($keyExistsResult->path ?? new Path($this->key));
}
}
2 changes: 1 addition & 1 deletion library/Rules/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function evaluate(mixed $input): Result

return $this->rule
->evaluate($this->getPropertyValue($input, $this->propertyName))
->withPath(new Path($this->propertyName));
->withPath($propertyExistsResult->path ?? new Path($this->propertyName));
}

private function getPropertyValue(object $object, string $propertyName): mixed
Expand Down
3 changes: 3 additions & 0 deletions tests/library/Builders/ResultBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ final class ResultBuilder

private bool $hasInvertedMode = false;

private bool $hasPrecedentName = true;

private string $template = Rule::TEMPLATE_STANDARD;

/** @var array<string, mixed> */
Expand Down Expand Up @@ -58,6 +60,7 @@ public function build(): Result
$this->parameters,
$this->template,
$this->hasInvertedMode,
$this->hasPrecedentName,
$this->name,
$this->adjacent,
$this->path,
Expand Down
Loading