refactor rules out of DataObject

This commit is contained in:
icefox 2026-02-19 15:34:33 -03:00
parent 77d1aebc0a
commit 74f151df07
No known key found for this signature in database
5 changed files with 115 additions and 93 deletions

View file

@ -5,9 +5,12 @@ declare(strict_types=1);
namespace Icefox\DTO\Support;
use Icefox\DTO\Attributes\CastWith;
use Icefox\DTO\Attributes\OverwriteRules;
use Icefox\DTO\Config;
use Icefox\DTO\Attributes\FromMapper;
use Icefox\DTO\Log;
use Icefox\DTO\ParameterMeta;
use Icefox\DTO\ReflectionHelper;
use Illuminate\Support\Facades\App;
use Illuminate\Validation\Rule;
use ReflectionClass;
@ -29,8 +32,6 @@ use phpDocumentor\Reflection\Types\Object_;
class RuleFactory
{
protected static array $cache = [];
/**
* @return array<string, array<string|Rule>>
*/
@ -57,7 +58,7 @@ class RuleFactory
} elseif ($type instanceof Float_ || $type instanceof Integer) {
$rules[$prefix][] = 'numeric';
} elseif ($type instanceof Object_) {
$paramsSub = self::getParametersMeta($type->getFqsen()->__toString());
$paramsSub = ReflectionHelper::getParametersMeta($type->getFqsen()->__toString());
$rules = array_merge(
$rules,
self::infer($paramsSub, $prefix . '.'),
@ -66,39 +67,6 @@ class RuleFactory
return $rules;
}
/**
* @param class-string $class
* @return array<ParameterMeta>
*/
public static function getParametersMeta(string $class): array
{
if (array_key_exists($class, self::$cache)) {
return self::$cache[$class];
}
$reflection = new ReflectionClass($class);
$constructor = $reflection->getConstructor();
try {
$docblockParams = (DocBlockFactory::createInstance())->create(
$constructor->getDocComment(),
(new ContextFactory())->createFromReflector($constructor),
)->getTagsByName('param');
} catch (\Exception) {
$docblockParams = [];
}
self::$cache[$class] = array_map(
fn(ReflectionParameter $p) => new ParameterMeta(
$p,
array_find(
$docblockParams,
fn(Tag $tag) => $tag instanceof Param ? $tag->getVariableName() == $p->getName() : false,
),
),
$constructor->getParameters(),
);
return self::$cache[$class];
}
/**
* @param array<ParameterMeta> $parameters
* @return array<string,array<int,string|Rule>>
@ -160,7 +128,7 @@ class RuleFactory
$rules[$root][] = Rule::enum($name);
}
} else {
$paramsSub = self::getParametersMeta($type->getName());
$paramsSub = ReflectionHelper::getParametersMeta($type->getName());
$rules = array_merge(
$rules,
self::infer($paramsSub, $root . '.'),
@ -190,4 +158,48 @@ class RuleFactory
return $rules;
}
public function __construct(public Log $log) {}
/**
* @param class-string $class
* @return array<string,array<int, string>>
*/
public function make(string $class): array
{
$parameters = ReflectionHelper::getParametersMeta($class);
$classReflection = new ReflectionClass($class);
$hasRulesMethod = $classReflection->hasMethod('rules');
$customRules = $hasRulesMethod ? App::call("$class::rules", []) : [];
if ($hasRulesMethod && !empty($classReflection->getMethod('rules')->getAttributes(OverwriteRules::class))) {
$rules = $customRules;
} else {
$inferredRules = RuleFactory::infer($parameters, '');
$rules = self::mergeRules($inferredRules, $customRules);
}
$this->log->rules($rules);
return $rules;
}
/**
* @param array<string,array<int, string>> $inferredRules
* @param array<string,array<int, string>> $customRules
* @return array<string,array<int, string>>
*/
protected function mergeRules(array $inferredRules, array $customRules): array
{
$merged = $inferredRules;
foreach ($customRules as $key => $rules) {
if (isset($merged[$key])) {
$merged[$key] = array_values(array_unique(array_merge($merged[$key], $rules)));
} else {
$merged[$key] = $rules;
}
}
return $merged;
}
}