-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[11.x] Add non-static JsonResource wrapping #53543
Conversation
@@ -102,10 +102,14 @@ protected function haveAdditionalInformationAndDataIsUnwrapped($data, $with, $ad | |||
/** | |||
* Get the default data wrapper for the resource. | |||
* | |||
* @return string | |||
* @return string|null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function would return null
before this PR already in cases where ::withoutWrapping()
was used
@SanderMuller @taylorotwell This is a breaking change. If non-static wrapper is not used in a class, it should return static I can give you access to my repository, I have laravel at Here's a test that illustrates it. It passes on class JsonResourceTest extends TestCase
{
#[Test]
public function test(): void
{
$response = new ResourceCollection([
new JsonResource(['foo' => 'bar']), // instantiation
]);
JsonResource::withoutWrapping(); // subsequent call
$this->assertSame([['foo' => 'bar']], $this->getData($response)); // breaking change at laravel 11.34.0
}
private function getData(ResourceCollection $collection): array
{
return $collection->toResponse($this->request())->getData(true);
}
private function request(): Request
{
return $this->createMock(Request::class);
}
} |
Static calls having impact after instantiation is a bit odd, but you're right that the wrapper changing for existing instances was how it worked before this PR. I don't think there's an easy fix for this, so this feature might have to be brought to 12.x or the current impact has to be deemed acceptable. More Laravel alike test which exposes the impact: public function testResourcesCanSetWithoutWrappingAfterCreatingInstance()
{
Route::get('/', function () {
$resource = new PostResource(new Post([
'id' => 5,
'title' => 'Test Title',
]));
$resource::withoutWrapping();
return $resource;
});
$response = $this->withoutExceptionHandling()->get(
'/', ['Accept' => 'application/json']
);
$response->assertJson([
'id' => 5,
'title' => 'Test Title',
]);
} |
@SanderMuller SanderMuller I agree that it's odd, but it was the only way to achieve the desired result with static wrapping. Here's an example project and code that uses that: There is 10-30 more places in the codebase like that. I don't have the resources to update all of those places. Currently, I'm unable to update laravel to |
The sad thing is, this PR solves exactly the reason why the code you linked to came to be this odd. |
Yea, the irony is evident to me too. I wish the fix came sooner, before the codebase was populated with the static approach.
I think the fix is quite easy - Currently, you return a different if ($this->resource instanceof JsonResource) {
return $this->resource->wrapper;
}
return get_class($this->resource)::$wrap; What can be done, is Or in other words, this condition |
I'm looking into this suggestion, thanks |
This reverts commit eb625fa.
Overview
This PR addresses an issue with setting JSON wrappers on resource collections or other general-purpose JSON resource classes where adjusting the wrapper for an
AnonymousResourceCollection
or other generic resource class would affect all instances in the same request or following tests. This PR introduces instance-specific JSON wrapping toJsonResource
through a new$wrapper
property, along withwithWrapper()
andwithoutWrapper()
methods. This change allows developers to set a wrapper for individual resources without impacting others globally.Example of the Issue
Currently, modifying the wrapper for a resource collection applies globally within the same request or test:
With this PR, the wrapper can be set on a per-instance basis:
Benefits
Why This Change Doesn't Break Existing Features
The default behavior remains the same because the new instance-specific
$wrapper
property respects the global$wrap
setting unless overridden. Existing resource configurations and behaviors are not altered unless explicitly changed.How It Makes Building Web Applications Easier