diff --git a/src/Illuminate/Http/Resources/Json/ResourceCollection.php b/src/Illuminate/Http/Resources/Json/ResourceCollection.php index 361542f26bb5..754839a59047 100644 --- a/src/Illuminate/Http/Resources/Json/ResourceCollection.php +++ b/src/Illuminate/Http/Resources/Json/ResourceCollection.php @@ -96,13 +96,14 @@ public function count(): int * @param \Illuminate\Http\Request $request * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable */ - public function toAttributes(Request $request) + #[\Override] + public function toArray(Request $request) { if ($this->collection->first() instanceof JsonResource) { return $this->collection->map->resolve($request)->all(); } - return $this->toArray($request); + return $this->collection->map->toArray($request)->all(); } /** diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index 307d95a83bb0..e798c2fed5d4 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -3,11 +3,14 @@ namespace Illuminate\Tests\Integration\Http; use Illuminate\Database\Eloquent\Model; +use Illuminate\Foundation\Auth\User; use Illuminate\Foundation\Http\Middleware\ValidatePostSize; use Illuminate\Http\Exceptions\PostTooLargeException; use Illuminate\Http\Request; use Illuminate\Http\Resources\ConditionallyLoadsAttributes; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Http\Resources\Json\ResourceCollection; +use Illuminate\Http\Resources\JsonApi\AnonymousResourceCollection; use Illuminate\Http\Resources\MergeValue; use Illuminate\Http\Resources\MissingValue; use Illuminate\Pagination\Cursor; @@ -50,6 +53,49 @@ class ResourceTest extends TestCase { + public function testResourceMayBeConvetedToArray() + { + $resource = new class((new User)->forceFill(['id' => 1, 'name' => 'Taylor Otwell'])) extends JsonResource + { + public function toArray(Request $request) + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'posts' => (new AnonymousResourceCollection([ + new Post([ + 'id' => 5, + 'title' => 'Test Title', + 'abstract' => 'Test abstract', + ]), + new Post([ + 'id' => 10, + 'title' => 'Another Test Title', + 'abstract' => 'Another Test abstract', + ]), + ], PostResource::class)), + ]; + } + }; + + $request = Request::create('GET', '/users'); + + tap($resource->toArray($request), function ($userAsArray) use ($request) { + $this->assertSame(1, $userAsArray['id']); + $this->assertSame('Taylor Otwell', $userAsArray['name']); + + $this->assertInstanceOf(AnonymousResourceCollection::class, $userAsArray['posts']); + $this->assertSame(PostResource::class, $userAsArray['posts']->collects); + + tap($userAsArray['posts']->toArray($request), function ($postsAsArray) { + $this->assertIsArray($postsAsArray); + $this->assertCount(2, $postsAsArray); + $this->assertSame(['id' => 5, 'title' => 'Test Title', 'custom' => true], $postsAsArray[0]); + $this->assertSame(['id' => 10, 'title' => 'Another Test Title', 'custom' => true], $postsAsArray[1]); + }); + }); + } + public function testResourcesMayBeConvertedToJson() { Route::get('/', function () { @@ -1888,6 +1934,102 @@ public function testResourceWrapsWhenDataKeyDoesNotExist() ], $content); } + public function testResourceCanOverridesWrapping() + { + $resource = new class(['id' => 5, 'title' => 'Test', 'data' => 'some data']) extends JsonResource + { + public static $wrap = 'results'; + public static bool $forceWrapping = true; + }; + + JsonResource::flushState(); + + $response = $resource->toResponse(request()); + $content = json_decode($response->getContent(), true); + + $this->assertEquals([ + 'results' => [ + 'id' => 5, + 'title' => 'Test', + 'data' => 'some data', + ], + ], $content); + } + + public function testResourceCollectionCanOverridesWrapping() + { + $resource = new class([new class(['id' => 5, 'title' => 'Test', 'data' => 'some data']) extends JsonResource + { + public static $wrap = null; + }, + ]) extends ResourceCollection { + public static $wrap = 'results'; + }; + + JsonResource::flushState(); + + $response = $resource->toResponse(request()); + $content = json_decode($response->getContent(), true); + + $this->assertEquals([ + 'results' => [ + [ + 'id' => 5, + 'title' => 'Test', + 'data' => 'some data', + ], + ], + ], $content); + } + + public function testPaginatedResourceCollectionCanOverridesWrapping() + { + $resource = new class(new LengthAwarePaginator([new class(['id' => 5, 'title' => 'Test', 'data' => 'some data']) extends JsonResource + { + public static $wrap = null; + }, + ], 10, 2)) extends ResourceCollection { + public static $wrap = 'results'; + }; + + JsonResource::flushState(); + + $response = $resource->toResponse(request()); + $content = json_decode($response->getContent(), true); + + $this->assertArrayHasKey('results', $content); + $this->assertArrayHasKey('links', $content); + $this->assertArrayHasKey('meta', $content); + + $this->assertCount(1, $content['results']); + $this->assertEquals([ + [ + 'id' => 5, + 'title' => 'Test', + 'data' => 'some data', + ], + ], $content['results']); + } + + public function testEmptyPaginatedResourceCollectionCanOverridesWrapping() + { + $resource = new class(new LengthAwarePaginator([], 10, 2)) extends ResourceCollection + { + public static $wrap = 'results'; + }; + + JsonResource::flushState(); + + $response = $resource->toResponse(request()); + $content = json_decode($response->getContent(), true); + + $this->assertArrayHasKey('results', $content); + $this->assertArrayHasKey('links', $content); + $this->assertArrayHasKey('meta', $content); + + $this->assertCount(0, $content['results']); + } + public function testResourceForceWrapOverridesDataKeyCheck() { $resource = new class(['id' => 5, 'title' => 'Test', 'data' => 'some data']) extends JsonResource diff --git a/tests/Integration/Http/Resources/Json/ResourceCollectionTest.php b/tests/Integration/Http/Resources/Json/ResourceCollectionTest.php new file mode 100644 index 000000000000..51e4df60d0cd --- /dev/null +++ b/tests/Integration/Http/Resources/Json/ResourceCollectionTest.php @@ -0,0 +1,62 @@ +assertSame($expected, $collection->toArray($request)); + } + + public static function toArrayDataProvider() + { + yield [ + new ResourceCollection([ + new Fluent(['id' => 1]), + new Fluent(['id' => 2]), + new Fluent(['id' => 3]), + ]), + [ + ['id' => 1], + ['id' => 2], + ['id' => 3], + ], + ]; + + yield [ + (new ResourceCollection([ + (new User())->forceFill(['name' => 'Taylor Otwell']), + (new User())->forceFill(['name' => 'Laravel']), + ]))->additional(['total', 1]), + [ + ['name' => 'Taylor Otwell'], + ['name' => 'Laravel'], + ], + ]; + + yield [ + new class(['list' => new Fluent(['id' => 1]), 'total' => 1]) extends ResourceCollection + { + public function toArray(Request $request) + { + return $this->resource->toArray(); + } + }, + [ + 'list' => ['id' => 1], + 'total' => 1, + ], + ]; + } +}