From 6075b4387371d3fa7db1afdf6712b63439a22573 Mon Sep 17 00:00:00 2001 From: Ruben Van Assche Date: Fri, 3 May 2024 11:08:01 +0200 Subject: [PATCH] Add initial support for union types --- src/DataPipes/CastPropertiesDataPipe.php | 11 ++++++-- tests/CreationTest.php | 35 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/DataPipes/CastPropertiesDataPipe.php b/src/DataPipes/CastPropertiesDataPipe.php index e3b2c338..559557d0 100644 --- a/src/DataPipes/CastPropertiesDataPipe.php +++ b/src/DataPipes/CastPropertiesDataPipe.php @@ -6,6 +6,7 @@ use Spatie\LaravelData\Casts\IterableItemCast; use Spatie\LaravelData\Casts\Uncastable; use Spatie\LaravelData\Enums\DataTypeKind; +use Spatie\LaravelData\Exceptions\CannotCreateData; use Spatie\LaravelData\Lazy; use Spatie\LaravelData\Optional; use Spatie\LaravelData\Support\Creation\CreationContext; @@ -87,9 +88,13 @@ protected function cast( ) { $context = $creationContext->next($property->type->dataClass, $property->name); - return $property->type->kind->isDataObject() - ? $context->from($value) - : $context->collect($value, $property->type->iterableClass); + try { + return $property->type->kind->isDataObject() + ? $context->from($value) + : $context->collect($value, $property->type->iterableClass); + } catch (CannotCreateData) { + return $value; + } } if ( diff --git a/tests/CreationTest.php b/tests/CreationTest.php index 59c9ac37..f9401c5a 100644 --- a/tests/CreationTest.php +++ b/tests/CreationTest.php @@ -1067,3 +1067,38 @@ public function __invoke(SimpleData $data) ->toBeArray() ->toEqual(['a', 'collection']); })->skip(fn () => config('data.features.cast_and_transform_iterables') === false); + +it('is possible to create an union type data object', function () { + $dataClass = new class () extends Data { + public string|SimpleData $property; + }; + + expect($dataClass::from(['property' => 'Hello World'])->property)->toBeInstanceOf(SimpleData::class); + + $dataClass = new class () extends Data { + public int|SimpleData $property; + }; + + expect($dataClass::from(['property' => 10])->property)->toBeInt(); + expect($dataClass::from(['property' => 'Hello World'])->property)->toBeInstanceOf(SimpleData::class); + + $dataClass = new class () extends Data { + public int|SimpleData|Optional|Lazy $property; + }; + + expect($dataClass::from(['property' => 10])->property)->toBeInt(); + expect($dataClass::from(['property' => 'Hello World'])->property)->toBeInstanceOf(SimpleData::class); + expect($dataClass::from(['property' => Lazy::create(fn () => 10)])->property)->toBeInstanceOf(Lazy::class); + expect($dataClass::from([])->property)->toBeInstanceOf(Optional::class); +}); + +it('is possible to create a union type data collectable', function () { + $dataClass = new class () extends Data { + /** @var array */ + public array $property; + }; + + expect($dataClass::from(['property' => [10, 'Hello World']])->property)->toEqual( + [10, SimpleData::from('Hello World')] + ); +})->todo();