workbench, tests
This commit is contained in:
parent
d83a324eb0
commit
367858c97c
27 changed files with 568 additions and 410 deletions
|
|
@ -5,10 +5,14 @@ declare(strict_types=1);
|
|||
namespace Icefox\DTO\Support;
|
||||
|
||||
use Icefox\DTO\Attributes\CastWith;
|
||||
use Icefox\DTO\Attributes\Flat;
|
||||
use Icefox\DTO\Config;
|
||||
use Icefox\DTO\ParameterMeta;
|
||||
use Icefox\DTO\ReflectionHelper;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionParameter;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Param;
|
||||
use phpDocumentor\Reflection\PseudoTypes\Generic;
|
||||
use phpDocumentor\Reflection\Type;
|
||||
use phpDocumentor\Reflection\Types\AbstractList;
|
||||
|
|
@ -35,31 +39,37 @@ class ValueFactory
|
|||
return App::makeWith($className, $rawValue);
|
||||
}
|
||||
|
||||
public static function resolveTypedValue(mixed $rawValue, Type $type): mixed
|
||||
public static function resolveAnnotatedValue(Type $type, mixed $rawValue): mixed
|
||||
{
|
||||
if ($type instanceof Nullable) {
|
||||
$type = $type->getActualType();
|
||||
}
|
||||
|
||||
if ($type instanceof Generic) {
|
||||
$types = $type->getTypes();
|
||||
$innerType = count($types) === 2 ? $types[1] : $types[0];
|
||||
$result = [];
|
||||
foreach ($rawValue as $key => $value) {
|
||||
$result[$key] = self::resolveTypedValue($value, $innerType);
|
||||
}
|
||||
return new ($type->getFqsen()->__toString())($result);
|
||||
}
|
||||
|
||||
if ($type instanceof AbstractList) {
|
||||
$innerType = $type->getValueType();
|
||||
$result = [];
|
||||
foreach ($rawValue as $key => $value) {
|
||||
$result[$key] = self::resolveTypedValue($value, $innerType);
|
||||
$result[$key] = self::resolveAnnotatedValue($innerType, $value);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($type instanceof Generic) {
|
||||
$types = $type->getTypes();
|
||||
$innerType = count($types) === 2 ? $types[1] : $types[0];
|
||||
if (is_array($rawValue)) {
|
||||
$innerValues = [];
|
||||
foreach ($rawValue as $key => $value) {
|
||||
$innerValues[$key] = self::resolveAnnotatedValue($innerType, $value);
|
||||
}
|
||||
return array_key_exists(0, $rawValue)
|
||||
? new ($type->getFqsen()->__toString())($innerValues)
|
||||
: App::makeWith($type->getFqsen()->__toString(), $innerValues);
|
||||
}
|
||||
$value = self::resolveAnnotatedValue($innerType, $rawValue);
|
||||
return new ($type->getFqsen()->__toString())($value);
|
||||
}
|
||||
|
||||
if ($type instanceof Boolean) {
|
||||
return boolval($rawValue);
|
||||
}
|
||||
|
|
@ -73,44 +83,70 @@ class ValueFactory
|
|||
}
|
||||
|
||||
if ($type instanceof Object_) {
|
||||
return self::constructObject($type->getFqsen()->__toString(), $rawValue);
|
||||
return self::make($type->getFqsen()->__toString(), $rawValue);
|
||||
}
|
||||
|
||||
return $rawValue;
|
||||
}
|
||||
|
||||
public static function resolveValue(mixed $rawValue, ?Type $type, ReflectionParameter $reflection): mixed
|
||||
public static function resolveDeclaredTypeValue(ReflectionNamedType $parameter, mixed $rawValue): mixed
|
||||
{
|
||||
if ($reflection->allowsNull() && is_null($rawValue)) {
|
||||
return null;
|
||||
}
|
||||
return match ($parameter->getName()) {
|
||||
'string' => $rawValue,
|
||||
'bool' => boolval($rawValue),
|
||||
'int' => intval($rawValue),
|
||||
'float' => floatval($rawValue),
|
||||
'array' => $rawValue,
|
||||
default => self::make($parameter->getName(), $rawValue),
|
||||
|
||||
$castWithAttrs = $reflection->getAttributes(CastWith::class);
|
||||
if ($withCast = $reflection->getAttributes(CastWith::class)[0] ?? null) {
|
||||
$caster = $withCast->newInstance()->class;
|
||||
return App::call("$caster@cast", ['value' => $rawValue]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!is_null($type)) {
|
||||
return self::resolveTypedValue($rawValue, $type);
|
||||
}
|
||||
public static function make(string $class, array $input): object
|
||||
{
|
||||
$parameters = ReflectionHelper::getParametersMeta($class);
|
||||
$arguments = [];
|
||||
foreach ($parameters as $parameter) {
|
||||
$name = $parameter->reflection->getName();
|
||||
|
||||
$reflectedType = $reflection->getType();
|
||||
if ($reflectedType instanceof ReflectionNamedType && $name = $reflectedType->getName()) {
|
||||
if ($caster = Config::getCaster($name)) {
|
||||
return App::call($caster, ['value' => $rawValue]);
|
||||
$parameterArgs = empty($parameter->reflection->getAttributes(Flat::class)) ? ($input[$name] ?? null) : $input;
|
||||
|
||||
if (is_null($parameterArgs)) {
|
||||
if ($parameter->reflection->allowsNull()) {
|
||||
$arguments[$name] = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
return match ($name) {
|
||||
'string' => $rawValue,
|
||||
'bool' => boolval($rawValue),
|
||||
'int' => intval($rawValue),
|
||||
'float' => floatval($rawValue),
|
||||
'array' => $rawValue,
|
||||
default => self::constructObject($name, $rawValue),
|
||||
};
|
||||
}
|
||||
if ($caster = $parameter->reflection->getAttributes(CastWith::class)[0] ?? null) {
|
||||
$caster = $caster->newInstance()->class;
|
||||
$arguments[$name] = App::call("$caster@cast", ['data' => $parameterArgs]);
|
||||
continue;
|
||||
}
|
||||
|
||||
return $rawValue;
|
||||
$parameterClass = $parameter->reflection->getClass()?->getName();
|
||||
|
||||
$type = $parameter->tag?->getType();
|
||||
if (empty($parameterClass) && $type instanceof Object_) {
|
||||
$parameterClass = $type->getFqsen();
|
||||
}
|
||||
if (!empty($parameterClass) && $caster = config('dto.cast.' . $parameterClass, null)) {
|
||||
$arguments[$name] = App::call($caster, ['data' => $parameterArgs]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($parameter->tag instanceof Param) {
|
||||
$arguments[$name] = self::resolveAnnotatedValue($type, $parameterArgs);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($parameter->reflection->getType() instanceof ReflectionNamedType) {
|
||||
$arguments[$name] = self::resolveDeclaredTypeValue($parameter->reflection->getType(), $parameterArgs);
|
||||
continue;
|
||||
}
|
||||
|
||||
$arguments[$name] = $parameterArgs;
|
||||
}
|
||||
return App::makeWith($class, $arguments);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue