From ae75f52de74778c549f62b2866835f7d8cd2b0ce Mon Sep 17 00:00:00 2001 From: Bastien Philippe Date: Thu, 30 Dec 2021 14:11:53 +0100 Subject: [PATCH 1/3] Add ability to customize json options on JsonResource response --- .../Http/Resources/Json/JsonResource.php | 10 +++++++++ .../Http/Resources/Json/ResourceResponse.php | 4 +++- .../Fixtures/PostResourceWithJsonOptions.php | 22 +++++++++++++++++++ tests/Integration/Http/ResourceTest.php | 21 ++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/Http/Fixtures/PostResourceWithJsonOptions.php diff --git a/src/Illuminate/Http/Resources/Json/JsonResource.php b/src/Illuminate/Http/Resources/Json/JsonResource.php index 7cbdb602997e..8f94f73cb2e6 100644 --- a/src/Illuminate/Http/Resources/Json/JsonResource.php +++ b/src/Illuminate/Http/Resources/Json/JsonResource.php @@ -164,6 +164,16 @@ public function additional(array $data) return $this; } + /** + * Get the serialization options applied to the resource response. + * + * @return int + */ + public function jsonOptions() + { + return 0; + } + /** * Customize the response for a request. * diff --git a/src/Illuminate/Http/Resources/Json/ResourceResponse.php b/src/Illuminate/Http/Resources/Json/ResourceResponse.php index 2e9d326d5c3e..51f36576f0ae 100644 --- a/src/Illuminate/Http/Resources/Json/ResourceResponse.php +++ b/src/Illuminate/Http/Resources/Json/ResourceResponse.php @@ -40,7 +40,9 @@ public function toResponse($request) $this->resource->with($request), $this->resource->additional ), - $this->calculateStatus() + $this->calculateStatus(), + [], + $this->resource->jsonOptions() ), function ($response) use ($request) { $response->original = $this->resource->resource; diff --git a/tests/Integration/Http/Fixtures/PostResourceWithJsonOptions.php b/tests/Integration/Http/Fixtures/PostResourceWithJsonOptions.php new file mode 100644 index 000000000000..d7524b75d8d8 --- /dev/null +++ b/tests/Integration/Http/Fixtures/PostResourceWithJsonOptions.php @@ -0,0 +1,22 @@ + $this->id, + 'title' => $this->title, + 'reading_time' => $this->reading_time, + ]; + } + + public function jsonOptions() + { + return JSON_PRESERVE_ZERO_FRACTION; + } +} diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index 98dfc6e16541..a85619ebb96b 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -24,6 +24,7 @@ use Illuminate\Tests\Integration\Http\Fixtures\PostResource; use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithAnonymousResourceCollectionWithPaginationInformation; use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithExtraData; +use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithJsonOptions; use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithOptionalAppendedAttributes; use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithOptionalData; use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithOptionalMerging; @@ -495,6 +496,26 @@ public function testResourcesMayCustomizeExtraDataWhenBuildingResponse() ]); } + public function testResourcesMayCustomizeJsonOptions() + { + Route::get('/', function () { + return new PostResourceWithJsonOptions(new Post([ + 'id' => 5, + 'title' => 'Test Title', + 'reading_time' => 3.0, + ])); + }); + + $response = $this->withoutExceptionHandling()->get( + '/', ['Accept' => 'application/json'] + ); + + $this->assertEquals( + '{"data":{"id":5,"title":"Test Title","reading_time":3.0}}', + $response->baseResponse->content() + ); + } + public function testCustomHeadersMayBeSetOnResponses() { Route::get('/', function () { From 288c7c71b0002a1f2713418f3ddd903355529d57 Mon Sep 17 00:00:00 2001 From: Bastien Philippe Date: Fri, 31 Dec 2021 08:39:18 +0100 Subject: [PATCH 2/3] Add ability to customize json options on resource collections and paginated responses --- .../Http/Resources/CollectsResources.php | 12 ++++++ .../Json/PaginatedResourceResponse.php | 4 +- tests/Integration/Http/ResourceTest.php | 39 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Resources/CollectsResources.php b/src/Illuminate/Http/Resources/CollectsResources.php index cd795df70fa0..21010da339ad 100644 --- a/src/Illuminate/Http/Resources/CollectsResources.php +++ b/src/Illuminate/Http/Resources/CollectsResources.php @@ -64,4 +64,16 @@ public function getIterator() { return $this->collection->getIterator(); } + + /** + * Get the serialization options applied to the resource response. + * + * @return int + */ + public function jsonOptions() + { + $collects = $this->collects(); + + return $collects ? (new $collects([]))->jsonOptions() : 0; + } } diff --git a/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php b/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php index c5e8fbcb164c..bd3e8f9ade36 100644 --- a/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php +++ b/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php @@ -23,7 +23,9 @@ public function toResponse($request) $this->resource->additional ) ), - $this->calculateStatus() + $this->calculateStatus(), + [], + $this->resource->jsonOptions() ), function ($response) use ($request) { $response->original = $this->resource->resource->map(function ($item) { return is_array($item) ? Arr::get($item, 'resource') : $item->resource; diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index a85619ebb96b..3d339e229677 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -516,6 +516,45 @@ public function testResourcesMayCustomizeJsonOptions() ); } + public function testCollectionResourcesMayCustomizeJsonOptions() + { + Route::get('/', function () { + return PostResourceWithJsonOptions::collection(collect([ + new Post(['id' => 5, 'title' => 'Test Title', 'reading_time' => 3.0]), + ])); + }); + + $response = $this->withoutExceptionHandling()->get( + '/', ['Accept' => 'application/json'] + ); + + $this->assertEquals( + '{"data":[{"id":5,"title":"Test Title","reading_time":3.0}]}', + $response->baseResponse->content() + ); + } + + public function testResourcesMayCustomizeJsonOptionsOnPaginatedResponse() + { + Route::get('/', function () { + $paginator = new LengthAwarePaginator( + collect([new Post(['id' => 5, 'title' => 'Test Title', 'reading_time' => 3.0])]), + 10, 15, 1 + ); + + return PostResourceWithJsonOptions::collection($paginator); + }); + + $response = $this->withoutExceptionHandling()->get( + '/', ['Accept' => 'application/json'] + ); + + $this->assertEquals( + '{"data":[{"id":5,"title":"Test Title","reading_time":3.0}],"links":{"first":"\/?page=1","last":"\/?page=1","prev":null,"next":null},"meta":{"current_page":1,"from":1,"last_page":1,"links":[{"url":null,"label":"« Previous","active":false},{"url":"\/?page=1","label":"1","active":true},{"url":null,"label":"Next »","active":false}],"path":"\/","per_page":15,"to":1,"total":10}}', + $response->baseResponse->content() + ); + } + public function testCustomHeadersMayBeSetOnResponses() { Route::get('/', function () { From 3e01d97c3196e26772ac806e560b189e5c679edc Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 3 Jan 2022 09:55:25 -0600 Subject: [PATCH 3/3] formatting --- .../Http/Resources/CollectsResources.php | 22 +++++++++---------- .../Http/Resources/Json/JsonResource.php | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Http/Resources/CollectsResources.php b/src/Illuminate/Http/Resources/CollectsResources.php index 21010da339ad..77269042aba3 100644 --- a/src/Illuminate/Http/Resources/CollectsResources.php +++ b/src/Illuminate/Http/Resources/CollectsResources.php @@ -55,25 +55,25 @@ class_exists($class = Str::replaceLast('Collection', 'Resource', get_class($this } /** - * Get an iterator for the resource collection. + * Get the JSON serialization options that should be applied to the resource response. * - * @return \ArrayIterator + * @return int */ - #[\ReturnTypeWillChange] - public function getIterator() + public function jsonOptions() { - return $this->collection->getIterator(); + $collects = $this->collects(); + + return $collects ? (new $collects([]))->jsonOptions() : 0; } /** - * Get the serialization options applied to the resource response. + * Get an iterator for the resource collection. * - * @return int + * @return \ArrayIterator */ - public function jsonOptions() + #[\ReturnTypeWillChange] + public function getIterator() { - $collects = $this->collects(); - - return $collects ? (new $collects([]))->jsonOptions() : 0; + return $this->collection->getIterator(); } } diff --git a/src/Illuminate/Http/Resources/Json/JsonResource.php b/src/Illuminate/Http/Resources/Json/JsonResource.php index 8f94f73cb2e6..8c8bf000bd43 100644 --- a/src/Illuminate/Http/Resources/Json/JsonResource.php +++ b/src/Illuminate/Http/Resources/Json/JsonResource.php @@ -165,7 +165,7 @@ public function additional(array $data) } /** - * Get the serialization options applied to the resource response. + * Get the JSON serialization options that should be applied to the resource response. * * @return int */