Remove unused code from the old validation engine

Because we've changed the validation engine, those classes are not
necessary anymore. This is a major step for the new validation engine.

The NestedValidationException was one of the most important classes of
the project, the one that formatted nested messages -- and it was also
one of the buggiest and most complicated ones. With the new validation
engine, it became obsolete.

These changes are a significant step toward refactoring the whole
codebase. The changes in the Factory are there to ensure it doesn't
break for the time being.

Thank you NestedValidationException; you did an excellent job for a long
time. I can't say I will miss you, but seeing you go is weird.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2024-03-07 00:50:15 +01:00
parent 3a6a71a1f8
commit fdd8c5a978
No known key found for this signature in database
GPG key ID: 221E9281655813A6
9 changed files with 1 additions and 510 deletions

View file

@ -1,25 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Attributes;
use Attribute;
use Respect\Validation\Exceptions\ValidationException;
#[Attribute(Attribute::TARGET_CLASS)]
final class ExceptionClass
{
/**
* @param class-string<ValidationException> $class
*/
public function __construct(
public readonly string $class
) {
}
}

View file

@ -1,37 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Exceptions;
final class EachException extends NestedValidationException
{
/**
* @todo This method shares too much with the parent implementation
*
* @param array<string, string> $templates
*
* @return array<string, string>
*/
public function getMessages(array $templates = []): array
{
$messages = [];
$count = -1;
foreach ($this->getChildren() as $exception) {
$count++;
$id = $exception->getId();
$messages[$id . '.' . $count] = $this->renderMessage(
$exception,
$this->findTemplates($templates, $this->getId())
);
}
return $messages;
}
}

View file

