diff --git a/tests/Fakes/Models/DummyModelWithPropertyMorphableCast.php b/tests/Fakes/Models/DummyModelWithPropertyMorphableCast.php new file mode 100644 index 00000000..ce1bfe6f --- /dev/null +++ b/tests/Fakes/Models/DummyModelWithPropertyMorphableCast.php @@ -0,0 +1,19 @@ + AbstractPropertyMorphableData::class, + 'data_collection' => SimpleDataCollection::class.':'.AbstractPropertyMorphableData::class, + ]; + + protected $table = 'dummy_model_with_casts'; + + public $timestamps = false; +} diff --git a/tests/Support/EloquentCasts/DataCollectionEloquentCastTest.php b/tests/Support/EloquentCasts/DataCollectionEloquentCastTest.php index 97efc5d1..676e6d42 100644 --- a/tests/Support/EloquentCasts/DataCollectionEloquentCastTest.php +++ b/tests/Support/EloquentCasts/DataCollectionEloquentCastTest.php @@ -11,6 +11,9 @@ use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithCasts; use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithCustomCollectionCasts; use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithDefaultCasts; +use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithPropertyMorphableCast; +use Spatie\LaravelData\Tests\Fakes\PropertyMorphableData\PropertyMorphableDataA; +use Spatie\LaravelData\Tests\Fakes\PropertyMorphableData\PropertyMorphableDataB; use Spatie\LaravelData\Tests\Fakes\SimpleData; use Spatie\LaravelData\Tests\Fakes\SimpleDataCollection; @@ -170,3 +173,29 @@ expect($model->abstract_collection[0])->toBeInstanceOf(AbstractDataA::class); expect($model->abstract_collection[1])->toBeInstanceOf(AbstractDataB::class); }); + +it('can load and save an abstract property-morphable data collection', function () { + $abstractA = new PropertyMorphableDataA('foo'); + $abstractB = new PropertyMorphableDataB('bar'); + + $modelId = DummyModelWithPropertyMorphableCast::create([ + 'data_collection' => [$abstractA, $abstractB], + ])->id; + + assertDatabaseHas(DummyModelWithPropertyMorphableCast::class, [ + 'data_collection' => json_encode([ + ['a' => 'foo', 'variant' => 'a'], + ['b' => 'bar', 'variant' => 'b'], + ], JSON_PRETTY_PRINT), + ]); + + $model = DummyModelWithPropertyMorphableCast::find($modelId); + + expect($model->data_collection[0]) + ->toBeInstanceOf(PropertyMorphableDataA::class) + ->a->toBe('foo'); + + expect($model->data_collection[1]) + ->toBeInstanceOf(PropertyMorphableDataB::class) + ->b->toBe('bar'); +}); diff --git a/tests/Support/EloquentCasts/DataEloquentCastTest.php b/tests/Support/EloquentCasts/DataEloquentCastTest.php index 4b291512..ba875728 100644 --- a/tests/Support/EloquentCasts/DataEloquentCastTest.php +++ b/tests/Support/EloquentCasts/DataEloquentCastTest.php @@ -12,6 +12,8 @@ use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithCasts; use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithDefaultCasts; use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithEncryptedCasts; +use Spatie\LaravelData\Tests\Fakes\Models\DummyModelWithPropertyMorphableCast; +use Spatie\LaravelData\Tests\Fakes\PropertyMorphableData\PropertyMorphableDataA; use Spatie\LaravelData\Tests\Fakes\SimpleData; use Spatie\LaravelData\Tests\Fakes\SimpleDataWithDefaultValue; @@ -183,3 +185,21 @@ expect($isEncrypted)->toBeTrue(); }); + +it('can load and save an abstract property-morphable data object', function () { + $abstractA = new PropertyMorphableDataA('foo'); + + $modelId = DummyModelWithPropertyMorphableCast::create([ + 'data' => $abstractA, + ])->id; + + assertDatabaseHas(DummyModelWithPropertyMorphableCast::class, [ + 'data' => json_encode(['a' => 'foo', 'variant' => 'a']), + ]); + + $model = DummyModelWithPropertyMorphableCast::find($modelId); + + expect($model->data) + ->toBeInstanceOf(PropertyMorphableDataA::class) + ->a->toBe('foo'); +}); diff --git a/tests/ValidationTest.php b/tests/ValidationTest.php index d6e1dff9..e08c2f8c 100644 --- a/tests/ValidationTest.php +++ b/tests/ValidationTest.php @@ -55,6 +55,8 @@ use Spatie\LaravelData\Tests\Fakes\MultiData; use Spatie\LaravelData\Tests\Fakes\NestedData; use Spatie\LaravelData\Tests\Fakes\NestedNullableData; +use Spatie\LaravelData\Tests\Fakes\PropertyMorphableData\AbstractPropertyMorphableData; +use Spatie\LaravelData\Tests\Fakes\PropertyMorphableData\NestedPropertyMorphableData; use Spatie\LaravelData\Tests\Fakes\SimpleData; use Spatie\LaravelData\Tests\Fakes\SimpleDataWithExplicitValidationRuleAttributeData; use Spatie\LaravelData\Tests\Fakes\SimpleDataWithOverwrittenRules; @@ -2528,3 +2530,56 @@ public function __construct( 'otherProperty' => 'Hello World', ]); }); + +it('can validate property-morphable data', function () { + DataValidationAsserter::for(AbstractPropertyMorphableData::class) + ->assertErrors([], [ + 'variant' => ['The variant field is required.'], + ]) + ->assertErrors([ + 'variant' => 'c', + ], [ + 'variant' => ['The selected variant is invalid.'], + ]) + ->assertErrors([ + 'variant' => 'a', + ], [ + 'a' => ['The a field is required.'], + ]) + ->assertErrors([ + 'variant' => 'b', + ], [ + 'b' => ['The b field is required.'], + ]) + ->assertOk([ + 'variant' => 'a', + 'a' => 'foo', + ]) + ->assertOk([ + 'variant' => 'b', + 'b' => 'foo', + ]); +}); + +it('can validate nested property-morphable data', function () { + DataValidationAsserter::for(NestedPropertyMorphableData::class) + ->assertErrors([ + 'nestedCollection' => [[]], + ], [ + 'nestedCollection.0.variant' => ['The nested collection.0.variant field is required.'], + ]) + ->assertErrors([ + 'nestedCollection' => [['variant' => 'c']], + ], [ + 'nestedCollection.0.variant' => ['The selected nested collection.0.variant is invalid.'], + ]) + ->assertErrors([ + 'nestedCollection' => [['variant' => 'a'], ['variant' => 'b']], + ], [ + 'nestedCollection.0.a' => ['The nested collection.0.a field is required.'], + 'nestedCollection.1.b' => ['The nested collection.1.b field is required.'], + ]) + ->assertOk([ + 'nestedCollection' => [['variant' => 'a', 'a' => 'foo'], ['variant' => 'b', 'b' => 'bar']], + ]); +});