Remove previous validation engine

After many refactorings, no rules use the previous validation engine.
That means we can remove the unused code from the repository and switch
from the previous to the new validation engine everywhere.

This commit will also soft deprecate the methods "validate()", and
"check()" in all the rules and the "assert()" in all rules but the
Validator itself. That means using those methods will still be allowed,
but static analysis tools might complain.

This is a big step toward releasing the next major version, as the code
is pretty much the way it should be when I release the next version.
There's some documentation to be updated, and I would like to change the
behavior of a couple of rules.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2024-03-25 09:18:05 +01:00
parent ae369c4791
commit 66faefd695
No known key found for this signature in database
GPG key ID: 221E9281655813A6
113 changed files with 263 additions and 1092 deletions

View file

@ -42,7 +42,7 @@ create a validator that validates if a string is equal to "Hello World".
### Creating the rule ### Creating the rule
The rule itself needs to implement the `Validatable` interface but, it is The rule itself needs to implement the `Validatable` interface but, it is
convenient to just extend the `AbstractRule` class. convenient to just extend the `Simple` or `Standard` class.
Doing that, you'll only need to declare one method: `validate($input)`. Doing that, you'll only need to declare one method: `validate($input)`.
This method must return `true` or `false`. This method must return `true` or `false`.
@ -62,14 +62,15 @@ declare(strict_types=1);
namespace Respect\Validation\Rules; namespace Respect\Validation\Rules;
use Respect\Validation\Message\Template; use Respect\Validation\Message\Template;
use Respect\Validation\Rules\Core\Simple;
#[Template( #[Template(
'{{name}} must be a Hello World', '{{name}} must be a Hello World',
'{{name}} must not be a Hello World', '{{name}} must not be a Hello World',
)] )]
final class HelloWorld extends AbstractRule final class HelloWorld extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return $input === 'Hello World'; return $input === 'Hello World';
} }

View file

@ -3,23 +3,24 @@
You can also create and use your own rules. To do this, you will need to create You can also create and use your own rules. To do this, you will need to create
a rule and an exception to go with the rule. a rule and an exception to go with the rule.
To create a rule, you need to create a class that extends the AbstractRule class To create a rule, you need to create a class that implements the `Validatable` interface
and is within the Rules `namespace`. When the rule is called the logic inside the and is within the Rules `namespace`. It is convenient to just extend the `Simple` or
validate method will be executed. Here's how the class should look: `Standard` class. When the rule is called the logic inside the validate method will be
executed. Here's how the class should look:
```php ```php
namespace My\Validation\Rules; namespace My\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Message\Template; use Respect\Validation\Message\Template;
use Respect\Validation\Rules\Core\Simple;
#[Template( #[Template(
'{{name}} is something', '{{name}} is something',
'{{name}} is not something', '{{name}} is not something',
)] )]
final class Something extends AbstractRule final class Something extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
// Do something here with the $input and return a boolean value // Do something here with the $input and return a boolean value
} }

View file

@ -10,106 +10,26 @@ declare(strict_types=1);
namespace Respect\Validation\Exceptions; namespace Respect\Validation\Exceptions;
use InvalidArgumentException; use InvalidArgumentException;
use Respect\Validation\Message\Template;
use Respect\Validation\Message\TemplateRenderer;
use function count; final class ValidationException extends InvalidArgumentException implements Exception
use function preg_match;
class ValidationException extends InvalidArgumentException implements Exception
{ {
public const MODE_DEFAULT = 'default'; /** @param array<string, mixed> $messages */
public const MODE_NEGATIVE = 'negative';
private string $mode = self::MODE_DEFAULT;
/**
* @var array<Template>
*/
private readonly array $templates;
/**
* @param array<string, mixed> $params
* @param array<Template> $templates
*/
public function __construct( public function __construct(
private readonly mixed $input, string $message,
private readonly string $id, private readonly string $fullMessage,
private array $params, private readonly array $messages,
private string $template,
array $templates,
private readonly TemplateRenderer $formatter
) { ) {
if (count($templates) === 0) { parent::__construct($message);
$templates = [new Template('{{name}} must be valid', '{{name}} must not be valid')];
}
$this->templates = $templates;
parent::__construct($this->createMessage());
} }
public function getId(): string public function getFullMessage(): string
{ {
return $this->id; return $this->fullMessage;
} }
/** /** @return array<string, mixed> */
* @return mixed[] public function getMessages(): array
*/
public function getParams(): array
{ {
return $this->params; return $this->messages;
}
public function getParam(string $name): mixed
{
return $this->params[$name] ?? null;
}
public function updateMode(string $mode): void
{
$this->mode = $mode;
$this->message = $this->createMessage();
}
public function updateTemplate(string $template): void
{
$this->template = $template;
$this->message = $this->createMessage();
}
/**
* @param mixed[] $params
*/
public function updateParams(array $params): void
{
$this->params = $params;
$this->message = $this->createMessage();
}
public function hasCustomTemplate(): bool
{
return preg_match('/__[a-z_]+_/', $this->template) === 0;
}
private function getTemplateString(): string
{
foreach ($this->templates as $template) {
if ($template->id === $this->template) {
return $template->{$this->mode};
}
}
return $this->template;
}
private function createMessage(): string
{
return $this->formatter->render($this->getTemplateString(), $this->input, $this->params);
}
public function __toString(): string
{
return $this->getMessage();
} }
} }

View file

@ -1,33 +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 ValidatorException extends \Exception implements Exception
{
/** @param array<string, mixed> $messages */
public function __construct(
string $message,
private readonly string $fullMessage,
private readonly array $messages,
) {
parent::__construct($message);
}
public function getFullMessage(): string
{
return $this->fullMessage;
}
/** @return array<string, mixed> */
public function getMessages(): array
{
return $this->messages;
}
}

View file

@ -11,16 +11,12 @@ namespace Respect\Validation;
use ReflectionClass; use ReflectionClass;
use ReflectionException; use ReflectionException;
use ReflectionObject;
use Respect\Validation\Exceptions\ComponentException; use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Exceptions\InvalidClassException; use Respect\Validation\Exceptions\InvalidClassException;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Message\Parameter\Processor; use Respect\Validation\Message\Parameter\Processor;
use Respect\Validation\Message\Parameter\Raw; use Respect\Validation\Message\Parameter\Raw;
use Respect\Validation\Message\Parameter\Stringify; use Respect\Validation\Message\Parameter\Stringify;
use Respect\Validation\Message\Parameter\Trans; use Respect\Validation\Message\Parameter\Trans;
use Respect\Validation\Message\TemplateCollector;
use Respect\Validation\Message\TemplateRenderer;
use Respect\Validation\Transformers\DeprecatedAttribute; use Respect\Validation\Transformers\DeprecatedAttribute;
use Respect\Validation\Transformers\DeprecatedKey; use Respect\Validation\Transformers\DeprecatedKey;
use Respect\Validation\Transformers\DeprecatedKeyNested; use Respect\Validation\Transformers\DeprecatedKeyNested;
@ -33,7 +29,6 @@ use Respect\Validation\Transformers\RuleSpec;
use Respect\Validation\Transformers\Transformer; use Respect\Validation\Transformers\Transformer;
use function array_merge; use function array_merge;
use function lcfirst;
use function sprintf; use function sprintf;
use function trim; use function trim;
use function ucfirst; use function ucfirst;
@ -52,8 +47,6 @@ final class Factory
private Processor $processor; private Processor $processor;
private TemplateCollector $templateCollector;
private Transformer $transformer; private Transformer $transformer;
private static Factory $defaultInstance; private static Factory $defaultInstance;
@ -62,7 +55,6 @@ final class Factory
{ {
$this->translator = static fn (string $message) => $message; $this->translator = static fn (string $message) => $message;
$this->processor = new Raw(new Trans($this->translator, new Stringify())); $this->processor = new Raw(new Trans($this->translator, new Stringify()));
$this->templateCollector = new TemplateCollector();
$this->transformer = new DeprecatedAttribute( $this->transformer = new DeprecatedAttribute(
new DeprecatedKey( new DeprecatedKey(
new DeprecatedKeyValue( new DeprecatedKeyValue(
@ -126,26 +118,6 @@ final class Factory
return $this->createRuleSpec($this->transformer->transform(new RuleSpec($ruleName, $arguments))); return $this->createRuleSpec($this->transformer->transform(new RuleSpec($ruleName, $arguments)));
} }
/**
* @param mixed[] $extraParams
*/
public function exception(Validatable $validatable, mixed $input, array $extraParams = []): ValidationException
{
$reflection = new ReflectionObject($validatable);
$params = ['input' => $input] + $extraParams + $validatable->getParams();
$id = lcfirst($reflection->getShortName());
if ($validatable->getName() !== null) {
$id = $params['name'] = $validatable->getName();
}
$standardTemplate = $reflection->getMethod('getStandardTemplate');
$template = $validatable->getTemplate() ?? $standardTemplate->invoke($validatable, $input);
$templates = $this->templateCollector->extract($validatable);
$formatter = new TemplateRenderer($this->translator, $this->processor);
return new ValidationException($input, $id, $params, $template, $templates, $formatter);
}
public static function setDefaultInstance(self $defaultInstance): void public static function setDefaultInstance(self $defaultInstance): void
{ {
self::$defaultInstance = $defaultInstance; self::$defaultInstance = $defaultInstance;
@ -170,12 +142,18 @@ final class Factory
try { try {
/** @var class-string<Validatable> $name */ /** @var class-string<Validatable> $name */
$name = $namespace . '\\' . ucfirst($ruleName); $name = $namespace . '\\' . ucfirst($ruleName);
/** @var Validatable $rule */ $reflection = new ReflectionClass($name);
$rule = $this if (!$reflection->isSubclassOf(Validatable::class)) {
->createReflectionClass($name, Validatable::class) throw new InvalidClassException(
->newInstanceArgs($arguments); sprintf('"%s" must be an instance of "%s"', $name, Validatable::class)
);
}
return $rule; if (!$reflection->isInstantiable()) {
throw new InvalidClassException(sprintf('"%s" must be instantiable', $name));
}
return $reflection->newInstanceArgs($arguments);
} catch (ReflectionException) { } catch (ReflectionException) {
continue; continue;
} }
@ -183,24 +161,4 @@ final class Factory
throw new ComponentException(sprintf('"%s" is not a valid rule name', $ruleName)); throw new ComponentException(sprintf('"%s" is not a valid rule name', $ruleName));
} }
/**
* @param class-string $name
* @param class-string $parentName
*
* @return ReflectionClass<ValidationException|Validatable|object>
*/
private function createReflectionClass(string $name, string $parentName): ReflectionClass
{
$reflection = new ReflectionClass($name);
if (!$reflection->isSubclassOf($parentName) && $parentName !== $name) {
throw new InvalidClassException(sprintf('"%s" must be an instance of "%s"', $name, $parentName));
}
if (!$reflection->isInstantiable()) {
throw new InvalidClassException(sprintf('"%s" must be instantiable', $name));
}
return $reflection;
}
} }

View file

@ -9,62 +9,31 @@ declare(strict_types=1);
namespace Respect\Validation\Helpers; namespace Respect\Validation\Helpers;
use Respect\Validation\Exceptions\ValidationException; use Respect\Validation\Validator;
use Respect\Validation\Message\Parameter\Stringify;
use Respect\Validation\Message\TemplateRenderer;
use function sprintf;
use function trigger_error;
use const E_USER_DEPRECATED;
trait DeprecatedValidatableMethods trait DeprecatedValidatableMethods
{ {
/**
* @deprecated Calling `validate()` directly is deprecated, please use the `Validator::isValid()` class instead.
*/
public function validate(mixed $input): bool public function validate(mixed $input): bool
{ {
$this->triggerDeprecation(__METHOD__); return $this->evaluate($input)->isValid;
return false;
} }
/**
* @deprecated Calling `assert()` directly is deprecated, please use the `Validator::assert()` instead.
*/
public function assert(mixed $input): void public function assert(mixed $input): void
{ {
$this->triggerDeprecation(__FUNCTION__); Validator::create($this)->assert($input);
} }
/**
* @deprecated Calling `check()` directly is deprecated, please use the `Validator::assert()` instead.
*/
public function check(mixed $input): void public function check(mixed $input): void
{ {
$this->triggerDeprecation(__FUNCTION__); Validator::create($this)->assert($input);
}
/** @param array<string, mixed> $extraParameters */
public function reportError(mixed $input, array $extraParameters = []): ValidationException
{
$this->triggerDeprecation(__FUNCTION__);
return new ValidationException(
input: $input,
id: 'id',
params: $extraParameters,
template: 'template',
templates: [],
formatter: new TemplateRenderer(static fn (string $message) => $message, new Stringify()),
);
}
/** @return array<string, mixed> */
public function getParams(): array
{
$this->triggerDeprecation(__FUNCTION__);
return [];
}
private function triggerDeprecation(string $function): void
{
trigger_error(
sprintf('The "%s" method is deprecated, please use the "Validator" class instead.', $function),
E_USER_DEPRECATED
);
} }
} }

View file

@ -14,7 +14,7 @@ use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Message\Parameter\Processor; use Respect\Validation\Message\Parameter\Processor;
use Respect\Validation\Mode; use Respect\Validation\Mode;
use Respect\Validation\Result; use Respect\Validation\Result;
use Respect\Validation\Rule; use Respect\Validation\Validatable;
use Throwable; use Throwable;
use function call_user_func; use function call_user_func;
@ -71,7 +71,7 @@ final class StandardRenderer implements Renderer
} }
/** @return array<Template> */ /** @return array<Template> */
private function extractTemplates(Rule $rule): array private function extractTemplates(Validatable $rule): array
{ {
if (!isset($this->templates[$rule::class])) { if (!isset($this->templates[$rule::class])) {
$reflection = new ReflectionClass($rule); $reflection = new ReflectionClass($rule);

View file

@ -1,33 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Message;
use ReflectionClass;
final class TemplateCollector
{
/** @var array<string, array<Template>> */
private array $templates = [];
/**
* @return array<Template>
*/
public function extract(object $object): array
{
if (!isset($this->templates[$object::class])) {
$reflection = new ReflectionClass($object);
foreach ($reflection->getAttributes(Template::class) as $attribute) {
$this->templates[$object::class][] = $attribute->newInstance();
}
}
return $this->templates[$object::class] ?? [];
}
}

View file

@ -1,60 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Message;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Message\Parameter\Processor;
use Throwable;
use function call_user_func;
use function preg_replace_callback;
use function sprintf;
final class TemplateRenderer
{
/** @var callable */
private $translator;
public function __construct(
callable $translator,
private readonly Processor $processor
) {
$this->translator = $translator;
}
/**
* @param mixed[] $parameters
*/
public function render(string $template, mixed $input, array $parameters): string
{
$parameters['name'] ??= $this->processor->process('input', $input);
return (string) preg_replace_callback(
'/{{(\w+)(\|([^}]+))?}}/',
function (array $matches) use ($parameters) {
if (!isset($parameters[$matches[1]])) {
return $matches[0];
}
return $this->processor->process($matches[1], $parameters[$matches[1]], $matches[3] ?? null);
},
$this->translate($template)
);
}
private function translate(mixed $message): string
{
try {
return call_user_func($this->translator, (string) $message);
} catch (Throwable $throwable) {
throw new ComponentException(sprintf('Failed to translate "%s"', $message), 0, $throwable);
}
}
}

View file

@ -32,9 +32,9 @@ final class Result
public function __construct( public function __construct(
public readonly bool $isValid, public readonly bool $isValid,
public readonly mixed $input, public readonly mixed $input,
public readonly Rule $rule, public readonly Validatable $rule,
public readonly array $parameters = [], public readonly array $parameters = [],
string $template = Rule::TEMPLATE_STANDARD, string $template = Validatable::TEMPLATE_STANDARD,
public readonly Mode $mode = Mode::DEFAULT, public readonly Mode $mode = Mode::DEFAULT,
?string $name = null, ?string $name = null,
?string $id = null, ?string $id = null,
@ -50,9 +50,9 @@ final class Result
/** @param array<string, mixed> $parameters */ /** @param array<string, mixed> $parameters */
public static function failed( public static function failed(
mixed $input, mixed $input,
Rule $rule, Validatable $rule,
array $parameters = [], array $parameters = [],
string $template = Rule::TEMPLATE_STANDARD string $template = Validatable::TEMPLATE_STANDARD
): self { ): self {
return new self(false, $input, $rule, $parameters, $template); return new self(false, $input, $rule, $parameters, $template);
} }
@ -60,9 +60,9 @@ final class Result
/** @param array<string, mixed> $parameters */ /** @param array<string, mixed> $parameters */
public static function passed( public static function passed(
mixed $input, mixed $input,
Rule $rule, Validatable $rule,
array $parameters = [], array $parameters = [],
string $template = Rule::TEMPLATE_STANDARD string $template = Validatable::TEMPLATE_STANDARD
): self { ): self {
return new self(true, $input, $rule, $parameters, $template); return new self(true, $input, $rule, $parameters, $template);
} }

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;
interface Rule
{
public const TEMPLATE_STANDARD = '__standard__';
public function evaluate(mixed $input): Result;
public function getName(): ?string;
public function setName(string $name): static;
public function getTemplate(): ?string;
public function setTemplate(string $template): static;
}

View file

@ -1,97 +0,0 @@
<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Rules;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Factory;
use Respect\Validation\Result;
use Respect\Validation\Validatable;
abstract class AbstractRule implements Validatable
{
protected ?string $template = null;
private ?string $name = null;
public function assert(mixed $input): void
{
if ($this->validate($input)) {
return;
}
throw $this->reportError($input);
}
public function evaluate(mixed $input): Result
{
return new Result(
$this->validate($input),
$input,
$this,
$this->getParams(),
$this->getStandardTemplate($input)
);
}
public function check(mixed $input): void
{
$this->assert($input);
}
public function getName(): ?string
{
return $this->name;
}
/**
* @param mixed[] $extraParameters
*/
public function reportError(mixed $input, array $extraParameters = []): ValidationException
{
return Factory::getDefaultInstance()->exception($this, $input, $extraParameters);
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function setTemplate(string $template): static
{
$this->template = $template;
return $this;
}
public function getTemplate(): ?string
{
return $this->template;
}
/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return [];
}
protected function getStandardTemplate(mixed $input): string
{
return self::TEMPLATE_STANDARD;
}
public function __invoke(mixed $input): bool
{
return $this->validate($input);
}
}

View file

@ -11,8 +11,8 @@ namespace Respect\Validation\Rules;
use Respect\Validation\Message\Template; use Respect\Validation\Message\Template;
use Respect\Validation\Result; use Respect\Validation\Result;
use Respect\Validation\Rule;
use Respect\Validation\Rules\Core\Composite; use Respect\Validation\Rules\Core\Composite;
use Respect\Validation\Validatable;
use function array_filter; use function array_filter;
use function array_map; use function array_map;
@ -36,7 +36,7 @@ final class AllOf extends Composite
public function evaluate(mixed $input): Result public function evaluate(mixed $input): Result
{ {
$children = array_map(static fn (Rule $rule) => $rule->evaluate($input), $this->rules); $children = array_map(static fn (Validatable $rule) => $rule->evaluate($input), $this->rules);
$valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry && $result->isValid, true); $valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry && $result->isValid, true);
$failed = array_filter($children, static fn (Result $result): bool => !$result->isValid); $failed = array_filter($children, static fn (Result $result): bool => !$result->isValid);
$template = self::TEMPLATE_SOME; $template = self::TEMPLATE_SOME;

View file

@ -26,7 +26,7 @@ final class AlwaysInvalid extends Simple
{ {
public const TEMPLATE_SIMPLE = '__simple__'; public const TEMPLATE_SIMPLE = '__simple__';
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return false; return false;
} }

View file

@ -18,7 +18,7 @@ use Respect\Validation\Rules\Core\Simple;
)] )]
final class AlwaysValid extends Simple final class AlwaysValid extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return true; return true;
} }

View file

@ -11,8 +11,8 @@ namespace Respect\Validation\Rules;
use Respect\Validation\Message\Template; use Respect\Validation\Message\Template;
use Respect\Validation\Result; use Respect\Validation\Result;
use Respect\Validation\Rule;
use Respect\Validation\Rules\Core\Composite; use Respect\Validation\Rules\Core\Composite;
use Respect\Validation\Validatable;
use function array_map; use function array_map;
use function array_reduce; use function array_reduce;
@ -25,7 +25,7 @@ final class AnyOf extends Composite
{ {
public function evaluate(mixed $input): Result public function evaluate(mixed $input): Result
{ {
$children = array_map(static fn (Rule $rule) => $rule->evaluate($input), $this->rules); $children = array_map(static fn (Validatable $rule) => $rule->evaluate($input), $this->rules);
$valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry || $result->isValid, false); $valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry || $result->isValid, false);
return (new Result($valid, $input, $this))->withChildren(...$children); return (new Result($valid, $input, $this))->withChildren(...$children);

View file

@ -20,7 +20,7 @@ use function is_array;
)] )]
final class ArrayType extends Simple final class ArrayType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_array($input); return is_array($input);
} }

