Skip to content

[5.8] Check for preserveKeys when serializing a collection from a resource#27985

Merged
taylorotwell merged 2 commits intolaravel:5.8from
rodrigopedra:resources-keys
Mar 29, 2019
Merged

[5.8] Check for preserveKeys when serializing a collection from a resource#27985
taylorotwell merged 2 commits intolaravel:5.8from
rodrigopedra:resources-keys

Conversation

@rodrigopedra
Copy link
Copy Markdown
Contributor

As commented by @staudenmeir, when setting the preserveKeys in a resource, but generating a collection from it, the keys are not preserved.

Before this PR the example in the docs should not work:

use App\User;
use App\Http\Resources\User as UserResource;

Route::get('/user', function () {
    return UserResource::collection(User::all()->keyBy->id);
});

As the JsonResource::collection returns a AnonymousResourceCollection and this class does not have a preserveKeys attribute, it fails on keeping the keys when serializing as currently we only check the $preserveKeys property in the object being serialized.

This PR adds a method to the ConditionallyLoadsAttributes trait to handle both the cases of serializing a Resoruce or a Collection of resources.

I used reflection to accomplish this, maybe to 5.9 we could change to using an Interface, I think it would clearer.

Worth noticing that @staudenmeir found this bug while working on issue #27950

@rodrigopedra
Copy link
Copy Markdown
Contributor Author

Ping @staudenmeir . Please take a look if you have the time

@rodrigopedra rodrigopedra changed the title [5.8] Check for preserveKeys when generating a collection from a resource [5.8] Check for preserveKeys when serializing a collection from a resource Mar 23, 2019
@staudenmeir
Copy link
Copy Markdown
Contributor

An issue I see:

class UserResource extends JsonResource
{
    public $preserveKeys = true;
}

class UserCollection extends ResourceCollection
{
    public $collects = 'App\Http\Resources\UserResource';
}

return new UserCollection(User::all()->filter->active);

Here, the keys are preserved when they shouldn't be.

Wouldn't your other suggestion solve this?

Add dynamically the $preserveKeys to the AnonymousResourceCollection in instantiation if the collected resource has it.

Comment thread src/Illuminate/Http/Resources/ConditionallyLoadsAttributes.php Outdated
@staudenmeir
Copy link
Copy Markdown
Contributor

What if we move this to JsonResource::collection() and add $preserveKeys = false to AnonymousResourceCollection::__construct()? This wouldn't be a breaking change and we could avoid using reflection.

@rodrigopedra
Copy link
Copy Markdown
Contributor Author

@staudenmeir , thanks for the suggestion, it is much nicer, can you please review it?

Copy link
Copy Markdown
Contributor

@staudenmeir staudenmeir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@taylorotwell taylorotwell merged commit 16f68bb into laravel:5.8 Mar 29, 2019
@rodrigopedra
Copy link
Copy Markdown
Contributor Author

Thanks! @taylorotwell

While fixing it I felt that this should have been implemented using an Interface, as we do with the ShouldQueue jobs, etc. As we expect the preserveKeys property to be true if this feature is needed.

If you think this is a good approach, I can send a PR to the 5.9 branch

@TBlindaruk
Copy link
Copy Markdown
Contributor

@rodrigopedra ,
I`m not sure that @taylorotwell is reading comments after PR is merged or closed.

@rodrigopedra rodrigopedra deleted the resources-keys branch March 31, 2019 02:43
@rodrigopedra
Copy link
Copy Markdown
Contributor Author

@TBlindaruk ok thanks, when I have the time I will try to send a PR so we can discuss there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants