diff --git a/src/Reflection/DataTransferObjectProperty.php b/src/Reflection/DataTransferObjectProperty.php index 5bbae955..abdf313d 100644 --- a/src/Reflection/DataTransferObjectProperty.php +++ b/src/Reflection/DataTransferObjectProperty.php @@ -7,6 +7,7 @@ use ReflectionClass; use ReflectionNamedType; use ReflectionProperty; +use ReflectionType; use ReflectionUnionType; use Spatie\DataTransferObject\Attributes\CastWith; use Spatie\DataTransferObject\Attributes\DefaultCast; @@ -84,7 +85,7 @@ private function resolveCaster(): ?Caster $attribute = $attributes[0]->newInstance(); return new $attribute->casterClass( - array_map(fn ($type) => $type->getName(), $this->extractTypes()), + array_map(fn ($type) => $this->resolveTypeName($type), $this->extractTypes()), ...$attribute->args ); } @@ -92,11 +93,13 @@ private function resolveCaster(): ?Caster private function resolveCasterFromType(): array { foreach ($this->extractTypes() as $type) { - if (! class_exists($type->getName())) { + $name = $this->resolveTypeName($type); + + if (! class_exists($name)) { continue; } - $reflectionClass = new ReflectionClass($type->getName()); + $reflectionClass = new ReflectionClass($name); do { $attributes = $reflectionClass->getAttributes(CastWith::class); @@ -167,4 +170,13 @@ private function extractTypes(): array ReflectionUnionType::class => $type->getTypes(), }; } + + private function resolveTypeName(ReflectionType $type): string + { + return match ($type->getName()) { + 'self' => $this->dataTransferObject::class, + 'parent' => get_parent_class($this->dataTransferObject), + default => $type->getName(), + }; + } } diff --git a/tests/DataTransferObjectTest.php b/tests/DataTransferObjectTest.php index 90c247d7..e5eed320 100644 --- a/tests/DataTransferObjectTest.php +++ b/tests/DataTransferObjectTest.php @@ -6,6 +6,8 @@ use Spatie\DataTransferObject\Tests\Dummy\ComplexDto; use Spatie\DataTransferObject\Tests\Dummy\ComplexDtoWithCastedAttributeHavingCast; use Spatie\DataTransferObject\Tests\Dummy\ComplexDtoWithNullableProperty; +use Spatie\DataTransferObject\Tests\Dummy\ComplexDtoWithParent; +use Spatie\DataTransferObject\Tests\Dummy\ComplexDtoWithSelf; use Spatie\DataTransferObject\Tests\Dummy\ComplexStrictDto; use Spatie\DataTransferObject\Tests\Dummy\WithDefaultValueDto; @@ -208,4 +210,34 @@ public function test_clone() $this->assertEquals('a', $clone->name); $this->assertEquals('a', $clone->other->name); } + + /** @test */ + public function create_with_nested_self() + { + $dto = new ComplexDtoWithSelf([ + 'name' => 'a', + 'other' => [ + 'name' => 'b', + ], + ]); + + $this->assertEquals('a', $dto->name); + $this->assertEquals('b', $dto->other->name); + $this->assertNull($dto->other->other); + } + + /** @test */ + public function create_with_nested_parent() + { + $dto = new ComplexDtoWithParent([ + 'name' => 'a', + 'other' => [ + 'name' => 'b', + ], + ]); + + $this->assertEquals('a', $dto->name); + $this->assertEquals('b', $dto->other->name); + $this->assertNull($dto->other->other); + } } diff --git a/tests/Dummy/ComplexDtoWithParent.php b/tests/Dummy/ComplexDtoWithParent.php new file mode 100644 index 00000000..ca7d802c --- /dev/null +++ b/tests/Dummy/ComplexDtoWithParent.php @@ -0,0 +1,10 @@ +