input mapping

This commit is contained in:
icefox 2026-02-25 16:03:00 -03:00
parent bba10b455f
commit fc46fe20ee
No known key found for this signature in database
29 changed files with 193 additions and 887 deletions

View file

@ -13,6 +13,8 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Validator;
use Psr\Log\LoggerInterface;
use ReflectionNamedType;
use phpDocumentor\Reflection\Types\AbstractList;
class DataObjectFactory
{
@ -21,7 +23,8 @@ class DataObjectFactory
*/
public static function fromRequest(string $class, Request $request): ?object
{
$routeParameters = $request->route() instanceof Route ? $request->route()->parameters() : [];
$route = $request->route();
$routeParameters = $route instanceof Route ? $route->parameters() : [];
return static::fromArray($class, $request->input(), $routeParameters);
}
@ -52,7 +55,6 @@ class DataObjectFactory
return ValueFactory::make($class, $validator->validated());
}
/**
* @param class-string $class
* @param array<string,mixed> $rawInput
@ -67,6 +69,7 @@ class DataObjectFactory
): array {
$input = [];
$parameters = ReflectionHelper::getParametersMeta($class);
foreach ($parameters as $parameter) {
$parameterName = $parameter->reflection->getName();
@ -77,17 +80,51 @@ class DataObjectFactory
}
}
$reflectionType = $parameter->reflection->getType();
$namedType = $reflectionType instanceof ReflectionNamedType ? $reflectionType->getName() : null;
$annotatedType = $parameter->tag?->getType();
$isListType
= $parameter->reflection->isArray()
|| in_array($namedType, config('dto.listTypes', []))
|| in_array($annotatedType?->__toString(), config('dto.listTypes', []))
|| $annotatedType instanceof AbstractList;
foreach ($parameter->reflection->getAttributes(FromInput::class) as $attr) {
if ($value = $rawInput[$attr->newInstance()->name] ?? null) {
$input[$parameterName] = $value;
if ($valueType = ReflectionHelper::getListParameterValueType($parameter->tag)) {
$input[$parameterName] = $isListType
? array_map(
fn($element) => self::mapInput($valueType, $element, $routeParameters, $logger),
$value,
)
: self::mapInput($valueType, $value, $routeParameters, $logger);
} else {
$input[$parameterName] = $value;
}
continue 2;
}
}
if ($value = $rawInput[$parameterName] ?? null) {
$input[$parameterName] = $value;
if ($valueType = ReflectionHelper::getListParameterValueType($parameter->tag)) {
$input[$parameterName] = $isListType
? array_map(
fn($element) => self::mapInput($valueType, $element, $routeParameters, $logger),
$rawInput[$parameterName],
)
: self::mapInput($valueType, $rawInput[$parameterName], $routeParameters, $logger);
continue;
}
if ($reflectionType instanceof ReflectionNamedType) {
$input[$parameterName] = $reflectionType->isBuiltin()
? $rawInput[$parameterName]
: self::mapInput($reflectionType->__toString(), $rawInput[$parameterName], $routeParameters, $logger);
continue;
}
$input[$parameterName] = $rawInput[$parameterName];
}
$logger->debug('input', $input);
return $input;

View file

@ -5,6 +5,8 @@ namespace Icefox\DTO;
use ReflectionParameter;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\PseudoTypes\Generic;
use phpDocumentor\Reflection\Types\AbstractList;
use phpDocumentor\Reflection\Types\ContextFactory;
use phpDocumentor\Reflection\DocBlockFactory;
use ReflectionClass;
@ -44,4 +46,21 @@ class ReflectionHelper
);
return self::$cache[$class];
}
public static function getListParameterValueType(?Param $param): ?string
{
$type = $param?->getType();
if ($type instanceof AbstractList) {
return $type->getValueType()->__toString();
}
if (!$type instanceof Generic) {
return null;
}
$subtypes = $type->getTypes();
return count($subtypes) > 1 ? $subtypes[1]->__toString() : $subtypes[0]->__toString();
}
}