respect-validation/library/NamespacedValidatorFactory.php
Henrique Moody 191922cf38
Rename RuleSpec to ValidatorSpec
That name makes more sense in relation to how the codebase currently
calls validators.
2026-01-05 17:36:35 +01:00

83 lines
2.7 KiB
PHP

<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation;
use ReflectionClass;
use ReflectionException;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Exceptions\InvalidClassException;
use Respect\Validation\Transformers\Transformer;
use Respect\Validation\Transformers\ValidatorSpec;
use function array_merge;
use function sprintf;
use function trim;
use function ucfirst;
final readonly class NamespacedValidatorFactory implements ValidatorFactory
{
/** @param array<int, string> $rulesNamespaces */
public function __construct(
private Transformer $transformer,
private array $rulesNamespaces,
) {
}
public function withNamespace(string $rulesNamespace): self
{
return clone ($this, ['rulesNamespaces' => [trim($rulesNamespace, '\\'), ...$this->rulesNamespaces]]);
}
/** @param array<int, mixed> $arguments */
public function create(string $ruleName, array $arguments = []): Validator
{
return $this->createValidatorSpec($this->transformer->transform(new ValidatorSpec($ruleName, $arguments)));
}
private function createValidatorSpec(ValidatorSpec $validatorSpec): Validator
{
$validator = $this->createRule($validatorSpec->name, $validatorSpec->arguments);
if ($validatorSpec->wrapper !== null) {
return $this->createRule(
$validatorSpec->wrapper->name,
array_merge($validatorSpec->wrapper->arguments, [$validator]),
);
}
return $validator;
}
/** @param array<int, mixed> $arguments */
private function createRule(string $ruleName, array $arguments = []): Validator
{
foreach ($this->rulesNamespaces as $namespace) {
try {
/** @var class-string<Validator> $name */
$name = $namespace . '\\' . ucfirst($ruleName);
$reflection = new ReflectionClass($name);
if (!$reflection->isSubclassOf(Validator::class)) {
throw new InvalidClassException(
sprintf('"%s" must be an instance of "%s"', $name, Validator::class),
);
}
if (!$reflection->isInstantiable()) {
throw new InvalidClassException(sprintf('"%s" must be instantiable', $name));
}
return $reflection->newInstanceArgs($arguments);
} catch (ReflectionException) {
continue;
}
}
throw new ComponentException(sprintf('"%s" is not a valid rule name', $ruleName));
}
}