yajra/laravel-datatables-fractal
Fractal transformer plugin for yajra/laravel-datatables. Use League\Fractal to shape server-side DataTables JSON responses. Supports Laravel 12 / PHP 8.2+, with optional service provider and vendor:publish config/assets.
composer require yajra/laravel-datatables-fractal:^12.0
php artisan vendor:publish --tag=datatables-fractal
// config/app.php
'providers' => [
Yajra\DataTables\FractalServiceProvider::class,
],
(Auto-discovered in Laravel 5.5+)use Yajra\DataTables\Facades\DataTables;
use League\Fractal\Manager;
use League\Fractal\Resource\Collection;
Route::get('/users', function () {
$manager = app(Manager::class);
return DataTables::of(User::query())
->transform(function ($query) use ($manager) {
return $manager->createData(new Collection($query->get(), new UserTransformer()))
->toArray();
})
->make(true);
});
UserTransformer).->transform() to inject Fractal into the response pipeline.app/Transformers/UserTransformer.php):
namespace App\Transformers;
use App\Models\User;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
public function transform(User $user)
{
return [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'full_name' => $user->first_name . ' ' . $user->last_name, // Computed field
];
}
}
return DataTables::of(User::query())
->transform(function ($query) {
$manager = app(\League\Fractal\Manager::class);
return $manager->createData(
new \League\Fractal\Resource\Collection($query->get(), new UserTransformer())
)->toArray();
})
->addColumn('full_name', function ($user) {
return $user->first_name . ' ' . $user->last_name;
}) // Optional: Add DataTables-specific columns
->make(true);
// UserTransformer.php
public function transform(User $user)
{
return [
'id' => $user->id,
'orders' => $this->collection($user->orders, new OrderTransformer()),
];
}
return DataTables::of(User::with(request('includes', [])))
->transform(function ($query) {
$manager = app(\League\Fractal\Manager::class);
return $manager->createData(
new \League\Fractal\Resource\Collection($query->get(), new UserTransformer())
)->toArray();
});
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind(\League\Fractal\Serializer\DataArraySerializer::class, function () {
return new \League\Fractal\Serializer\ArraySerializer();
});
}
// API Resource (Laravel 8+)
public function toArray($request)
{
$manager = app(\League\Fractal\Manager::class);
return $manager->createData(
new \League\Fractal\Resource\Item($this->resource, new UserTransformer())
)->toArray();
}
return DataTables::of(User::query())
->transform(function ($query) {
$manager = app(\League\Fractal\Manager::class);
$collection = $manager->createData(
new \League\Fractal\Resource\Collection($query->get(), new UserTransformer())
);
return [
'data' => $collection->toArray()['data'],
'recordsTotal' => $query->getQuery()->getCountForPagination(),
'recordsFiltered' => $query->getQuery()->getCountForPagination(),
];
})
->make(true);
->addColumn(), ->editColumn(), or ->rawColumns() alongside Fractal for hybrid responses.$manager = app(\League\Fractal\Manager::class);
$cachedTransformer = cache()->remember('user.transformer', now()->addHours(1), function () use ($manager) {
return $manager->createData(new \League\Fractal\Resource\Collection([], new UserTransformer()));
});
// Frontend (DataTables.js)
$.ajax({
url: '/users',
data: table.params(),
success: function (data) {
table.clear().rows.add(data.data).draw();
}
});
Double Data Loading
cursor() for pagination:
$manager->createData(new \League\Fractal\Resource\Collection($query->cursor(), new UserTransformer()))
Transformer Not Found
Class 'App\Transformers\UserTransformer' not found due to autoloading.Transformers namespace is registered in composer.json:
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
}
Then run composer dump-autoload.Includes Parameter Conflict
includes parameter (for eager loading) may conflict with DataTables’ internal parameters.request('includes', []) explicitly (as shown in the docs) or alias it in your routes:
Route::get('/users', function () {
return DataTables::of(User::with(request('with', [])))->...
});
Fractal Serializer Mismatch
recordsTotal).$fractalData = $manager->createData(...)->toArray();
return array_merge($fractalData, [
'recordsTotal' => $query->getQuery()->getCountForPagination(),
'recordsFiltered' => $query->getQuery()->getCountForPagination(),
]);
Laravel 12+ Pitfalls
app(Manager::class) may fail if Fractal isn’t bound.AppServiceProvider:
public function boot()
{
$this->app->singleton(\League\Fractal\Manager::class, function () {
$manager = new \League\Fractal\Manager();
$manager->setSerializer(new \League\Fractal\Serializer\DataArraySerializer());
return $manager;
});
}
return $manager->createData(new \League\Fractal\Resource\Collection([$user], new UserTransformer()))->toArray();
\Log::info('DataTables params:', request()->all());
php artisan fractal:validate (if available) or manually test transformers:
$user = User::first();
$transformer = new UserTransformer();
$data = $transformer->transform($user);
AppServiceProvider:
$this->app->singleton(\League\F
How can I help you explore Laravel packages today?