This commit is contained in:
icefox 2026-02-18 20:18:39 -03:00
parent bef42b3352
commit afb47c1977
No known key found for this signature in database
7 changed files with 56 additions and 26 deletions

View file

@ -7,7 +7,7 @@ namespace Icefox\DTO\Attributes;
use Attribute;
#[Attribute(Attribute::TARGET_PARAMETER)]
class FromMapper
class CastWith
{
/**
* @param class-string $class

18
src/Config.php Normal file
View file

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Icefox\DTO;
class Config
{
public static function getCaster(string $className): ?callable
{
return config('dto.cast.' . $className, null);
}
public static function getRules(string $className): ?callable
{
return config('dto.rules.' . $className, null);
}
}

View file

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Icefox\DTO;
use Icefox\DTO\Attributes\FromInput;
use Icefox\DTO\Attributes\FromMapper;
use Icefox\DTO\Attributes\CastWith;
use Icefox\DTO\Attributes\FromRouteParameter;
use Icefox\DTO\Support\RuleFactory;
use Icefox\DTO\Support\ValueFactory;
@ -78,7 +78,7 @@ trait DataObject
foreach ($parameters as $parameter) {
$parameterName = $parameter->reflection->getName();
if ($mapper = array_first($parameter->reflection->getAttributes(FromMapper::class))) {
if ($mapper = array_first($parameter->reflection->getAttributes(CastWith::class))) {
$value = App::call(
[App::make($mapper->newInstance()->class), 'map'],
['value' => $validator->getValue($parameterName)],

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Icefox\DTO\Support;
use Icefox\DTO\Attributes\CastWith;
use Icefox\DTO\Config;
use Icefox\DTO\Attributes\FromMapper;
use Icefox\DTO\ParameterMeta;
use Illuminate\Support\Facades\App;
@ -139,7 +141,7 @@ class RuleFactory
}
if ($type instanceof ReflectionNamedType && $name = $type->getName()) {
if ($globalRules = config('dto.rules.' . $name)) {
if ($globalRules = Config::getRules($name)) {
foreach ($globalRules($parameter->reflection, $parameter->tag->getType()) as $scopedPrefix => $values) {
$realPrefix = $root . $scopedPrefix;
$rules[$realPrefix] = array_values(array_unique(array_merge($rules[$realPrefix] ?? [], $values)));
@ -166,7 +168,7 @@ class RuleFactory
}
}
foreach ($parameter->reflection->getAttributes(FromMapper::class) as $attr) {
foreach ($parameter->reflection->getAttributes(CastWith::class) as $attr) {
$mapperClass = $attr->newInstance()->class;
if (method_exists($mapperClass, 'rules')) {
$subRules = App::call("$mapperClass@rules");

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Icefox\DTO\Support;
use Icefox\DTO\Attributes\CastWith;
use Icefox\DTO\Config;
use Illuminate\Support\Facades\App;
use ReflectionNamedType;
use ReflectionParameter;
@ -20,7 +22,7 @@ class ValueFactory
{
public static function constructObject(string $className, mixed $rawValue): object
{
if ($mapper = config('dto.mappers.' . $className, null)) {
if ($mapper = Config::getCaster($className)) {
return $mapper($rawValue);
}
@ -83,9 +85,22 @@ class ValueFactory
return null;
}
if (is_null($type)) {
$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);
}
$reflectedType = $reflection->getType();
if ($reflectedType instanceof ReflectionNamedType && $name = $reflectedType->getName()) {
if ($caster = Config::getCaster($name)) {
return App::call($caster, ['value' => $rawValue]);
}
return match ($name) {
'string' => $rawValue,
'bool' => boolval($rawValue),
@ -95,9 +110,7 @@ class ValueFactory
default => self::constructObject($name, $rawValue),
};
}
return $rawValue;
}
return self::resolveTypedValue($rawValue, $type);
}
}

View file

@ -4,11 +4,8 @@ use Icefox\DTO\Factories\CollectionFactory;
use Illuminate\Support\Collection;
return [
'cast' => [],
'rules' => [
Collection::class => CollectionFactory::rules(...),
],
'default' => [
'factories' => [
],
],
];

View file

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Tests\Classes;
use Carbon\CarbonPeriodImmutable;
use Icefox\DTO\Attributes\FromMapper;
use Icefox\DTO\Attributes\CastWith;
use Icefox\DTO\DataObject;
readonly class WithMapperObject
@ -13,7 +13,7 @@ readonly class WithMapperObject
use DataObject;
public function __construct(
#[FromMapper(CarbonPeriodMapper::class)]
#[CastWith(CarbonPeriodMapper::class)]
public CarbonPeriodImmutable $period,
) {}
}