Installation:
composer require rmunate/easy-datatable
Publish the config (optional):
php artisan vendor:publish --provider="Rmunate\EasyDataTable\EasyDataTableServiceProvider"
First Use Case: Create a controller method to return a datatable response:
use Rmunate\EasyDataTable\Facades\EasyDataTable;
public function index()
{
$data = EasyDataTable::of(User::query())
->select(['id', 'name', 'email'])
->search(['name', 'email'])
->orderBy('name')
->paginate(10)
->make(true);
return response()->json($data);
}
Frontend Integration: Use the standard DataTables JS library with your API endpoint. Example:
$('#example').DataTable({
processing: true,
serverSide: true,
ajax: '/users'
});
Key Files to Review:
config/easy-datatable.php (for customization)vendor/rmunate/easy-datatable/src/ (core logic)// Controller
public function index()
{
return EasyDataTable::of(User::query())
->select(['id', 'name', 'email', 'created_at'])
->search(['name', 'email'])
->orderBy('name')
->paginate(10)
->make(true);
}
// Frontend (Vue/React/Any)
const table = new DataTable('#users-table', {
processing: true,
serverSide: true,
ajax: '/users',
columns: [
{ data: 'id', name: 'id' },
{ data: 'name', name: 'name' },
{ data: 'email', name: 'email' },
]
});
// With relationships and custom logic
$table = EasyDataTable::of(User::with('roles'))
->select(['users.id', 'users.name', 'roles.name as role'])
->search(['users.name', 'roles.name'])
->filter(function($query) {
$query->whereHas('roles', function($q) {
$q->where('roles.name', 'like', '%admin%');
});
})
->orderBy('users.name')
->paginate(15)
->make(true);
// Dynamically add columns based on user role
$columns = ['id', 'name', 'email'];
if (auth()->user()->isAdmin()) {
$columns[] = 'deleted_at';
}
return EasyDataTable::of(User::query())
->select($columns)
->search($columns)
->make(true);
// Using API Resources for transformation
return EasyDataTable::of(User::query())
->setResource(UserResource::class) // Custom API Resource
->select(['id', 'name', 'email'])
->make(true);
// Listen to datatable events (e.g., for logging or caching)
EasyDataTable::listen('beforeQuery', function($query, $request) {
logger()->info('DataTable query executed', ['query' => $query->toSql()]);
});
Laravel Scout Integration:
Use ->scout() method for full-text search:
EasyDataTable::of(User::query())
->scout()
->search(['name', 'email'])
->make(true);
Caching Responses: Cache frequent queries using Laravel's cache:
return Cache::remember('users-datatable', now()->addMinutes(5), function() {
return EasyDataTable::of(User::query())
->select(['id', 'name'])
->make(true);
});
Authorization: Combine with Laravel's gates/policies:
public function index()
{
$this->authorize('view', User::class);
return EasyDataTable::of(User::query())
->select(['id', 'name'])
->make(true);
}
Testing:
Use EasyDataTable::fake() in tests:
public function test_datatable()
{
EasyDataTable::fake();
$response = $this->get('/users');
$response->assertJsonStructure(['data', 'recordsTotal', 'recordsFiltered']);
}
Custom Responses: Override the default response format:
$data = EasyDataTable::of(User::query())
->select(['id', 'name'])
->make(false); // Returns raw data
return response()->json([
'success' => true,
'data' => $data,
]);
N+1 Query Problem:
with() or load() before passing the query to EasyDataTable:
EasyDataTable::of(User::with('roles')->query())
->select(['users.id', 'roles.name'])
->make(true);
Case Sensitivity in Search:
->search(['name' => ['name', 'ILIKE']]) for case-insensitive search.Pagination Conflicts:
config/easy-datatable.php:
'default_paginate' => 10,
Column Name Mismatches:
data) don't match backend (name).->setColumnMap():
EasyDataTable::of(User::query())
->select(['id', 'name as full_name'])
->setColumnMap(['full_name' => 'name'])
->make(true);
Performance with Large Datasets:
->scout() for full-text search.EasyDataTable::of(User::query())
->cursor()
->make(true);
Log Queries:
Enable query logging in config/easy-datatable.php:
'debug' => [
'log_queries' => true,
],
Queries will be logged to storage/logs/laravel.log.
Validate Request Data:
Use ->validate() to ensure required parameters are present:
EasyDataTable::of(User::query())
->validate()
->make(true);
Check for Deprecated Methods:
addColumn → select).Custom Query Modifiers: Extend the query builder by adding a macro:
use Illuminate\Database\Query\Builder;
Builder::macro('customFilter', function($field, $value) {
return $this->where($field, $value);
});
// Usage
EasyDataTable::of(User::query())
->filter(function($query) {
return $query->customFilter('status', 'active');
})
->make(true);
Override Default Response: Bind a custom response formatter:
EasyDataTable::macro('customResponse', function($data) {
return [
'status' => 'success',
'data' => $data,
'timestamp' => now()->toIso8601String(),
];
});
// Usage
$response = EasyDataTable::of(User::query())
->select(['id', 'name'])
->make(true)
->customResponse();
Add Custom Events: Listen to or dispatch events for hooks:
// Listen to 'afterQuery' event
EasyDataTable::listen('afterQuery', function($query, $request, $response) {
// Post-process response
$response['custom_field'] = 'added_via_event';
});
Integrate with Laravel Nova:
Use EasyDataTable as a backend for Nova tools:
// In a Nova Tool
public function handle(Request $
How can I help you explore Laravel packages today?