diff --git a/src/DataObject.php b/src/DataObject.php index c6b05d8..cc2fcf3 100644 --- a/src/DataObject.php +++ b/src/DataObject.php @@ -78,9 +78,9 @@ trait DataObject foreach ($parameters as $parameter) { $parameterName = $parameter->reflection->getName(); - if ($mapper = array_first($parameter->reflection->getAttributes(CastWith::class))) { + if ($castWith = array_first($parameter->reflection->getAttributes(CastWith::class))) { $value = App::call( - [App::make($mapper->newInstance()->class), 'map'], + [App::make($castWith->newInstance()->class), 'cast'], ['value' => $validator->getValue($parameterName)], ); $mappedInput[$parameterName] = $value; diff --git a/tests/Casters/CasterTest.php b/tests/Casters/CasterTest.php new file mode 100644 index 0000000..c8e6a59 --- /dev/null +++ b/tests/Casters/CasterTest.php @@ -0,0 +1,71 @@ + []]); + }); + + it('uses CastWith attribute over global config caster', function () { + $globalCaster = function (mixed $value): SimpleValue { + return new SimpleValue($value['value'] * 3); + }; + config(['dto.cast.' . SimpleValue::class => $globalCaster]); + + $object = WithSpecificCaster::fromArray([ + 'value' => ['value' => 5], + ]); + + expect($object->value->value)->toBe(10); // 5 * 2 + }); + + it('falls back to global config caster when no CastWith attribute', function () { + $globalCaster = function (mixed $value): SimpleValue { + return new SimpleValue($value['value'] * 3); + }; + config(['dto.cast.' . SimpleValue::class => $globalCaster]); + + $object = WithGlobalCaster::fromArray([ + 'value' => ['value' => 5], + ]); + + expect($object->value->value)->toBe(15); // 5 * 3 + }); + + it('falls back to default construction when no caster exists', function () { + $object = WithoutCaster::fromArray([ + 'value' => ['value' => 5], + ]); + expect($object)->toBeInstanceOf(WithoutCaster::class); + }); +}); + +describe('caster with rules', function () { + beforeEach(function () { + config(['dto.cast' => []]); + }); + + it('validates input using caster rules before casting', function () { + expect(fn() => WithSpecificCaster::fromArray([ + 'value' => [], + ]))->toThrow(ValidationException::class); + }); + + it('accepts valid input and casts correctly', function () { + $object = WithSpecificCaster::fromArray([ + 'value' => ['value' => 10], + ]); + + expect($object->value->value)->toBe(20); // 10 * 2 + }); +}); diff --git a/tests/Casters/SimpleValue.php b/tests/Casters/SimpleValue.php new file mode 100644 index 0000000..1f08683 --- /dev/null +++ b/tests/Casters/SimpleValue.php @@ -0,0 +1,10 @@ + ['required', 'numeric'], + ]; + } +} diff --git a/tests/Casters/WithGlobalCaster.php b/tests/Casters/WithGlobalCaster.php new file mode 100644 index 0000000..98b39ef --- /dev/null +++ b/tests/Casters/WithGlobalCaster.php @@ -0,0 +1,16 @@ +