Customizing Resource Collection Mapping in Laravel
Laravel's resource collections provide a powerful way to transform your data for API responses. By default, Laravel makes some assumptions about how your resources should be mapped, but sometimes you need more control. Let's explore how to customize resource collection mapping to fit your specific needs.
Default Behavior
Typically, when you create a resource collection, Laravel automatically maps each item in the collection to its corresponding singular resource. For instance, a UserCollection
would normally map to UserResource
for each item.
The $collects Property
Laravel provides the $collects
property to allow you to specify which resource class should be used for the items in your collection. This is particularly useful when you want to use a different resource class than what Laravel would assume by default.
Here's how you can implement this:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
/**
* The resource that this resource collects.
*
* @var string
*/
public $collects = Member::class;
// ... other methods
}
In this example, instead of using UserResource
, the collection will use Member
resource for each item.
Real-World Scenario
Let's consider a scenario where you have a Team
model with a collection of User
models, but you want to represent users as "members" in your API response.
First, create a MemberResource
:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class MemberResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'role' => $this->pivot->role,
'joined_at' => $this->pivot->created_at->toDateString(),
];
}
}
Now, create a TeamResource
that uses MemberResource
for its users:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class TeamResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'members' => MemberResource::collection($this->users),
];
}
}
Finally, if you want a collection of teams, you can create a TeamCollection
that ensures MemberResource
is used for all nested user data:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class TeamCollection extends ResourceCollection
{
public $collects = TeamResource::class;
public function toArray($request)
{
return [
'data' => $this->collection,
'total_teams' => $this->collection->count(),
'total_members' => $this->collection->sum(function ($team) {
return $team->users->count();
}),
];
}
}
Now, when you return this collection from a controller:
return new TeamCollection(Team::with('users')->get());
You'll get a response where each team's users are represented as "members" using the MemberResource
, providing a consistent and customized API structure.
Conclusion
The $collects
property in Laravel resource collections offers a flexible way to customize how your data is transformed for API responses. By specifying which resource class to use for collection items, you can create more expressive and tailored API structures that better fit your application's domain language and requirements.
If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!