View file

@ -22,7 +22,7 @@ use function is_array;
)] )]
final class ArrayVal extends Simple final class ArrayVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_array($input) || $input instanceof ArrayAccess || $input instanceof SimpleXMLElement; return is_array($input) || $input instanceof ArrayAccess || $input instanceof SimpleXMLElement;
} }

View file

@ -22,7 +22,7 @@ use function preg_match;
)] )]
final class Base64 extends Simple final class Base64 extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -20,7 +20,7 @@ use function is_bool;
)] )]
final class BoolType extends Simple final class BoolType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_bool($input); return is_bool($input);
} }

View file

@ -24,7 +24,7 @@ use const FILTER_VALIDATE_BOOLEAN;
)] )]
final class BoolVal extends Simple final class BoolVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_bool(filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)); return is_bool(filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE));
} }

View file

@ -27,7 +27,7 @@ use function strval;
)] )]
final class Bsn extends Simple final class Bsn extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -20,7 +20,7 @@ use function is_callable;
)] )]
final class CallableType extends Simple final class CallableType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_callable($input); return is_callable($input);
} }

View file

@ -38,7 +38,7 @@ final class Callback extends Simple
$this->arguments = $arguments; $this->arguments = $arguments;
} }
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return (bool) call_user_func_array($this->callback, $this->getArguments($input)); return (bool) call_user_func_array($this->callback, $this->getArguments($input));
} }

View file

@ -22,7 +22,7 @@ use function preg_replace;
)] )]
final class Cnh extends Simple final class Cnh extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -25,7 +25,7 @@ use function str_split;
)] )]
final class Cnpj extends Simple final class Cnpj extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -13,8 +13,10 @@ use Respect\Validation\Result;
abstract class Simple extends Standard abstract class Simple extends Standard
{ {
abstract protected function isValid(mixed $input): bool;
public function evaluate(mixed $input): Result public function evaluate(mixed $input): Result
{ {
return new Result($this->validate($input), $input, $this); return new Result($this->isValid($input), $input, $this);
} }
} }

View file

@ -21,7 +21,7 @@ use function is_array;
)] )]
final class Countable extends Simple final class Countable extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_array($input) || $input instanceof CountableInterface; return is_array($input) || $input instanceof CountableInterface;
} }

View file

@ -23,7 +23,7 @@ use function preg_replace;
)] )]
final class Cpf extends Simple final class Cpf extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
// Code ported from jsfromhell.com // Code ported from jsfromhell.com
$c = preg_replace('/\D/', '', $input); $c = preg_replace('/\D/', '', $input);

View file

@ -23,7 +23,7 @@ use function is_scalar;
)] )]
final class Directory extends Simple final class Directory extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $input->isDir(); return $input->isDir();

View file

@ -37,7 +37,7 @@ final class Email extends Simple
$this->validator = $validator; $this->validator = $validator;
} }
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -22,7 +22,7 @@ use const FILTER_VALIDATE_INT;
)] )]
final class Even extends Simple final class Even extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (filter_var($input, FILTER_VALIDATE_INT) === false) { if (filter_var($input, FILTER_VALIDATE_INT) === false) {
return false; return false;

View file

@ -22,7 +22,7 @@ use function is_scalar;
)] )]
final class Executable extends Simple final class Executable extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $input->isExecutable(); return $input->isExecutable();

View file

@ -22,7 +22,7 @@ use function is_string;
)] )]
final class Exists extends Simple final class Exists extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
$input = $input->getPathname(); $input = $input->getPathname();

View file

@ -23,7 +23,7 @@ use const FILTER_VALIDATE_BOOLEAN;
)] )]
final class FalseVal extends Simple final class FalseVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === false; return filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === false;
} }

View file

@ -20,7 +20,7 @@ use function is_numeric;
)] )]
final class Fibonacci extends Simple final class Fibonacci extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_numeric($input)) { if (!is_numeric($input)) {
return false; return false;

View file

@ -22,7 +22,7 @@ use function is_string;
)] )]
final class File extends Simple final class File extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $input->isFile(); return $input->isFile();

View file

@ -21,7 +21,7 @@ use function is_numeric;
)] )]
final class Finite extends Simple final class Finite extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_numeric($input) && is_finite((float) $input); return is_numeric($input) && is_finite((float) $input);
} }

View file

@ -20,7 +20,7 @@ use function is_float;
)] )]
final class FloatType extends Simple final class FloatType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_float($input); return is_float($input);
} }

View file

@ -23,7 +23,7 @@ use const FILTER_VALIDATE_FLOAT;
)] )]
final class FloatVal extends Simple final class FloatVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_float(filter_var($input, FILTER_VALIDATE_FLOAT)); return is_float(filter_var($input, FILTER_VALIDATE_FLOAT));
} }

View file

@ -28,7 +28,7 @@ final class Hetu extends Simple
{ {
use CanValidateDateTime; use CanValidateDateTime;
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -103,7 +103,7 @@ final class Iban extends Simple
'VG' => 24, 'VG' => 24,
]; ];
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -33,10 +33,10 @@ final class Image extends Simple
$this->fileInfo = $fileInfo ?: new finfo(FILEINFO_MIME_TYPE); $this->fileInfo = $fileInfo ?: new finfo(FILEINFO_MIME_TYPE);
} }
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $this->validate($input->getPathname()); return $this->isValid($input->getPathname());
} }
if (!is_string($input)) { if (!is_string($input)) {

View file

@ -24,10 +24,7 @@ final class Imei extends Simple
{ {
private const IMEI_SIZE = 15; private const IMEI_SIZE = 15;
/** protected function isValid(mixed $input): bool
* @see https://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity
*/
public function validate(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;
@ -38,6 +35,6 @@ final class Imei extends Simple
return false; return false;
} }
return (new Luhn())->validate($numbers); return (new Luhn())->isValid($numbers);
} }
} }

View file

@ -21,7 +21,7 @@ use function is_numeric;
)] )]
final class Infinite extends Simple final class Infinite extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_numeric($input) && is_infinite((float) $input); return is_numeric($input) && is_infinite((float) $input);
} }

View file

@ -20,7 +20,7 @@ use function is_int;
)] )]
final class IntType extends Simple final class IntType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_int($input); return is_int($input);
} }

View file

@ -22,7 +22,7 @@ use function preg_match;
)] )]
final class IntVal extends Simple final class IntVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (is_int($input)) { if (is_int($input)) {
return true; return true;

View file

@ -32,7 +32,7 @@ final class Isbn extends Simple
'(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$', '(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$',
]; ];
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -20,7 +20,7 @@ use function is_iterable;
)] )]
final class IterableType extends Simple final class IterableType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_iterable($input); return is_iterable($input);
} }

View file

@ -21,7 +21,7 @@ final class IterableVal extends Simple
{ {
use CanValidateIterable; use CanValidateIterable;
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return $this->isIterable($input); return $this->isIterable($input);
} }

View file

@ -26,7 +26,7 @@ use const JSON_ERROR_NONE;
)] )]
final class Json extends Simple final class Json extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input) || $input === '') { if (!is_string($input) || $input === '') {
return false; return false;

View file

@ -27,14 +27,14 @@ final class LeapDate extends Simple
) { ) {
} }
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof DateTimeInterface) { if ($input instanceof DateTimeInterface) {
return $input->format('m-d') === '02-29'; return $input->format('m-d') === '02-29';
} }
if (is_scalar($input)) { if (is_scalar($input)) {
return $this->validate(DateTimeImmutable::createFromFormat($this->format, (string) $input)); return $this->isValid(DateTimeImmutable::createFromFormat($this->format, (string) $input));
} }
return false; return false;

View file

@ -25,7 +25,7 @@ use function strtotime;
)] )]
final class LeapYear extends Simple final class LeapYear extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (is_numeric($input)) { if (is_numeric($input)) {
$date = strtotime(sprintf('%d-02-29', (int) $input)); $date = strtotime(sprintf('%d-02-29', (int) $input));
@ -34,11 +34,11 @@ final class LeapYear extends Simple
} }
if (is_scalar($input)) { if (is_scalar($input)) {
return $this->validate((int) date('Y', (int) strtotime((string) $input))); return $this->isValid((int) date('Y', (int) strtotime((string) $input)));
} }
if ($input instanceof DateTimeInterface) { if ($input instanceof DateTimeInterface) {
return $this->validate($input->format('Y')); return $this->isValid($input->format('Y'));
} }
return false; return false;

View file

@ -21,7 +21,7 @@ use function mb_strtolower;
)] )]
final class Lowercase extends Simple final class Lowercase extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -25,19 +25,14 @@ use function str_split;
)] )]
final class Luhn extends Simple final class Luhn extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!(new Digit())->evaluate($input)->isValid) { if (!(new Digit())->evaluate($input)->isValid) {
return false; return false;
} }
return $this->isValid((string) $input);
}
private function isValid(string $input): bool
{
$sum = 0; $sum = 0;
$digits = array_map('intval', str_split($input)); $digits = array_map('intval', str_split((string) $input));
$numDigits = count($digits); $numDigits = count($digits);
$parity = $numDigits % 2; $parity = $numDigits % 2;
for ($i = 0; $i < $numDigits; ++$i) { for ($i = 0; $i < $numDigits; ++$i) {

View file

@ -21,7 +21,7 @@ use function preg_match;
)] )]
final class MacAddress extends Simple final class MacAddress extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -20,7 +20,7 @@ use function is_numeric;
)] )]
final class Negative extends Simple final class Negative extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_numeric($input)) { if (!is_numeric($input)) {
return false; return false;

View file

@ -26,7 +26,7 @@ use function str_split;
)] )]
final class NfeAccessKey extends Simple final class NfeAccessKey extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (mb_strlen($input) !== 44) { if (mb_strlen($input) !== 44) {
return false; return false;

View file

@ -29,7 +29,7 @@ use function str_split;
)] )]
final class Nif extends Simple final class Nif extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -26,7 +26,7 @@ use function str_split;
)] )]
final class Nip extends Simple final class Nip extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -22,7 +22,7 @@ use function preg_match;
)] )]
final class NoWhitespace extends Simple final class NoWhitespace extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (is_null($input)) { if (is_null($input)) {
return true; return true;

View file

@ -11,8 +11,8 @@ namespace Respect\Validation\Rules;
use Respect\Validation\Message\Template; use Respect\Validation\Message\Template;
use Respect\Validation\Result; use Respect\Validation\Result;
use Respect\Validation\Rule;
use Respect\Validation\Rules\Core\Composite; use Respect\Validation\Rules\Core\Composite;
use Respect\Validation\Validatable;
use function array_map; use function array_map;
use function array_reduce; use function array_reduce;
@ -25,7 +25,10 @@ final class NoneOf extends Composite
{ {
public function evaluate(mixed $input): Result public function evaluate(mixed $input): Result
{ {
$children = array_map(static fn (Rule $rule) => $rule->evaluate($input)->withInvertedMode(), $this->rules); $children = array_map(
static fn (Validatable $rule) => $rule->evaluate($input)->withInvertedMode(),
$this->rules
);
$valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry && $result->isValid, true); $valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry && $result->isValid, true);
return (new Result($valid, $input, $this))->withChildren(...$children); return (new Result($valid, $input, $this))->withChildren(...$children);

View file

@ -194,7 +194,7 @@ final class NotEmoji extends Simple
'\x{3299}', '\x{3299}',
]; ];
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -20,7 +20,7 @@ use function is_null;
)] )]
final class NullType extends Simple final class NullType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_null($input); return is_null($input);
} }

View file

@ -21,7 +21,7 @@ use function is_numeric;
)] )]
final class Number extends Simple final class Number extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_numeric($input)) { if (!is_numeric($input)) {
return false; return false;

View file

@ -20,7 +20,7 @@ use function is_numeric;
)] )]
final class NumericVal extends Simple final class NumericVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_numeric($input); return is_numeric($input);
} }

View file

@ -20,7 +20,7 @@ use function is_object;
)] )]
final class ObjectType extends Simple final class ObjectType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_object($input); return is_object($input);
} }

View file

@ -23,7 +23,7 @@ use const FILTER_VALIDATE_INT;
)] )]
final class Odd extends Simple final class Odd extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_numeric($input)) { if (!is_numeric($input)) {
return false; return false;

View file

@ -11,8 +11,8 @@ namespace Respect\Validation\Rules;
use Respect\Validation\Message\Template; use Respect\Validation\Message\Template;
use Respect\Validation\Result; use Respect\Validation\Result;
use Respect\Validation\Rule;
use Respect\Validation\Rules\Core\Composite; use Respect\Validation\Rules\Core\Composite;
use Respect\Validation\Validatable;
use function array_map; use function array_map;
use function array_reduce; use function array_reduce;
@ -25,7 +25,7 @@ final class OneOf extends Composite
{ {
public function evaluate(mixed $input): Result public function evaluate(mixed $input): Result
{ {
$children = array_map(static fn (Rule $rule) => $rule->evaluate($input), $this->rules); $children = array_map(static fn (Validatable $rule) => $rule->evaluate($input), $this->rules);
$valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry xor $result->isValid, false); $valid = array_reduce($children, static fn (bool $carry, Result $result) => $carry xor $result->isValid, false);
return (new Result($valid, $input, $this))->withChildren(...$children); return (new Result($valid, $input, $this))->withChildren(...$children);

View file

@ -22,7 +22,7 @@ use function sqrt;
)] )]
final class PerfectSquare extends Simple final class PerfectSquare extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_numeric($input) && floor(sqrt((float) $input)) == sqrt((float) $input); return is_numeric($input) && floor(sqrt((float) $input)) == sqrt((float) $input);
} }

View file

@ -21,7 +21,7 @@ use function preg_match;
)] )]
final class Pesel extends Simple final class Pesel extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -21,7 +21,7 @@ use function preg_match;
)] )]
final class PhpLabel extends Simple final class PhpLabel extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_string($input) && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $input); return is_string($input) && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $input);
} }

View file

@ -23,7 +23,7 @@ use function preg_replace;
)] )]
final class Pis extends Simple final class Pis extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -30,7 +30,7 @@ final class PolishIdCard extends Simple
private const ASCII_CODE_9 = 57; private const ASCII_CODE_9 = 57;
private const ASCII_CODE_A = 65; private const ASCII_CODE_A = 65;
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -31,7 +31,7 @@ use function strlen;
)] )]
final class PortugueseNif extends Simple final class PortugueseNif extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
// Validate format and length // Validate format and length
if (!is_string($input)) { if (!is_string($input)) {

View file

@ -20,7 +20,7 @@ use function is_numeric;
)] )]
final class Positive extends Simple final class Positive extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_numeric($input)) { if (!is_numeric($input)) {
return false; return false;

View file

@ -22,7 +22,7 @@ use function sqrt;
)] )]
final class PrimeNumber extends Simple final class PrimeNumber extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_numeric($input) || $input <= 1) { if (!is_numeric($input) || $input <= 1) {
return false; return false;

View file

@ -28,7 +28,7 @@ final class PublicDomainSuffix extends Simple
{ {
use CanValidateUndefined; use CanValidateUndefined;
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -23,7 +23,7 @@ use function is_string;
)] )]
final class Readable extends Simple final class Readable extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $input->isReadable(); return $input->isReadable();

View file

@ -20,7 +20,7 @@ use function is_resource;
)] )]
final class ResourceType extends Simple final class ResourceType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_resource($input); return is_resource($input);
} }

View file

@ -20,7 +20,7 @@ use function is_scalar;
)] )]
final class ScalarVal extends Simple final class ScalarVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_scalar($input); return is_scalar($input);
} }

View file

@ -22,7 +22,7 @@ use function preg_match;
)] )]
final class Slug extends Simple final class Slug extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input) || mb_strstr($input, '--')) { if (!is_string($input) || mb_strstr($input, '--')) {
return false; return false;

View file

@ -20,7 +20,7 @@ use function is_string;
)] )]
final class StringType extends Simple final class StringType extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_string($input); return is_string($input);
} }

View file

@ -22,7 +22,7 @@ use function method_exists;
)] )]
final class StringVal extends Simple final class StringVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return is_scalar($input) || (is_object($input) && method_exists($input, '__toString')); return is_scalar($input) || (is_object($input) && method_exists($input, '__toString'));
} }

View file

@ -22,7 +22,7 @@ use function is_string;
)] )]
final class SymbolicLink extends Simple final class SymbolicLink extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $input->isLink(); return $input->isLink();

View file

@ -239,7 +239,7 @@ final class Tld extends Simple
'ZERO', 'ZIP', 'ZM', 'ZONE', 'ZUERICH', 'ZW', 'ZERO', 'ZIP', 'ZM', 'ZONE', 'ZUERICH', 'ZW',
]; ];
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_scalar($input)) { if (!is_scalar($input)) {
return false; return false;

View file

@ -23,7 +23,7 @@ use const FILTER_VALIDATE_BOOLEAN;
)] )]
final class TrueVal extends Simple final class TrueVal extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === true; return filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === true;
} }

View file

@ -23,7 +23,7 @@ use const SORT_REGULAR;
)] )]
final class Unique extends Simple final class Unique extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_array($input)) { if (!is_array($input)) {
return false; return false;

View file

@ -23,10 +23,10 @@ use function is_uploaded_file;
)] )]
final class Uploaded extends Simple final class Uploaded extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $this->validate($input->getPathname()); return $this->isValid($input->getPathname());
} }
if ($input instanceof UploadedFileInterface) { if ($input instanceof UploadedFileInterface) {

View file

@ -21,7 +21,7 @@ use function mb_strtoupper;
)] )]
final class Uppercase extends Simple final class Uppercase extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -24,7 +24,7 @@ use function preg_match;
)] )]
final class Version extends Simple final class Version extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -23,7 +23,7 @@ use function is_writable;
)] )]
final class Writable extends Simple final class Writable extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $input->isWritable(); return $input->isWritable();

View file

