From 33cc77ca39f67fe756101a37bd6079fad6a2557b Mon Sep 17 00:00:00 2001 From: Aleksei Zarubin Date: Mon, 14 Jun 2021 12:37:59 +0500 Subject: [PATCH] refactor!: upgrade to spatie/data-transfer-object ^3.0 --- .github/workflows/ci.yml | 4 +- composer.json | 4 +- src/CastableDataTransferObjectCollection.php | 19 +- src/Casts/DataTransferObject.php | 8 +- ...stableDataTransferObjectCollectionTest.php | 180 ++++++++++-------- tests/CastableDataTransferObjectTest.php | 111 ++++++----- 6 files changed, 192 insertions(+), 134 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0172816..10ef34a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - php-version: [ '7.4', '8.0' ] + php-version: [ '8.0' ] name: Tests on PHP ${{ matrix.php-version }} @@ -42,4 +42,4 @@ jobs: run: composer install --prefer-dist --no-progress --no-suggest - name: Run test suite - run: vendor/bin/phpunit --verbose \ No newline at end of file + run: vendor/bin/phpunit --verbose diff --git a/composer.json b/composer.json index a0b3fbb..3903f01 100644 --- a/composer.json +++ b/composer.json @@ -19,10 +19,10 @@ } ], "require": { - "php": ">=7.4", + "php": ">=8.0", "ext-json": "*", "illuminate/contracts": "^8.0", - "spatie/data-transfer-object": "^2.5|^3.0" + "spatie/data-transfer-object": "^3.0" }, "require-dev": { "phpunit/phpunit": "^8.0", diff --git a/src/CastableDataTransferObjectCollection.php b/src/CastableDataTransferObjectCollection.php index cb2112f..09bbd1b 100644 --- a/src/CastableDataTransferObjectCollection.php +++ b/src/CastableDataTransferObjectCollection.php @@ -5,20 +5,22 @@ namespace Tailflow\DataTransferObjects; use Illuminate\Contracts\Database\Eloquent\Castable; -use Spatie\DataTransferObject\DataTransferObjectCollection; +use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Support\Collection; use Tailflow\DataTransferObjects\Casts\DataTransferObject as DataTransferObjectCast; -abstract class CastableDataTransferObjectCollection extends DataTransferObjectCollection implements Castable +abstract class CastableDataTransferObjectCollection implements Castable, Arrayable { protected static string $itemClass; + protected Collection $collection; public function __construct(array $collection = []) { $itemClass = static::$itemClass; - $this->collection = array_map(function($item) use ($itemClass) { + $this->collection = collect($collection)->map(function($item) use ($itemClass) { return is_array($item) ? new $itemClass($item) : $item; - }, $collection); + }); } public static function castUsing(array $arguments): DataTransferObjectCast @@ -37,6 +39,11 @@ public static function fromJson($json) $itemClass = static::$itemClass; - return new static($itemClass::arrayOf($collection)); + return collect($itemClass::arrayOf($collection)); } -} \ No newline at end of file + + public function toArray(): array + { + return $this->collection->toArray(); + } +} diff --git a/src/Casts/DataTransferObject.php b/src/Casts/DataTransferObject.php index 3fdcb71..91165f8 100644 --- a/src/Casts/DataTransferObject.php +++ b/src/Casts/DataTransferObject.php @@ -6,6 +6,7 @@ use Illuminate\Contracts\Database\Eloquent\CastsAttributes; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Collection; use InvalidArgumentException; class DataTransferObject implements CastsAttributes @@ -28,6 +29,7 @@ public function __construct(string $class) * @param string $key * @param mixed $value * @param array $attributes + * @return void */ public function get($model, string $key, $value, $attributes) { @@ -57,10 +59,14 @@ public function set($model, $key, $value, $attributes) $value = new $this->class($value); } + if ($value instanceof Collection) { + $value = new $this->class($value->toArray()); + } + if (!$value instanceof $this->class) { throw new InvalidArgumentException("Value must be of type [$this->class], array, or null"); } return $value->toJson(); } -} \ No newline at end of file +} diff --git a/tests/CastableDataTransferObjectCollectionTest.php b/tests/CastableDataTransferObjectCollectionTest.php index 8d6a40e..6beabb1 100644 --- a/tests/CastableDataTransferObjectCollectionTest.php +++ b/tests/CastableDataTransferObjectCollectionTest.php @@ -4,9 +4,9 @@ namespace Tailflow\DataTransferObjects\Tests; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use InvalidArgumentException; -use Spatie\DataTransferObject\DataTransferObjectError; use Tailflow\DataTransferObjects\Tests\Fixtures\App\DataTransferObjects\Address; use Tailflow\DataTransferObjects\Tests\Fixtures\App\DataTransferObjects\Addresses; use Tailflow\DataTransferObjects\Tests\Fixtures\App\Models\User; @@ -16,88 +16,106 @@ class CastableDataTransferObjectCollectionTest extends TestCase /** @test */ public function it_casts_arrays_to_json(): void { - User::factory()->create([ - 'delivery_addresses' => [ - [ - 'country' => 'jp', - 'city' => 'Tokyo', - 'street' => '4-2-8 Shiba-koen' - ], - [ - 'country' => 'jp', - 'city' => 'Tokyo', - 'street' => '5-2-0 Ueno-koen' + User::factory()->create( + [ + 'delivery_addresses' => [ + [ + 'country' => 'jp', + 'city' => 'Tokyo', + 'street' => '4-2-8 Shiba-koen' + ], + [ + 'country' => 'jp', + 'city' => 'Tokyo', + 'street' => '5-2-0 Ueno-koen' + ], ], - ], - ]); - - self::assertTrue(DB::table('users') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].country") = "jp"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].city") = "Tokyo"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].street") = "4-2-8 Shiba-koen"') - ->exists()); - - self::assertTrue(DB::table('users') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].country") = "jp"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].city") = "Tokyo"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].street") = "5-2-0 Ueno-koen"') - ->exists()); + ] + ); + + self::assertTrue( + DB::table('users') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].country") = "jp"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].city") = "Tokyo"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].street") = "4-2-8 Shiba-koen"') + ->exists() + ); + + self::assertTrue( + DB::table('users') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].country") = "jp"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].city") = "Tokyo"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].street") = "5-2-0 Ueno-koen"') + ->exists() + ); } /** @test */ public function it_casts_data_transfer_objects_to_json(): void { - User::factory()->create([ - 'delivery_addresses' => new Addresses( - [ - new Address([ + User::factory()->create( + [ + 'delivery_addresses' => new Addresses( + [ + new Address( + [ + 'country' => 'jp', + 'city' => 'Tokyo', + 'street' => '4-2-8 Shiba-koen' + ] + ), + new Address( + [ + 'country' => 'jp', + 'city' => 'Tokyo', + 'street' => '5-2-0 Ueno-koen' + ] + ), + ] + ), + ] + ); + + self::assertTrue( + DB::table('users') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].country") = "jp"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].city") = "Tokyo"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].street") = "4-2-8 Shiba-koen"') + ->exists() + ); + + self::assertTrue( + DB::table('users') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].country") = "jp"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].city") = "Tokyo"') + ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].street") = "5-2-0 Ueno-koen"') + ->exists() + ); + } + + /** @test */ + public function it_casts_json_to_a_data_transfer_object(): void + { + $user = User::factory()->create( + [ + 'delivery_addresses' => [ + [ 'country' => 'jp', 'city' => 'Tokyo', 'street' => '4-2-8 Shiba-koen' - ]), - new Address([ + ], + [ 'country' => 'jp', 'city' => 'Tokyo', 'street' => '5-2-0 Ueno-koen' - ]), - ] - ), - ]); - - self::assertTrue(DB::table('users') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].country") = "jp"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].city") = "Tokyo"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[0].street") = "4-2-8 Shiba-koen"') - ->exists()); - - self::assertTrue(DB::table('users') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].country") = "jp"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].city") = "Tokyo"') - ->whereRaw('JSON_EXTRACT(delivery_addresses, "$[1].street") = "5-2-0 Ueno-koen"') - ->exists()); - } - - /** @test */ - public function it_casts_json_to_a_data_transfer_object(): void - { - $user = User::factory()->create([ - 'delivery_addresses' => [ - [ - 'country' => 'jp', - 'city' => 'Tokyo', - 'street' => '4-2-8 Shiba-koen' - ], - [ - 'country' => 'jp', - 'city' => 'Tokyo', - 'street' => '5-2-0 Ueno-koen' + ], ], - ], - ]); + ] + ); $user = $user->fresh(); - self::assertInstanceOf(Addresses::class, $user->delivery_addresses); + self::assertInstanceOf(Collection::class, $user->delivery_addresses); self::assertEquals('jp', $user->delivery_addresses[0]->country); self::assertEquals('Tokyo', $user->delivery_addresses[0]->city); @@ -111,13 +129,17 @@ public function it_casts_json_to_a_data_transfer_object(): void /** @test */ public function it_throws_exceptions_for_incorrect_data_structures(): void { - $this->expectException(DataTransferObjectError::class); - - User::factory()->create([ - 'delivery_addresses' => [ - ['bad' => 'thing'], - ], - ]); + $this->expectExceptionMessage( + 'Cannot assign null to property Tailflow\DataTransferObjects\Tests\Fixtures\App\DataTransferObjects\Address::$country of type string' + ); + + User::factory()->create( + [ + 'delivery_addresses' => [ + ['bad' => 'thing'], + ], + ] + ); } /** @test */ @@ -125,9 +147,11 @@ public function it_rejects_invalid_types(): void { $this->expectException(InvalidArgumentException::class); - User::factory()->create([ - 'delivery_addresses' => 'string', - ]); + User::factory()->create( + [ + 'delivery_addresses' => 'string', + ] + ); } /** @test */ @@ -139,4 +163,4 @@ public function it_handles_nullable_columns(): void self::assertNull($user->refresh()->address); } -} \ No newline at end of file +} diff --git a/tests/CastableDataTransferObjectTest.php b/tests/CastableDataTransferObjectTest.php index 87c0904..159b617 100644 --- a/tests/CastableDataTransferObjectTest.php +++ b/tests/CastableDataTransferObjectTest.php @@ -4,9 +4,10 @@ namespace Tailflow\DataTransferObjects\Tests; +use Illuminate\Support\Facades\DB; use InvalidArgumentException; -use Spatie\DataTransferObject\DataTransferObjectError; use Tailflow\DataTransferObjects\Tests\Fixtures\App\DataTransferObjects\Address; +use Tailflow\DataTransferObjects\Tests\Fixtures\App\DataTransferObjects\Addresses; use Tailflow\DataTransferObjects\Tests\Fixtures\App\Models\User; class CastableDataTransferObjectTest extends TestCase @@ -14,49 +15,63 @@ class CastableDataTransferObjectTest extends TestCase /** @test */ public function it_casts_arrays_to_json(): void { - User::factory()->create([ - 'work_address' => [ - 'country' => 'jp', - 'city' => 'Tokyo', - 'street' => '4-2-8 Shiba-koen', - ], - ]); - - $this->assertDatabaseHas('users', [ - 'work_address->country' => 'jp', - 'work_address->city' => 'Tokyo', - 'work_address->street' => '4-2-8 Shiba-koen', - ]); + User::factory()->create( + [ + 'work_address' => [ + 'country' => 'jp', + 'city' => 'Tokyo', + 'street' => '4-2-8 Shiba-koen', + ], + ] + ); + + $this->assertDatabaseHas( + 'users', + [ + 'work_address->country' => 'jp', + 'work_address->city' => 'Tokyo', + 'work_address->street' => '4-2-8 Shiba-koen', + ] + ); } /** @test */ public function it_casts_data_transfer_objects_to_json(): void { - User::factory()->create([ - 'work_address' => new Address([ - 'country' => 'jp', - 'city' => 'Tokyo', - 'street' => '4-2-8 Shiba-koen', - ]), - ]); - - $this->assertDatabaseHas('users', [ - 'work_address->country' => 'jp', - 'work_address->city' => 'Tokyo', - 'work_address->street' => '4-2-8 Shiba-koen', - ]); + User::factory()->create( + [ + 'work_address' => new Address( + [ + 'country' => 'jp', + 'city' => 'Tokyo', + 'street' => '4-2-8 Shiba-koen', + ] + ), + ] + ); + + $this->assertDatabaseHas( + 'users', + [ + 'work_address->country' => 'jp', + 'work_address->city' => 'Tokyo', + 'work_address->street' => '4-2-8 Shiba-koen', + ] + ); } /** @test */ public function it_casts_json_to_a_data_transfer_object(): void { - $user = User::factory()->create([ - 'work_address' => [ - 'country' => 'jp', - 'city' => 'Tokyo', - 'street' => '4-2-8 Shiba-koen', - ], - ]); + $user = User::factory()->create( + [ + 'work_address' => [ + 'country' => 'jp', + 'city' => 'Tokyo', + 'street' => '4-2-8 Shiba-koen', + ], + ] + ); $user = $user->fresh(); @@ -69,13 +84,17 @@ public function it_casts_json_to_a_data_transfer_object(): void /** @test */ public function it_throws_exceptions_for_incorrect_data_structures(): void { - $this->expectException(DataTransferObjectError::class); - - User::factory()->create([ - 'work_address' => [ - 'bad' => 'thing', - ], - ]); + $this->expectExceptionMessage( + 'Cannot assign null to property Tailflow\DataTransferObjects\Tests\Fixtures\App\DataTransferObjects\Address::$country of type string' + ); + + User::factory()->create( + [ + 'work_address' => [ + 'bad' => 'thing', + ], + ] + ); } /** @test */ @@ -83,9 +102,11 @@ public function it_rejects_invalid_types(): void { $this->expectException(InvalidArgumentException::class); - User::factory()->create([ - 'work_address' => 'string', - ]); + User::factory()->create( + [ + 'work_address' => 'string', + ] + ); } /** @test */ @@ -97,4 +118,4 @@ public function it_handles_nullable_columns(): void self::assertNull($user->refresh()->work_address); } -} \ No newline at end of file +}