mirror of
https://github.com/Respect/Validation.git
synced 2024-06-07 16:22:16 +02:00
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:
parent
3a6a71a1f8
commit
fdd8c5a978
|
@ -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
|
||||
) {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 = [];
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
}
|
|
@ -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())
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue