mikailfaruqali / datatable
A powerful Laravel package for building server-side DataTables with custom column builders, easy frontend integration, and comprehensive export functionality.
Requires
- php: >=7.4
- illuminate/contracts: >=5.0
- maatwebsite/excel: *
Requires (Dev)
- driftingly/rector-laravel: ^2.0
- laravel/pint: ^1.14
- orchestra/testbench: ^8.22 || ^9.0
This package is auto-updated.
Last update: 2025-09-11 22:05:54 UTC
README
A powerful Laravel package for building server-side DataTables with custom column builders, easy frontend integration, and comprehensive export functionality.
Features
- 🚀 Server-side Processing: Efficient handling of large datasets
- 🎨 Custom Column Builders: Flexible column customization and formatting
- 📊 Export Functionality: Built-in Excel export with formatting
- 🖨️ Print Support: Professional print layouts
- 🔍 Advanced Filtering: Column-specific filtering and search
- 📱 Responsive Design: Mobile-friendly tables
- 🌐 Multi-language Support: Localization ready (English, Arabic, Kurdish)
- 🎛️ Column Visibility: User-controlled column hiding/showing
- 📈 Aggregation Support: Built-in totals and calculations
- ⚡ Performance Optimized: Efficient query building and caching
Requirements
- PHP >= 7.4
- Laravel >= 5.0
- Maatwebsite/Excel package
Installation
Install the package via Composer:
composer require mikailfaruqali/datatable
Publish Assets
Publish the package configuration, views, and language files:
php artisan vendor:publish --tag=snawbar-datatable-assets
Run Migrations
The package includes migrations for column visibility preferences:
php artisan migrate
Configuration
After publishing assets, configure your DataTable settings in config/snawbar-datatable.php
:
return [ // Session key for text direction (LTR/RTL) 'local-direction-session-key' => 'direction', // Default table CSS classes 'table-style' => 'table table-bordered w-100', // Font URL (optional) 'font' => null, // CSS assets for DataTables 'datatable-css' => [ 'https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css', 'https://cdn.datatables.net/buttons/2.3.6/css/buttons.bootstrap5.min.css', ], // JavaScript assets for DataTables 'datatable-js' => [ 'https://code.jquery.com/jquery-3.6.0.min.js', 'https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js', 'https://cdn.datatables.net/1.13.4/js/dataTables.bootstrap5.min.js', 'https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js', ], // Print-specific CSS 'datatable-print-css' => [ // Add print-specific stylesheets ], ];
Quick Start
1. Generate a DataTable Class
Use the Artisan command to generate a new DataTable class:
php artisan make:datatable UserDataTable
This creates a new class in app/DataTables/UserDataTable.php
.
2. Configure Your DataTable
<?php namespace App\DataTables; use Illuminate\Database\Query\Builder; use Illuminate\Http\Request; use Snawbar\DataTable\Components\DataTable; use Snawbar\DataTable\Services\Column; use App\Models\User; class UserDataTable extends DataTable { public function query(Request $request): Builder { return User::query() ->select(['id', 'name', 'email', 'created_at']) ->when($request->search['value'], function ($query, $search) { $query->where('name', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%"); }); } public function columns(): array { return [ Column::make('id')->title('ID')->orderable(), Column::make('name')->title('Name')->orderable(), Column::make('email')->title('Email')->orderable(), Column::make('created_at')->title('Created At')->orderable(), ]; } public function tableId(): string { return 'users-table'; } public function setupColumns(): void { $this->editColumn('created_at', function ($row) { return $row->created_at->format('Y-m-d H:i:s'); }); $this->addColumn('actions', function ($row) { return '<button class="btn btn-sm btn-primary">Edit</button>'; }); } public function isOrderable(): bool { return true; } public function length(): int { return 25; } public function exportTitle(): ?string { return 'Users Export'; } }
3. Use in Controller
<?php namespace App\Http\Controllers; use App\DataTables\UserDataTable; use Illuminate\Http\Request; class UserController extends Controller { public function index(Request $request, UserDataTable $dataTable) { if ($request->isAjaxDatatable()) { return $dataTable->builder()->ajax(); } return view('users.index', [ 'dataTable' => $dataTable->builder() ]); } }
4. Display in Blade View
Add the DataTable CSS and JS assets to your layout:
{{-- In your layout head --}} @datatableCss {{-- Before closing body tag --}} @datatableJs
Display the DataTable in your view:
{{-- resources/views/users/index.blade.php --}} @extends('layouts.app') @section('content') <div class="container"> <h1>Users</h1> {!! $dataTable->html() !!} {!! $dataTable->tableTotalableHtml() !!} </div> @endsection
Advanced Features
Column Customization
Edit Existing Columns
public function setupColumns(): void { // Format currency $this->editColumn('price', function ($row) { return '$' . number_format($row->price, 2); }); // Format dates $this->editColumn('created_at', function ($row) { return $row->created_at->format('M d, Y'); }); // Conditional formatting $this->editColumn('status', function ($row) { $class = $row->status === 'active' ? 'success' : 'danger'; return "<span class='badge bg-{$class}'>{$row->status}</span>"; }); }
Add Custom Columns
public function setupColumns(): void { // Add action buttons $this->addColumn('actions', function ($row) { return view('partials.action-buttons', compact('row'))->render(); }); // Add computed values $this->addColumn('full_name', function ($row) { return "{$row->first_name} {$row->last_name}"; }); }
Column Types and Options
public function columns(): array { return [ Column::make('id') ->title('ID') ->orderable() ->className('text-center'), Column::make('name') ->title('Full Name') ->orderable() ->searchable(), Column::make('price') ->title('Price') ->type('number') ->orderable(), Column::make('actions') ->title('Actions') ->orderable(false) ->printable(false) ->exportable(false), ]; }
Totals and Aggregations
public function totalableColumns(): ?array { return [ 'price' => 'sum', 'quantity' => 'sum', 'id' => 'count', ]; }
Export Configuration
public function exportTitle(): ?string { return 'Sales Report - ' . now()->format('Y-m-d'); } // Custom export data processing protected function prepareExportData(): array { // Custom logic for export data return $this->builder->get()->toArray(); }
Filtering and Search
public function query(Request $request): Builder { return Product::query() ->select(['id', 'name', 'price', 'category_id']) ->with('category') ->when($request->input('category'), function ($query, $category) { $query->where('category_id', $category); }) ->when($request->search['value'], function ($query, $search) { $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%") ->orWhereHas('category', function ($categoryQuery) use ($search) { $categoryQuery->where('name', 'like', "%{$search}%"); }); }); }); } public function filterContainer(): ?string { return '#custom-filter-container'; }
Print Customization
public function attachPrintSubitems(object $row): ?Collection { // Add sub-items for detailed print view return collect([ ['label' => 'Order Items', 'value' => $row->items->count()], ['label' => 'Total Amount', 'value' => '$' . number_format($row->total, 2)], ]); }
Callbacks and JavaScript Integration
public function callbacks(): ?array { return [ 'initComplete' => 'function() { console.log("Table initialized"); }', 'drawCallback' => 'function() { $("[data-toggle=tooltip]").tooltip(); }', 'rowCallback' => 'function(row, data, index) { if (data.status === "inactive") { $(row).addClass("table-warning"); } }' ]; }
Blade Directives
The package provides several helpful Blade directives:
Asset Loading
{{-- Load DataTable CSS --}} @datatableCss {{-- Load DataTable JavaScript --}} @datatableJs {{-- Load print-specific CSS --}} @datatablePrintCss
Table Spacing
{{-- Add empty rows for spacing --}} @datatableRowSpace(3)
Helper Functions
The package includes useful helper functions:
// Process DataTable request $process = datatableProcess($dataTableInstance); // Handle asset URLs $url = assetOrUrl('/css/custom.css'); // Returns asset() or the URL as-is // Conditional rendering $html = datatableWhen($condition, '<b>Bold</b>', 'Normal'); // Print HTML safely datatablePrintHtml($htmlContent);
Request Macro
Check if the current request is a DataTable AJAX request:
if (request()->isAjaxDatatable()) { return $dataTable->ajax(); }
Localization
The package supports multiple languages. Publish the language files and customize:
php artisan vendor:publish --tag=snawbar-datatable-assets
Available languages:
- English (
en
) - Arabic (
ar
) - Kurdish (
ku
)
Styling and Theming
Bootstrap Integration
The package works seamlessly with Bootstrap:
// In config/snawbar-datatable.php 'table-style' => 'table table-striped table-bordered table-hover',
Custom CSS
Add custom styles to your DataTable:
.dataTables_wrapper .dataTables_filter input { border-radius: 0.375rem; border: 1px solid #ced4da; } .dataTables_wrapper .dataTables_length select { border-radius: 0.375rem; border: 1px solid #ced4da; }
Performance Optimization
Database Optimization
public function query(Request $request): Builder { return User::query() ->select(['id', 'name', 'email', 'created_at']) // Select only needed columns ->with(['role:id,name']) // Eager load relationships ->when($request->search['value'], function ($query, $search) { // Use indexes for search $query->whereRaw('MATCH(name, email) AGAINST(? IN BOOLEAN MODE)', [$search]); }); }
Caching
public function query(Request $request): Builder { $cacheKey = "datatable.users." . md5(serialize($request->all())); return cache()->remember($cacheKey, 300, function () use ($request) { return User::query()->select(['id', 'name', 'email', 'created_at']); }); }
Testing
use Tests\TestCase; use App\DataTables\UserDataTable; class UserDataTableTest extends TestCase { public function test_datatable_returns_correct_structure() { $request = request()->merge(['draw' => 1]); $dataTable = new UserDataTable($request); $response = $dataTable->builder()->ajax(); $this->assertArrayHasKey('data', $response->getData(true)); $this->assertArrayHasKey('recordsTotal', $response->getData(true)); } }
Troubleshooting
Common Issues
- Missing jQuery: Ensure jQuery is loaded before DataTables JavaScript
- Column Mismatch: Verify that column count matches between frontend and backend
- Export Issues: Check that Maatwebsite/Excel is properly installed
- Permission Errors: Ensure proper authentication for column visibility features
Debug Mode
Enable debug mode to see SQL queries:
// In your DataTable class public function query(Request $request): Builder { \DB::enableQueryLog(); $query = User::query()->select(['id', 'name', 'email']); \Log::info(\DB::getQueryLog()); return $query; }
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This package is open-sourced software licensed under the MIT license.
Credits
- Snawbar
- Built with Laravel
- Powered by DataTables
- Export functionality by Maatwebsite/Excel
Support
If you discover any security vulnerabilities or bugs, please send an e-mail to alanfaruq85@gmail.com.