mirror of
https://github.com/Respect/Validation.git
synced 2026-03-17 07:45:45 +01:00
There are a few "problems" with the current engine: - Allowing each rule to execute assert() and check() means duplication in some cases. - Because we use exceptions to assert/check, we can only invert a validation (with Not) if there are errors. That means that we have limited granularity control. - There is a lot of logic in the exceptions. That means that even after it throws an exception, something could still happen. We're stable on that front, but I want to simplify them. Besides, debugging exception code is painful because the stack trace does not go beyond the exception. Apart from that, there are many limitations with templating, and working that out in the current implementation makes it much harder. These changes will improve the library in many aspects, but they will also change the behavior and break backward compatibility. However, that's a price I'm willing to pay for the improvements we'll have. Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
144 lines
3.6 KiB
PHP
144 lines
3.6 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
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\Rules\AbstractRule;
|
|
use Respect\Validation\Rules\AllOf;
|
|
|
|
use function count;
|
|
use function current;
|
|
|
|
/**
|
|
* @mixin StaticValidator
|
|
*/
|
|
#[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 = [];
|
|
|
|
/** @var array<string, mixed> */
|
|
private array $templates = [];
|
|
|
|
public function __construct(
|
|
private readonly Factory $factory,
|
|
private readonly Formatter $formatter,
|
|
) {
|
|
}
|
|
|
|
public static function create(Validatable ...$rules): self
|
|
{
|
|
$validator = new self(
|
|
Factory::getDefaultInstance(),
|
|
new StandardFormatter(
|
|
new StandardRenderer(
|
|
Factory::getDefaultInstance()->getTranslator(),
|
|
Factory::getDefaultInstance()->getParameterProcessor(),
|
|
)
|
|
)
|
|
);
|
|
$validator->rules = $rules;
|
|
|
|
return $validator;
|
|
}
|
|
|
|
public function evaluate(mixed $input): Result
|
|
{
|
|
return $this->bindEvaluate($this->rule(), $this, $input);
|
|
}
|
|
|
|
public function validate(mixed $input): bool
|
|
{
|
|
return $this->evaluate($input)->isValid;
|
|
}
|
|
|
|
public function assert(mixed $input): void
|
|
{
|
|
$result = $this->evaluate($input);
|
|
if ($result->isValid) {
|
|
return;
|
|
}
|
|
|
|
$templates = $this->templates;
|
|
if (count($templates) === 0 && $this->template != null) {
|
|
$templates = ['__self__' => $this->template];
|
|
}
|
|
|
|
throw new ValidatorException(
|
|
$this->formatter->main($result, $templates),
|
|
$this->formatter->full($result, $templates),
|
|
$this->formatter->array($result, $templates),
|
|
);
|
|
}
|
|
|
|
/** @param array<string, mixed> $templates */
|
|
public function setTemplates(array $templates): self
|
|
{
|
|
$this->templates = $templates;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/** @return array<Validatable> */
|
|
public function getRules(): array
|
|
{
|
|
return $this->rules;
|
|
}
|
|
|
|
private function rule(): Validatable
|
|
{
|
|
if (count($this->rules) === 1) {
|
|
return current($this->rules);
|
|
}
|
|
|
|
return new AllOf(...$this->rules);
|
|
}
|
|
|
|
/**
|
|
* @param mixed[] $arguments
|
|
*/
|
|
public static function __callStatic(string $ruleName, array $arguments): self
|
|
{
|
|
return self::create()->__call($ruleName, $arguments);
|
|
}
|
|
|
|
/**
|
|
* @param mixed[] $arguments
|
|
*/
|
|
public function __call(string $ruleName, array $arguments): self
|
|
{
|
|
$this->rules[] = $this->factory->rule($ruleName, $arguments);
|
|
|
|
return $this;
|
|
}
|
|
}
|