ekyna/resource
Laravel package providing a Resource layer with controllers, forms, validation, persistence and admin-style CRUD tooling. Helps structure domain resources consistently across your app and speeds up building back-office interfaces.
Installation Add the package via Composer:
composer require ekyna/resource
Publish the config (if available) with:
php artisan vendor:publish --provider="Ekyna\Resource\ResourceServiceProvider"
Basic Usage
The package provides a Resource class for transforming Eloquent models into standardized API responses. Start by creating a custom resource class:
use Ekyna\Resource\Resource;
class UserResource extends Resource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
];
}
}
First Use Case Transform a model in a controller:
use Ekyna\Resource\UserResource;
public function show(User $user)
{
return new UserResource($user);
}
Resource Classes
Extend Ekyna\Resource\Resource for each model. Keep them in app/Http/Resources (or similar).
Example:
class PostResource extends Resource
{
public function toArray($request)
{
return [
'title' => $this->title,
'content' => Str::limit($this->content, 200),
'author' => new UserResource($this->author),
];
}
}
Nested Resources Use nested resource classes for relationships:
class CommentResource extends Resource
{
public function toArray($request)
{
return [
'body' => $this->body,
'user' => new UserResource($this->user),
];
}
}
Collections
Extend Ekyna\Resource\ResourceCollection for collections:
class PostCollection extends ResourceCollection
{
public function toArray($request)
{
return $this->collection->map->toArray($request);
}
}
Request-Driven Fields
Use $request to conditionally include fields:
public function toArray($request)
{
return [
'name' => $this->name,
'email' => $request->has('include_email') ? $this->email : null,
];
}
API Responses Return resources directly from controllers:
public function index()
{
return new PostCollection(Post::all());
}
$resource = new UserResource(factory(User::class)->make());
$this->assertEquals('John', $resource->name);
public function handle($request, Closure $next)
{
$response = $next($request);
if ($request->wantsJson()) {
Cache::put('resource:' . $request->path(), $response);
}
return $response;
}
Missing toArray Method
Forgetting to implement toArray() will throw MethodNotAllowedHttpException. Always override it.
Circular References
Nested resources with circular relationships (e.g., User->posts->user) will cause infinite recursion. Use null or break cycles:
public function toArray($request)
{
return [
'posts' => PostResource::collection($this->posts)->except('user'),
];
}
Request Scope
Resources rely on the $request object. Ensure it’s passed correctly in non-HTTP contexts (e.g., queues, commands). Use a mock request:
$resource = new UserResource($user, new Request());
No Built-in Pagination
The package doesn’t include pagination. Use Laravel’s LengthAwarePaginator or SimplePaginator manually:
return new PostCollection(Post::paginate(10));
dd((new UserResource($user))->toArray(new Request()));
$request object is accessible in toArray():
dd($request->all()); // Debug request data
Customize Resource Class
Override Resource to add global behavior:
class CustomResource extends Ekyna\Resource\Resource
{
public function toArray($request)
{
$array = parent::toArray($request);
$array['meta'] = ['timestamp' => now()->toIso8601String()];
return $array;
}
}
Add Metadata Include metadata in responses:
public function toArray($request)
{
return [
'data' => $this->transformData(),
'meta' => [
'created_at' => $this->created_at->format('Y-m-d'),
],
];
}
Conditional Loading Lazy-load relationships to improve performance:
public function toArray($request)
{
$this->loadMissing('posts.comments');
return [
'posts' => PostResource::collection($this->posts),
];
}
API Versioning
Use request-based versioning in toArray():
public function toArray($request)
{
if ($request->bearsToken('api-v2')) {
return $this->toArrayV2();
}
return $this->toArrayV1();
}
How can I help you explore Laravel packages today?