diff --git a/src/DataPipes/CastPropertiesDataPipe.php b/src/DataPipes/CastPropertiesDataPipe.php index e3b2c338d..559557d05 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 59c9ac37c..f9401c5ab 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();