@ -29,7 +29,7 @@ final class Yes extends Simple
) { ) {
} }
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
if (!is_string($input)) { if (!is_string($input)) {
return false; return false;

View file

@ -9,25 +9,17 @@ declare(strict_types=1);
namespace Respect\Validation; namespace Respect\Validation;
use Respect\Validation\Exceptions\ValidationException; interface Validatable
interface Validatable extends Rule
{ {
public function assert(mixed $input): void; public const TEMPLATE_STANDARD = '__standard__';
public function check(mixed $input): void; public function evaluate(mixed $input): Result;
/** public function getName(): ?string;
* @param mixed[] $extraParameters
*/ public function setName(string $name): static;
public function reportError(mixed $input, array $extraParameters = []): ValidationException;
public function getTemplate(): ?string; public function getTemplate(): ?string;
/** public function setTemplate(string $template): static;
* @return array<string, mixed>
*/
public function getParams(): array;
public function validate(mixed $input): bool;
} }

View file

@ -9,14 +9,14 @@ declare(strict_types=1);
namespace Respect\Validation; namespace Respect\Validation;
use Respect\Validation\Exceptions\ValidatorException; use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Helpers\CanBindEvaluateRule; use Respect\Validation\Helpers\CanBindEvaluateRule;
use Respect\Validation\Message\Formatter; use Respect\Validation\Message\Formatter;
use Respect\Validation\Message\StandardFormatter; use Respect\Validation\Message\StandardFormatter;
use Respect\Validation\Message\StandardRenderer; use Respect\Validation\Message\StandardRenderer;
use Respect\Validation\Mixins\StaticValidator; use Respect\Validation\Mixins\StaticValidator;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Rules\AllOf; use Respect\Validation\Rules\AllOf;
use Respect\Validation\Rules\Core\Standard;
use function count; use function count;
use function current; use function current;
@ -24,7 +24,7 @@ use function current;
/** /**
* @mixin StaticValidator * @mixin StaticValidator
*/ */
final class Validator extends AbstractRule final class Validator extends Standard
{ {
use CanBindEvaluateRule; use CanBindEvaluateRule;
@ -61,7 +61,7 @@ final class Validator extends AbstractRule
return $this->bindEvaluate($this->rule(), $this, $input); return $this->bindEvaluate($this->rule(), $this, $input);
} }
public function validate(mixed $input): bool public function isValid(mixed $input): bool
{ {
return $this->evaluate($input)->isValid; return $this->evaluate($input)->isValid;
} }
@ -74,11 +74,11 @@ final class Validator extends AbstractRule
} }
$templates = $this->templates; $templates = $this->templates;
if (count($templates) === 0 && $this->template != null) { if (count($templates) === 0 && $this->getTemplate() != null) {
$templates = ['__self__' => $this->template]; $templates = ['__self__' => $this->getTemplate()];
} }
throw new ValidatorException( throw new ValidationException(
$this->formatter->main($result, $templates), $this->formatter->main($result, $templates),
$this->formatter->full($result, $templates), $this->formatter->full($result, $templates),
$this->formatter->array($result, $templates), $this->formatter->array($result, $templates),
@ -99,6 +99,22 @@ final class Validator extends AbstractRule
return $this->rules; return $this->rules;
} }
/**
* @deprecated Use {@see isValid()} instead.
*/
public function validate(mixed $input): bool
{
return $this->evaluate($input)->isValid;
}
/**
* @deprecated Use {@see assert()} instead.
*/
public function check(mixed $input): void
{
$this->assert($input);
}
private function rule(): Validatable private function rule(): Validatable
{ {
if (count($this->rules) === 1) { if (count($this->rules) === 1) {

View file

@ -7,7 +7,7 @@
declare(strict_types=1); declare(strict_types=1);
use Respect\Validation\Exceptions\ValidatorException; use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Validatable; use Respect\Validation\Validatable;
use Symfony\Component\VarExporter\VarExporter; use Symfony\Component\VarExporter\VarExporter;
@ -18,7 +18,7 @@ function exceptionMessage(callable $callable, string $fallbackMessage = 'No exce
try { try {
$callable(); $callable();
echo $fallbackMessage . PHP_EOL; echo $fallbackMessage . PHP_EOL;
} catch (ValidatorException $exception) { } catch (ValidationException $exception) {
echo $exception->getMessage() . PHP_EOL; echo $exception->getMessage() . PHP_EOL;
} }
} }
@ -28,7 +28,7 @@ function exceptionMessages(callable $callable, string $fallbackMessage = 'No exc
try { try {
$callable(); $callable();
echo $fallbackMessage . PHP_EOL; echo $fallbackMessage . PHP_EOL;
} catch (ValidatorException $exception) { } catch (ValidationException $exception) {
echo VarExporter::export($exception->getMessages()) . PHP_EOL; echo VarExporter::export($exception->getMessages()) . PHP_EOL;
} }
} }
@ -38,7 +38,7 @@ function exceptionFullMessage(callable $callable, string $fallbackMessage = 'No
try { try {
$callable(); $callable();
echo $fallbackMessage . PHP_EOL; echo $fallbackMessage . PHP_EOL;
} catch (ValidatorException $exception) { } catch (ValidationException $exception) {
echo $exception->getFullMessage() . PHP_EOL; echo $exception->getFullMessage() . PHP_EOL;
} }
} }

View file

@ -11,7 +11,6 @@ namespace Respect\Validation\Test\Builders;
use Respect\Validation\Mode; use Respect\Validation\Mode;
use Respect\Validation\Result; use Respect\Validation\Result;
use Respect\Validation\Rule;
use Respect\Validation\Test\Rules\Stub; use Respect\Validation\Test\Rules\Stub;
use Respect\Validation\Validatable; use Respect\Validation\Validatable;
@ -23,7 +22,7 @@ final class ResultBuilder
private Mode $mode = Mode::DEFAULT; private Mode $mode = Mode::DEFAULT;
private string $template = Rule::TEMPLATE_STANDARD; private string $template = Validatable::TEMPLATE_STANDARD;
/** @var array<string, mixed> */ /** @var array<string, mixed> */
private array $parameters = []; private array $parameters = [];

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\ValidationException;
final class StubException extends ValidationException
{
}

View file

@ -13,7 +13,7 @@ use Respect\Validation\Rules\Core\Simple;
final class ConcreteSimple extends Simple final class ConcreteSimple extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return true; return true;
} }

View file

@ -9,11 +9,11 @@ declare(strict_types=1);
namespace Respect\Validation\Test\Rules; namespace Respect\Validation\Test\Rules;
use Respect\Validation\Rules\AbstractRule; use Respect\Validation\Rules\Core\Simple;
final class CustomRule extends AbstractRule final class CustomRule extends Simple
{ {
public function validate(mixed $input): bool protected function isValid(mixed $input): bool
{ {
return false; return false;
} }

Some files were not shown because too many files have changed in this diff Show more