diff --git a/src/Illuminate/Http/Resources/Json/JsonResource.php b/src/Illuminate/Http/Resources/Json/JsonResource.php index 87cd43bdd796..035c25d969b1 100644 --- a/src/Illuminate/Http/Resources/Json/JsonResource.php +++ b/src/Illuminate/Http/Resources/Json/JsonResource.php @@ -49,6 +49,13 @@ class JsonResource implements ArrayAccess, JsonSerializable, Responsable, UrlRou */ public static $wrap = 'data'; + /** + * Whether to force wrapping even if the $wrap key exists in underlying resource data. + * + * @var bool + */ + public static bool $forceWrapping = false; + /** * Create a new resource instance. * diff --git a/src/Illuminate/Http/Resources/Json/ResourceResponse.php b/src/Illuminate/Http/Resources/Json/ResourceResponse.php index 4e4f9d3e1313..1c9d7e60f2c3 100644 --- a/src/Illuminate/Http/Resources/Json/ResourceResponse.php +++ b/src/Illuminate/Http/Resources/Json/ResourceResponse.php @@ -80,6 +80,10 @@ protected function wrap($data, $with = [], $additional = []) */ protected function haveDefaultWrapperAndDataIsUnwrapped($data) { + if ($this->resource instanceof JsonResource && $this->resource::$forceWrapping) { + return $this->wrapper() !== null; + } + return $this->wrapper() && ! array_key_exists($this->wrapper(), $data); } diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index 263b8f348995..307d95a83bb0 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -1853,6 +1853,61 @@ public function testItThrowsNoErrorInStrictModeWhenResourceIsPaginated() } } + public function testResourceSkipsWrappingWhenDataKeyExists() + { + $resource = new class(['id' => 5, 'title' => 'Test', 'data' => 'some data']) extends JsonResource + { + public static $wrap = 'data'; + }; + + $response = $resource->toResponse(request()); + $content = json_decode($response->getContent(), true); + + $this->assertEquals([ + 'id' => 5, + 'title' => 'Test', + 'data' => 'some data', + ], $content); + } + + public function testResourceWrapsWhenDataKeyDoesNotExist() + { + $resource = new class(['id' => 5, 'title' => 'Test']) extends JsonResource + { + public static $wrap = 'data'; + }; + + $response = $resource->toResponse(request()); + $content = json_decode($response->getContent(), true); + + $this->assertEquals([ + 'data' => [ + 'id' => 5, + 'title' => 'Test', + ], + ], $content); + } + + public function testResourceForceWrapOverridesDataKeyCheck() + { + $resource = new class(['id' => 5, 'title' => 'Test', 'data' => 'some data']) extends JsonResource + { + public static $wrap = 'data'; + public static bool $forceWrapping = true; + }; + + $response = $resource->toResponse(request()); + $content = json_decode($response->getContent(), true); + + $this->assertEquals([ + 'data' => [ + 'id' => 5, + 'title' => 'Test', + 'data' => 'some data', + ], + ], $content); + } + private function assertJsonResourceResponse($data, $expectedJson) { Route::get('/', function () use ($data) {