Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Datatables Fractal Laravel Package

yajra/laravel-datatables-fractal

Laravel DataTables Fractal plugin for Laravel: transform server-side DataTables responses using League Fractal. Works with PHP 8.2+ and Laravel 12+. Install via Composer; optional service provider and vendor:publish config.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require yajra/laravel-datatables-fractal:^12.0
    
  2. Publish config (optional):
    php artisan vendor:publish --tag=datatables-fractal
    
  3. First use case: Transform a basic Eloquent query into a Fractal-formatted DataTables response.

Example: Quick Implementation

use Yajra\DataTables\Facades\DataTables;
use League\Fractal\Manager;
use League\Fractal\Resource\Collection;

class UserController extends Controller
{
    public function anyData()
    {
        $fractal = app(Manager::class);
        return DataTables::of(User::query())
            ->transform(function ($query) use ($fractal) {
                return $fractal->collection($query->get(), new UserTransformer());
            });
    }
}

Where to Look First

  • Official Documentation for transformer setup.
  • app/Transformers/ directory (create if missing) for custom transformers.
  • config/datatables-fractal.php for global configuration (e.g., default format).

Implementation Patterns

Core Workflow

  1. Define a Transformer:

    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,
                'created_at' => $user->created_at->format('Y-m-d'),
            ];
        }
    }
    
  2. Integrate with DataTables:

    return DataTables::of(User::query())
        ->transform(function ($query) {
            return Fractal::collection($query->get(), new UserTransformer());
        });
    
  3. Handle Nested Resources:

    // Transformer for nested relationships
    class OrderTransformer extends TransformerAbstract
    {
        public function transform(Order $order)
        {
            return [
                'id' => $order->id,
                'user' => $this->includeUser($order),
                'total' => $order->total,
            ];
        }
    
        protected function includeUser(Order $order)
        {
            return $this->item($order->user, new UserTransformer());
        }
    }
    

Integration Tips

  • Leverage Fractal’s include() for eager loading:
    return DataTables::of(Order::with('user'))
        ->transform(function ($query) {
            return Fractal::collection($query->get(), new OrderTransformer())
                ->parseIncludes(['user']);
        });
    
  • Use addColumn for computed fields:
    return DataTables::of(User::query())
        ->addColumn('full_name', function ($user) {
            return $user->first_name . ' ' . $user->last_name;
        })
        ->transform(function ($query) {
            return Fractal::collection($query->get(), new UserTransformer());
        });
    
  • Global Transformer Binding (via FractalServiceProvider):
    // config/datatables-fractal.php
    'transformers' => [
        'default' => \App\Transformers\UserTransformer::class,
    ],
    

Common Patterns

Pattern Example
Basic Transformer Fractal::collection($query->get(), new UserTransformer())
Nested Includes ->parseIncludes(['user', 'user.address'])
Custom Format Fractal::create()->format(new JsonApiFormat())
Conditional Fields Use if in transformer methods to exclude sensitive data.
Pagination Meta Fractal automatically includes meta for pagination details.

Gotchas and Tips

Pitfalls

  1. Double Data Loading:

    • Issue: Calling ->get() inside transform loads data twice (once for DataTables, once for Fractal).
    • Fix: Use ->cursor() or optimize with ->select():
      return DataTables::of(User::query()->select(['id', 'name', 'email']))
          ->transform(function ($query) {
              return Fractal::collection($query->cursor(), new UserTransformer());
          });
      
  2. Transformer Not Found:

    • Issue: Class 'App\Transformers\UserTransformer' not found.
    • Fix: Ensure the transformer is autoloaded (PSR-4 compliant) or manually register it in FractalServiceProvider.
  3. Fractal Format Mismatch:

    • Issue: Frontend expects data but Fractal returns items.
    • Fix: Configure the format explicitly:
      Fractal::create()->format(new JsonApiFormat())->collection($data, $transformer);
      
  4. Circular References:

    • Issue: Infinite recursion in nested transformers (e.g., User->orders->user).
    • Fix: Use Fractal::manager()->parseIncludes() and manually handle cycles:
      $fractal = Fractal::create();
      $fractal->parseIncludes(['user']);
      $fractal->collection($orders, new OrderTransformer());
      
  5. Case Sensitivity in Includes:

    • Issue: include=user fails if transformer method is includeUser().
    • Fix: Use parseIncludes() with exact method names or configure a mapper.

Debugging Tips

  • Inspect Raw Data:
    ->transform(function ($query) {
        $data = $query->get();
        dd($data->toArray()); // Debug before transformation
        return Fractal::collection($data, new UserTransformer());
    });
    
  • Check Fractal Output:
    $resource = Fractal::collection($data, new UserTransformer());
    dd($resource->toArray());
    
  • Enable Fractal Debugging:
    Fractal::create()->debug(true)->collection($data, $transformer);
    

Extension Points

  1. Custom Formats: Extend League\Fractal\Resource\ResourceAbstract for non-JSON:API/HAL formats.

    class CustomFormat extends FormatAbstract
    {
        public function getDataArray($resource)
        {
            return ['data' => $resource->toArray()];
        }
    }
    
  2. Dynamic Transformers: Use dependency injection to switch transformers based on request:

    $transformer = app()->make(\App\Transformers\DynamicTransformer::class, [
        'format' => request('format', 'json:api')
    ]);
    
  3. Middleware for Fractal: Add middleware to modify Fractal responses globally:

    namespace App\Http\Middleware;
    
    use Closure;
    use League\Fractal\Manager;
    
    class FractalResponseMiddleware
    {
        public function handle($request, Closure $next)
        {
            $response = $next($request);
            if ($response->hasHeader('X-Fractal')) {
                $response->getContent();
                // Modify response here
            }
            return $response;
        }
    }
    
  4. Testing Transformers: Use Pest/Laravel’s testing helpers:

    public function test_user_transformer()
    {
        $user = User::factory()->create();
        $transformer = new UserTransformer();
        $data = $transformer->transform($user);
        $this->assertArrayHasKey('email', $data);
    }
    

Configuration Quirks

  • Default Transformer: Set in config/datatables-fractal.php:

    'transformers' => [
        'default' => \App\Transformers\UserTransformer::class,
    ],
    

    Override per route:

    return DataTables::of(User::query())
        ->setTransformer(new AdminUserTransformer());
    
  • Fractal Manager Binding: Bind a custom manager in FractalServiceProvider:

    $this->app->singleton(Manager::class, function ($app) {
        $manager = new Manager();
        $manager->parseIncludes = true;
        return $manager;
    });
    

Performance Optimizations

  • Lazy Loading: Use cursor() for large datasets:
    return DataTables::of(User::query())
        ->transform(function ($query) {
            return Fractal::collection($query->cursor(), new UserTransformer());
        });
    
  • Selective Fields: Limit columns in the query:
    return DataTables::of(User::query()->select(['id', 'name', 'email']))
        ->transform(...);
    
  • **
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai