kevinpirnie / kpt-datatables
Advanced PHP DataTables library with CRUD operations, search, sorting, pagination, bulk actions, and UIKit3 integration
Fund package maintenance!
kpirnie
Requires
- php: >=8.1
- kevinpirnie/kpt-database: ^1.0
- kevinpirnie/kpt-logger: ^1.0
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0 || ^11.0
- squizlabs/php_codesniffer: ^3.7
README
Advanced PHP DataTables library with CRUD operations, search, sorting, pagination, bulk actions, and UIKit3 integration.
Features
- 🚀 Full CRUD Operations - Create, Read, Update, Delete with AJAX support
- 🔍 Advanced Search - Search all columns or specific columns
- 📊 Sorting - Multi-column sorting with visual indicators
- 📄 Pagination - Configurable page sizes with first/last navigation
- ✅ Bulk Actions - Select multiple records for bulk operations
- ✏️ Inline Editing - Double-click to edit fields directly in the table
- 📁 File Uploads - Built-in file upload handling with validation
- 🎨 Themes - Light and dark UIKit3 themes with toggle
- 📱 Responsive - Mobile-friendly design
- 🔗 JOINs - Support for complex database relationships
- 🎛️ Customizable - Extensive configuration options
- 🔧 Chainable API - Fluent interface for easy configuration
Requirements
- PHP 8.1 or higher
- PDO extension
- JSON extension
Installation
Install via Composer:
composer require kevinpirnie/kpt-datatables
Dependencies
This package depends on:
kevinpirnie/kpt-database
- Database wrapperkevinpirnie/kpt-logger
- Logging functionality
Quick Start
1. Basic Setup
<?php require 'vendor/autoload.php'; use KPT\DataTables\DataTables; // Option 1: Configure database via constructor $dbConfig = [ 'server' => 'localhost', 'schema' => 'your_database', 'username' => 'your_username', 'password' => 'your_password', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci' ]; $dataTable = new DataTables($dbConfig); // Option 2: Configure database via method chaining $dataTable = new DataTables(); $dataTable->database($dbConfig);
2. Include Required Assets
// Include JavaScript files echo DataTables::getJsIncludes();
3. Handle AJAX Requests
// Handle AJAX requests (before any HTML output) if (isset($_POST['action']) || isset($_GET['action'])) { $dataTable->handleAjax(); }
4. Simple Table
// Configure and render table echo $dataTable ->table('users') ->columns([ 'id' => 'ID', 'name' => 'Full Name', 'email' => 'Email Address', 'created_at' => 'Created' ]) ->sortable(['name', 'email', 'created_at']) ->renderDataTableComponent();
Advanced Usage
Complete Configuration Example
$dataTable = new DataTables($dbConfig); echo $dataTable ->table('users') ->primaryKey('user_id') // Default: 'id' ->columns([ 'user_id' => 'ID', 'name' => 'Name', 'email' => 'Email', 'role_name' => 'Role', 'status' => 'Status' ]) // JOIN other tables ->join('LEFT', 'user_roles r', 'u.role_id = r.role_id') // Configure sorting and editing ->sortable(['name', 'email', 'created_at']) ->inlineEditable(['name', 'email']) // Pagination options ->perPage(25) ->pageSizeOptions([10, 25, 50, 100], true) // true includes "ALL" option // Enable bulk actions ->bulkActions(true, [ 'activate' => [ 'label' => 'Activate Selected', 'icon' => 'check', 'class' => 'uk-button-secondary', 'confirm' => 'Activate selected users?', 'callback' => function($ids, $db, $table) { return $db->query("UPDATE {$table} SET status = 'active' WHERE user_id IN (" . implode(',', array_fill(0, count($ids), '?')) . ")") ->bind($ids) ->execute(); } ] ]) // Configure action buttons ->actions('end', true, true, [ [ 'icon' => 'mail', 'title' => 'Send Email', 'class' => 'btn-email' ] ]) // Add form configuration ->addForm('Add New User', [ 'name' => [ 'type' => 'text', 'label' => 'Full Name', 'required' => true, 'placeholder' => 'Enter full name' ], 'email' => [ 'type' => 'email', 'label' => 'Email Address', 'required' => true, 'placeholder' => 'user@example.com' ], 'role_id' => [ 'type' => 'select', 'label' => 'Role', 'required' => true, 'options' => [ '1' => 'Administrator', '2' => 'Editor', '3' => 'User' ] ], 'avatar' => [ 'type' => 'file', 'label' => 'Avatar Image' ], 'status' => [ 'type' => 'radio', 'label' => 'Status', 'options' => [ 'active' => 'Active', 'inactive' => 'Inactive' ], 'value' => 'active' ] ]) // Edit form (similar to add form) ->editForm('Edit User', [ // ... same fields as add form ]) // CSS customization ->tableClass('uk-table uk-table-striped uk-table-hover custom-table') ->rowClass('custom-row') ->columnClasses([ 'name' => 'uk-text-bold', 'email' => 'uk-text-primary', 'status' => 'uk-text-center' ]) // File upload configuration ->fileUpload('uploads/avatars/', ['jpg', 'jpeg', 'png', 'gif'], 5242880) // 5MB limit ->renderDataTableComponent();
Enhanced Column Configuration
Simple Configuration
->columns([ 'name' => 'Full Name', 'email' => 'Email Address' ])
Enhanced Configuration with Type Overrides
->columns([ 'active' => [ 'label' => 'Status', 'type' => 'boolean', 'class' => 'uk-text-center' ], 'category_id' => [ 'label' => 'Category', 'type' => 'select', 'options' => [ '1' => 'Category 1', '2' => 'Category 2' ] ] ])
Field Types
Text Inputs
'field_name' => [ 'type' => 'text', // text, email, url, tel, number, password 'label' => 'Field Label', 'required' => true, 'placeholder' => 'Placeholder text', 'class' => 'custom-css-class', 'attributes' => ['maxlength' => '100'] ]
Textarea
'description' => [ 'type' => 'textarea', 'label' => 'Description', 'placeholder' => 'Enter description...', 'attributes' => ['rows' => '5'] ]
Select Dropdown
'category' => [ 'type' => 'select', 'label' => 'Category', 'required' => true, 'options' => [ '1' => 'Category 1', '2' => 'Category 2', '3' => 'Category 3' ] ]
Boolean/Checkbox
'active' => [ 'type' => 'boolean', // Renders as select in forms, toggle in table 'label' => 'Active Status' ], 'newsletter' => [ 'type' => 'checkbox', 'label' => 'Subscribe to Newsletter', 'value' => '1' ]
Radio Buttons
'status' => [ 'type' => 'radio', 'label' => 'Status', 'options' => [ 'active' => 'Active', 'inactive' => 'Inactive', 'pending' => 'Pending' ], 'value' => 'active' ]
File Upload
'document' => [ 'type' => 'file', 'label' => 'Upload Document' ]
Date/Time Fields
'birth_date' => [ 'type' => 'date', 'label' => 'Birth Date' ], 'appointment' => [ 'type' => 'datetime-local', 'label' => 'Appointment Date & Time' ], 'meeting_time' => [ 'type' => 'time', 'label' => 'Meeting Time' ]
Bulk Actions
Built-in Delete Action
->bulkActions(true) // Enables default delete action
Custom Bulk Actions
->bulkActions(true, [ 'archive' => [ 'label' => 'Archive Selected', 'icon' => 'archive', 'class' => 'uk-button-secondary', 'confirm' => 'Archive selected records?', 'callback' => function($selectedIds, $database, $tableName) { $placeholders = implode(',', array_fill(0, count($selectedIds), '?')); return $database->query("UPDATE {$tableName} SET archived = 1 WHERE id IN ({$placeholders})") ->bind($selectedIds) ->execute(); }, 'success_message' => 'Records archived successfully', 'error_message' => 'Failed to archive records' ] ])
Action Button Groups
Grouped Actions with Separators
->actionGroups([ ['edit', 'delete'], // Group 1: built-in actions [ // Group 2: custom actions 'email' => [ 'icon' => 'mail', 'title' => 'Send Email', 'class' => 'btn-email' ], 'export' => [ 'icon' => 'download', 'title' => 'Export Data', 'class' => 'btn-export' ] ] ])
Database Joins
$dataTable ->table('orders o') ->join('INNER', 'customers c', 'o.customer_id = c.customer_id') ->join('LEFT', 'order_status s', 'o.status_id = s.status_id') ->columns([ 'order_id' => 'Order ID', 'customer_name' => 'Customer', 'order_date' => 'Date', 'status_name' => 'Status', 'total' => 'Total' ]);
AJAX vs Non-AJAX Forms
AJAX Forms (Default)
->addForm('Add Record', $fields, true) // true = AJAX ->editForm('Edit Record', $fields, true)
Traditional Form Submission
->addForm('Add Record', $fields, false) // false = traditional POST ->editForm('Edit Record', $fields, false)
File Upload Configuration
->fileUpload( 'uploads/documents/', // Upload path ['pdf', 'doc', 'docx', 'jpg'], // Allowed extensions 10485760 // Max file size (10MB) )
Search Configuration
Enable/Disable Search
->search(true) // Enable search ->search(false) // Disable search
CSS Customization
Table Classes
->tableClass('uk-table uk-table-striped uk-table-hover custom-table')
Row Classes with ID Suffix
->rowClass('highlight') // Creates classes like "highlight-123" for row with ID 123
Column-Specific Classes
->columnClasses([ 'name' => 'uk-text-bold uk-text-primary', 'status' => 'uk-text-center', 'actions' => 'uk-text-nowrap' ])
Complete Working Example
<?php require 'vendor/autoload.php'; use KPT\DataTables\DataTables; // Database configuration $dbConfig = [ 'server' => 'localhost', 'schema' => 'your_database', 'username' => 'your_username', 'password' => 'your_password', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci' ]; // Create DataTables instance $dataTable = new DataTables($dbConfig); // Handle AJAX requests first if (isset($_POST['action']) || isset($_GET['action'])) { $dataTable->handleAjax(); } ?> <!DOCTYPE html> <html> <head> <title>DataTables Example</title> <!-- UIKit CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.16.14/dist/css/uikit.min.css" /> <!-- UIKit JS --> <script src="https://cdn.jsdelivr.net/npm/uikit@3.16.14/dist/js/uikit.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/uikit@3.16.14/dist/js/uikit-icons.min.js"></script> <?php echo DataTables::getJsIncludes(); ?> </head> <body> <div class="uk-container uk-margin-top"> <?php echo $dataTable ->table('users') ->columns([ 'id' => 'ID', 'name' => 'Name', 'email' => 'Email', 'status' => [ 'label' => 'Status', 'type' => 'boolean' ] ]) ->sortable(['name', 'email']) ->inlineEditable(['name', 'email', 'status']) ->bulkActions(true) ->addForm('Add User', [ 'name' => [ 'type' => 'text', 'label' => 'Full Name', 'required' => true ], 'email' => [ 'type' => 'email', 'label' => 'Email', 'required' => true ], 'status' => [ 'type' => 'boolean', 'label' => 'Active', 'value' => '1' ] ]) ->editForm('Edit User', [ 'name' => [ 'type' => 'text', 'label' => 'Full Name', 'required' => true ], 'email' => [ 'type' => 'email', 'label' => 'Email', 'required' => true ], 'status' => [ 'type' => 'boolean', 'label' => 'Active' ] ]) ->renderDataTableComponent(); ?> </div> </body> </html>
Auto-Generated Forms
The library automatically generates forms based on your database schema:
- Text Fields: VARCHAR, CHAR columns become text inputs
- Email Fields: Columns with "email" in the name become email inputs
- Numbers: INT, DECIMAL, FLOAT columns become number inputs
- Booleans: TINYINT(1) columns become boolean toggles
- Dates: DATE, DATETIME, TIMESTAMP columns become date/datetime inputs
- Text Areas: TEXT, LONGTEXT columns become textareas
- Selects: ENUM columns become select dropdowns
You can override any auto-detected type using the enhanced column configuration.
Events and Hooks
JavaScript Events
// Table loaded document.addEventListener('datatables:loaded', function(e) { console.log('Table loaded', e.detail); }); // Record added document.addEventListener('datatables:record:added', function(e) { console.log('Record added', e.detail); }); // Theme changed document.addEventListener('datatables:theme:changed', function(e) { console.log('Theme changed to', e.detail.theme); });
API Methods
Core Configuration
table(string $tableName)
- Set the database tabledatabase(array $config)
- Configure database connectionprimaryKey(string $column)
- Set primary key column (default: 'id')columns(array $columns)
- Configure table columnsjoin(string $type, string $table, string $condition)
- Add JOIN clause
Display Options
sortable(array $columns)
- Set sortable columnsinlineEditable(array $columns)
- Set inline editable columnssearch(bool $enabled)
- Enable/disable searchperPage(int $count)
- Set records per pagepageSizeOptions(array $options, bool $includeAll)
- Set page size options
Actions and Forms
actions(string $position, bool $showEdit, bool $showDelete, array $customActions)
- Configure action buttonsactionGroups(array $groups)
- Configure grouped actions with separatorsbulkActions(bool $enabled, array $actions)
- Configure bulk actionsaddForm(string $title, array $fields, bool $ajax)
- Configure add formeditForm(string $title, array $fields, bool $ajax)
- Configure edit form
Styling
tableClass(string $class)
- Set table CSS classrowClass(string $class)
- Set row CSS class basecolumnClasses(array $classes)
- Set column-specific CSS classes
File Handling
fileUpload(string $path, array $extensions, int $maxSize)
- Configure file uploads
Rendering
renderDataTableComponent()
- Generate complete HTML outputhandleAjax()
- Handle AJAX requests
Static Methods
DataTables::getJsIncludes()
- Get JavaScript include tags
Browser Support
- Chrome 60+
- Firefox 60+
- Safari 12+
- Edge 79+
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Testing
# Run tests composer test # Run tests with coverage composer test-coverage # Run static analysis composer phpstan # Run code style check composer cs-check
Security
If you discover any security-related issues, please email security@kpirnie.com instead of using the issue tracker.
License
The MIT License (MIT). Please see License File for more information.
Credits
- Kevin Pirnie
- UIKit3 for the UI framework
- All contributors
Support
- Documentation: GitHub Wiki
- Issues: GitHub Issues
Roadmap
- Export functionality (CSV, Excel, PDF)
- Advanced filtering options
- Column visibility toggle
- Row drag & drop reordering
- Real-time updates via WebSockets
- Integration with popular PHP frameworks
- REST API endpoints
- Audit trail/change logging
Made with ❤️ by Kevin Pirnie