respect-validation/library/Factory.php
2025-12-18 19:03:39 +01:00

85 lines
2.5 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\Prefix;
use Respect\Validation\Transformers\RuleSpec;
use Respect\Validation\Transformers\Transformer;
use function array_merge;
use function sprintf;
use function trim;
use function ucfirst;
final class Factory
{
/** @var string[] */
private array $rulesNamespaces = ['Respect\\Validation\\Rules'];
public function __construct(
private readonly Transformer $transformer = new Prefix(),
) {
}
public function withRuleNamespace(string $rulesNamespace): self
{
$clone = clone $this;
$clone->rulesNamespaces[] = trim($rulesNamespace, '\\');
return $clone;
}
/** @param mixed[] $arguments */
public function rule(string $ruleName, array $arguments = []): Rule
{
return $this->createRuleSpec($this->transformer->transform(new RuleSpec($ruleName, $arguments)));
}
private function createRuleSpec(RuleSpec $ruleSpec): Rule
{
$rule = $this->createRule($ruleSpec->name, $ruleSpec->arguments);
if ($ruleSpec->wrapper !== null) {
return $this->createRule($ruleSpec->wrapper->name, array_merge($ruleSpec->wrapper->arguments, [$rule]));
}
return $rule;
}
/** @param mixed[] $arguments */
private function createRule(string $ruleName, array $arguments = []): Rule
{
foreach ($this->rulesNamespaces as $namespace) {
try {
/** @var class-string<Rule> $name */
$name = $namespace . '\\' . ucfirst($ruleName);
$reflection = new ReflectionClass($name);
if (!$reflection->isSubclassOf(Rule::class)) {
throw new InvalidClassException(
sprintf('"%s" must be an instance of "%s"', $name, Rule::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));
}
}