@ -1,236 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Exceptions;
use IteratorAggregate;
use RecursiveIteratorIterator;
use SplObjectStorage;
use function array_shift;
use function count;
use function current;
use function implode;
use function is_array;
use function is_string;
use function spl_object_hash;
use function sprintf;
use function str_repeat;
use const PHP_EOL;
/**
* @implements IteratorAggregate<ValidationException>
*/
class NestedValidationException extends ValidationException implements IteratorAggregate
{
/**
* @var ValidationException[]
*/
private array $exceptions = [];
/**
* @return ValidationException[]
*/
public function getChildren(): array
{
return $this->exceptions;
}
public function addChild(ValidationException $exception): self
{
$this->exceptions[spl_object_hash($exception)] = $exception;
return $this;
}
/**
* @param ValidationException[] $exceptions
*/
public function addChildren(array $exceptions): self
{
foreach ($exceptions as $exception) {
$this->addChild($exception);
}
return $this;
}
/**
* @return SplObjectStorage<ValidationException, int>
*/
public function getIterator(): SplObjectStorage
{
/** @var SplObjectStorage<ValidationException, int> */
$childrenExceptions = new SplObjectStorage();
$recursiveIteratorIterator = $this->getRecursiveIterator();
$lastDepth = 0;
$lastDepthOriginal = 0;
$knownDepths = [];
foreach ($recursiveIteratorIterator as $childException) {
if ($this->isOmissible($childException)) {
continue;
}
$currentDepth = $lastDepth;
$currentDepthOriginal = $recursiveIteratorIterator->getDepth() + 1;
if (isset($knownDepths[$currentDepthOriginal])) {
$currentDepth = $knownDepths[$currentDepthOriginal];
} elseif ($currentDepthOriginal > $lastDepthOriginal) {
++$currentDepth;
}
if (!isset($knownDepths[$currentDepthOriginal])) {
$knownDepths[$currentDepthOriginal] = $currentDepth;
}
$lastDepth = $currentDepth;
$lastDepthOriginal = $currentDepthOriginal;
$childrenExceptions->attach($childException, $currentDepth);
}
return $childrenExceptions;
}
/**
* Returns a key->value array with all the messages of the exception.
*
* In this array the "keys" are the ids of the exceptions (defined name or
* name of the rule) and the values are the message.
*
* Once templates are passed it overwrites the templates of the given
* messages.
*
* @param string[]|string[][] $templates
*
* @return string[]
*/
public function getMessages(array $templates = []): array
{
$messages = [$this->getId() => $this->renderMessage($this, $templates)];
foreach ($this->getChildren() as $exception) {
$id = $exception->getId();
if (!$exception instanceof self) {
$messages[$id] = $this->renderMessage(
$exception,
$this->findTemplates($templates, $this->getId())
);
continue;
}
$messages[$id] = $exception->getMessages($this->findTemplates($templates, $id, $this->getId()));
if (count($messages[$id]) > 1) {
continue;
}
$messages[$id] = current($messages[$exception->getId()]);
}
if (count($messages) > 1) {
unset($messages[$this->getId()]);
}
return $messages;
}
public function getFullMessage(): string
{
$messages = [];
$leveler = 1;
if (!$this->isOmissible($this)) {
$leveler = 0;
$messages[] = sprintf('- %s', $this->getMessage());
}
$exceptions = $this->getIterator();
/** @var ValidationException $exception */
foreach ($exceptions as $exception) {
$messages[] = sprintf(
'%s- %s',
str_repeat(' ', (int) ($exceptions[$exception] - $leveler) * 2),
$exception->getMessage()
);
}
return implode(PHP_EOL, $messages);
}
/**
* @param string[]|string[][] $templates
*/
protected function renderMessage(ValidationException $exception, array $templates): string
{
if (isset($templates[$exception->getId()]) && is_string($templates[$exception->getId()])) {
$exception->updateTemplate($templates[$exception->getId()]);
}
return $exception->getMessage();
}
/**
* @param string[]|string[][] $templates
*
* @return string[]|string[][]
*/
protected function findTemplates(array $templates, mixed ...$ids): array
{
while (count($ids) > 0) {
$id = array_shift($ids);
if (!isset($templates[$id])) {
continue;
}
if (!is_array($templates[$id])) {
continue;
}
$templates = $templates[$id];
}
return $templates;
}
/**
* @return RecursiveIteratorIterator<RecursiveExceptionIterator>
*/
private function getRecursiveIterator(): RecursiveIteratorIterator
{
return new RecursiveIteratorIterator(
new RecursiveExceptionIterator($this),
RecursiveIteratorIterator::SELF_FIRST
);
}
private function isOmissible(Exception $exception): bool
{
if (!$exception instanceof self) {
return false;
}
if (count($exception->getChildren()) !== 1) {
return false;
}
/** @var ValidationException $childException */
$childException = current($exception->getChildren());
if ($childException->getMessage() === $exception->getMessage()) {
return true;
}
if ($exception->hasCustomTemplate()) {
return $childException->hasCustomTemplate();
}
return !$childException instanceof NonOmissibleValidationException;
}
}

View file

@ -1,14 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Exceptions;
final class NonOmissibleValidationException extends NestedValidationException
{
}

View file

@ -1,83 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Exceptions;
use ArrayIterator;
use Countable;
use RecursiveIterator;
use UnexpectedValueException;
/**
* @implements RecursiveIterator<int, ValidationException>
*/
final class RecursiveExceptionIterator implements RecursiveIterator, Countable
{
/**
* @var ArrayIterator<int, ValidationException>
*/
private readonly ArrayIterator $exceptions;
public function __construct(NestedValidationException $parent)
{
$this->exceptions = new ArrayIterator($parent->getChildren());
}
public function count(): int
{
return $this->exceptions->count();
}
public function hasChildren(): bool
{
if (!$this->valid()) {
return false;
}
return $this->current() instanceof NestedValidationException;
}
public function getChildren(): self
{
$exception = $this->current();
if (!$exception instanceof NestedValidationException) {
throw new UnexpectedValueException();
}
return new static($exception);
}
/**
* @return ValidationException|NestedValidationException
*/
public function current(): ValidationException
{
return $this->exceptions->current();
}
public function key(): int
{
return (int) $this->exceptions->key();
}
public function next(): void
{
$this->exceptions->next();
}
public function rewind(): void
{
$this->exceptions->rewind();
}
public function valid(): bool
{
return $this->exceptions->valid();
}
}

View file

@ -12,7 +12,6 @@ namespace Respect\Validation;
use ReflectionClass;
use ReflectionException;
use ReflectionObject;
use Respect\Validation\Attributes\ExceptionClass;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Exceptions\InvalidClassException;
use Respect\Validation\Exceptions\ValidationException;
@ -23,7 +22,6 @@ use Respect\Validation\Message\Parameter\Trans;
use Respect\Validation\Message\TemplateCollector;
use Respect\Validation\Message\TemplateRenderer;
use function count;
use function lcfirst;
use function sprintf;
use function trim;
@ -138,17 +136,7 @@ final class Factory
$templates = $this->templateCollector->extract($validatable);
$formatter = new TemplateRenderer($this->translator, $this->processor);
$attributes = $reflection->getAttributes(ExceptionClass::class);
if (count($attributes) === 0) {
return new ValidationException($input, $id, $params, $template, $templates, $formatter);
}
/** @var ValidationException $exception */
$exception = $this
->createReflectionClass($attributes[0]->newInstance()->class, ValidationException::class)
->newInstance($input, $id, $params, $template, $templates, $formatter);
return $exception;
return new ValidationException($input, $id, $params, $template, $templates, $formatter);
}
public static function setDefaultInstance(self $defaultInstance): void

View file

@ -9,14 +9,11 @@ declare(strict_types=1);
namespace Respect\Validation;
use Respect\Validation\Attributes\ExceptionClass;
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Exceptions\ValidatorException;
use Respect\Validation\Helpers\CanBindEvaluateRule;
use Respect\Validation\Message\Formatter;
use Respect\Validation\Message\StandardFormatter;
use Respect\Validation\Message\StandardRenderer;
use Respect\Validation\Message\Template;
use Respect\Validation\Mixins\ChainedValidator;
use Respect\Validation\Mixins\StaticValidator;
use Respect\Validation\Rules\AbstractRule;
@ -29,24 +26,10 @@ use function current;
* @mixin StaticValidator
* @mixin ChainedValidator
*/
#[ExceptionClass(NestedValidationException::class)]
#[Template(
'All of the required rules must pass for {{name}}',
'None of these rules must pass for {{name}}',
self::TEMPLATE_NONE,
)]
#[Template(
'These rules must pass for {{name}}',
'These rules must not pass for {{name}}',
self::TEMPLATE_SOME,
)]
final class Validator extends AbstractRule
{
use CanBindEvaluateRule;
public const TEMPLATE_NONE = '__none__';
public const TEMPLATE_SOME = '__some__';
/** @var array<Validatable> */
private array $rules = [];

View file

@ -1,16 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Test\Exceptions;
use Respect\Validation\Exceptions\NestedValidationException;
final class CompositeStubException extends NestedValidationException
{
}

View file

@ -1,69 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Exceptions;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Test;
use Respect\Validation\Message\Parameter\Stringify;
use Respect\Validation\Message\TemplateRenderer;
use Respect\Validation\Test\TestCase;
use Respect\Validation\Validatable;
#[Group('core')]
#[CoversClass(NestedValidationException::class)]
final class NestedValidationExceptionTest extends TestCase
{
#[Test]
public function getChildrenShouldReturnExceptionAddedByAddRelated(): void
{
$composite = $this->createNestedValidationException();
$node = $this->createValidationException();
$composite->addChild($node);
self::assertCount(1, $composite->getChildren());
self::assertContainsOnly(ValidationException::class, $composite->getChildren());
}
#[Test]
public function addingTheSameInstanceShouldAddJustOneSingleReference(): void
{
$composite = $this->createNestedValidationException();
$node = $this->createValidationException();
$composite->addChild($node);
$composite->addChild($node);
$composite->addChild($node);
self::assertCount(1, $composite->getChildren());
self::assertContainsOnly(ValidationException::class, $composite->getChildren());
}
public function createNestedValidationException(): NestedValidationException
{
return new NestedValidationException(
input: 'input',
id: 'id',
params: [],
template: Validatable::TEMPLATE_STANDARD,
templates: [],
formatter: new TemplateRenderer('strval', new Stringify())
);
}
public function createValidationException(): ValidationException
{
return new ValidationException(
input: 'input',
id: 'id',
params: [],
template: Validatable::TEMPLATE_STANDARD,
templates: [],
formatter: new TemplateRenderer('strval', new Stringify())
);
}
}