├── .github └── workflows │ └── ci.yaml ├── LICENSE ├── README.md ├── assets ├── dist │ ├── controller.js │ └── functions │ │ ├── deleteRow.js │ │ ├── getLoadedDataTablesStyleSheet.js │ │ ├── loadButtonsLibrary.js │ │ ├── loadDataTableLibrary.js │ │ ├── loadResponsiveLibrary.js │ │ └── loadSelectLibrary.js └── package.json ├── composer.json ├── docs ├── action-columns.md ├── ajax.md ├── columns.md ├── configuration.md ├── extensions.md ├── installation.md ├── options.md └── usage.md ├── src ├── Builder │ ├── DataTableBuilder.php │ ├── DataTableBuilderInterface.php │ ├── DataTableResponseBuilder.php │ └── DataTableResponseBuilderInterface.php ├── DataTablesBundle.php ├── Enum │ ├── Action.php │ ├── ButtonType.php │ ├── ColumnType.php │ ├── Feature.php │ ├── Language.php │ ├── SelectItemType.php │ └── SelectStyle.php ├── Model │ ├── ActionColumn.php │ ├── Column.php │ ├── ColumnInterface.php │ ├── DataTable.php │ ├── DataTableExtensions.php │ ├── DataTableOptions.php │ ├── Extensions │ │ ├── ButtonsExtension.php │ │ ├── ExtensionInterface.php │ │ ├── ResponsiveExtension.php │ │ └── SelectExtension.php │ └── Options │ │ ├── AjaxOption.php │ │ └── LayoutOption.php └── Twig │ └── DataTablesExtension.php └── tsconfig.json /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: "Test Suite" 2 | 3 | on: 4 | pull_request_target: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | run: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | php: ['8.2', '8.3', '8.4'] 15 | name: PHP ${{ matrix.php }} ${{ matrix.description }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup PHP 21 | uses: shivammathur/setup-php@v2 22 | with: 23 | php-version: ${{ matrix.php }} 24 | 25 | - name: Dump PHP diagnostics 26 | run: php -i && php -m 27 | 28 | - name: Install dependencies 29 | run: composer install --no-progress 30 | 31 | - name: Check for dangerous and broken dependencies 32 | run: composer audit 33 | 34 | - name: Run automated tests 35 | run: vendor/bin/phpunit --coverage-text --coverage-xml build/coverage-xml --coverage-cobertura build/cobertura.xml 36 | 37 | - name: Upload coverage reports to Codecov 38 | uses: codecov/codecov-action@v5 39 | with: 40 | token: ${{ secrets.CODECOV_TOKEN }} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Tanguy Lemarié 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UX DataTables 2 | 3 | UX DataTables is a Symfony bundle integrating the [DataTables][1] 4 | library in Symfony applications. 5 | 6 | [1]: https://datatables.net 7 | 8 | ## Requirements 9 | - PHP 8.2 or higher 10 | - StimulusBundle 11 | - Composer 12 | 13 | ## Installation 14 | 15 | Install the library via Composer: 16 | 17 | ```console 18 | composer require pentiminax/ux-datatables 19 | ``` 20 | 21 | ## Advanced documentation 22 | - [Installation](https://github.com/pentiminax/ux-datatables/blob/main/docs/installation.md) 23 | - [Configuration](https://github.com/pentiminax/ux-datatables/blob/main/docs/configuration.md) 24 | - [Extensions](https://github.com/pentiminax/ux-datatables/blob/main/docs/extensions.md) 25 | - [Usage](https://github.com/pentiminax/ux-datatables/blob/main/docs/usage.md) 26 | - [Ajax](https://github.com/pentiminax/ux-datatables/blob/main/docs/ajax.md) 27 | - [Columns](https://github.com/pentiminax/ux-datatables/blob/main/docs/columns.md) 28 | -------------------------------------------------------------------------------- /assets/dist/controller.js: -------------------------------------------------------------------------------- 1 | import {Controller} from '@hotwired/stimulus'; 2 | import {getLoadedDataTablesStyleSheet} from "./functions/getLoadedDataTablesStyleSheet.js"; 3 | import {loadButtonsLibrary} from "./functions/loadButtonsLibrary.js"; 4 | import {loadDataTableLibrary} from "./functions/loadDataTableLibrary.js"; 5 | import {loadSelectLibrary} from "./functions/loadSelectLibrary.js"; 6 | import {loadResponsiveLibrary} from "./functions/loadResponsiveLibrary.js"; 7 | import {deleteRow} from "./functions/deleteRow.js"; 8 | 9 | class default_1 extends Controller { 10 | constructor() { 11 | super(...arguments); 12 | this.table = null; 13 | this.isDataTableInitialized = false; 14 | } 15 | 16 | async connect() { 17 | if (this.isDataTableInitialized) { 18 | return; 19 | } 20 | 21 | if (!(this.element instanceof HTMLTableElement)) { 22 | throw new Error('Invalid element'); 23 | } 24 | 25 | const payload = this.viewValue; 26 | 27 | this.dispatchEvent('pre-connect', { 28 | config: payload, 29 | }); 30 | 31 | const stylesheet = getLoadedDataTablesStyleSheet(); 32 | const DataTable = await loadDataTableLibrary(stylesheet); 33 | 34 | if (this.isButtonsExtensionEnabled(payload)) { 35 | await loadButtonsLibrary(DataTable, stylesheet); 36 | } 37 | 38 | if (this.isSelectExtensionEnabled(payload)) { 39 | await loadSelectLibrary(stylesheet); 40 | } 41 | 42 | if (this.isResponsiveExtensionEnabled(payload)) { 43 | await loadResponsiveLibrary(stylesheet); 44 | } 45 | 46 | payload.columns.forEach((column, index) => { 47 | if (column.action === 'DELETE') { 48 | column.render = function (data, type, row) { 49 | const className = `${column.action.toLowerCase()}-action`; 50 | 51 | return ``; 52 | }; 53 | } 54 | }); 55 | 56 | this.table = new DataTable(this.element, payload); 57 | this.isDataTableInitialized = true; 58 | 59 | this.element.addEventListener('click', async (e) => { 60 | if (e.target.matches('.delete-action')) { 61 | const url = e.target.getAttribute('data-url'); 62 | 63 | if (url) { 64 | const response = await deleteRow({ 65 | id: e.target.getAttribute('data-id'), 66 | url: url, 67 | }); 68 | 69 | if (response.ok) { 70 | this.table.ajax.reload(); 71 | } 72 | } 73 | } 74 | }); 75 | 76 | this.dispatchEvent('connect', {table: this.table}); 77 | } 78 | 79 | dispatchEvent(name, payload) { 80 | this.dispatch(name, { 81 | detail: payload, 82 | prefix: 'datatables' 83 | }); 84 | } 85 | 86 | isButtonsExtensionEnabled(payload) { 87 | return !!(payload?.layout?.topStart?.buttons); 88 | } 89 | 90 | isSelectExtensionEnabled(payload) { 91 | return !!payload?.select; 92 | } 93 | 94 | isResponsiveExtensionEnabled(payload) { 95 | return !!payload?.responsive; 96 | } 97 | } 98 | 99 | default_1.values = { 100 | view: Object, 101 | }; 102 | 103 | export default default_1; -------------------------------------------------------------------------------- /assets/dist/functions/deleteRow.js: -------------------------------------------------------------------------------- 1 | export async function deleteRow({id, url}) { 2 | return await fetch(url, { 3 | method: 'DELETE', 4 | headers: { 5 | 'Content-Type': 'application/json', 6 | 'X-Requested-With': 'XMLHttpRequest', 7 | }, 8 | body: JSON.stringify({id}), 9 | }); 10 | } -------------------------------------------------------------------------------- /assets/dist/functions/getLoadedDataTablesStyleSheet.js: -------------------------------------------------------------------------------- 1 | export function getLoadedDataTablesStyleSheet() { 2 | const cssFiles = [ 3 | 'dataTables.dataTables', 4 | 'dataTables.bootstrap5', 5 | ]; 6 | const loadedCSS = [...document.styleSheets].find(sheet => sheet.href && cssFiles.some(cssFile => sheet.href.includes(cssFile))); 7 | if (!loadedCSS) { 8 | console.warn('Warning: Required DataTables CSS file is not loaded.'); 9 | return null; 10 | } 11 | return loadedCSS; 12 | } 13 | -------------------------------------------------------------------------------- /assets/dist/functions/loadButtonsLibrary.js: -------------------------------------------------------------------------------- 1 | import 'datatables.net-buttons/js/buttons.html5'; 2 | import 'datatables.net-buttons/js/buttons.print'; 3 | import JSZip from 'jszip'; 4 | import pdfMake from 'pdfmake'; 5 | import 'pdfmake/build/vfs_fonts'; 6 | export async function loadButtonsLibrary(DataTable, stylesheet) { 7 | (await import('datatables.net-buttons')).default; 8 | if (stylesheet?.href?.includes('dataTables.bootstrap5')) { 9 | (await import('datatables.net-buttons-bs5')).default; 10 | } 11 | else { 12 | (await import('datatables.net-buttons-dt')).default; 13 | } 14 | DataTable.Buttons.jszip(JSZip); 15 | DataTable.Buttons.pdfMake(pdfMake); 16 | } 17 | -------------------------------------------------------------------------------- /assets/dist/functions/loadDataTableLibrary.js: -------------------------------------------------------------------------------- 1 | export async function loadDataTableLibrary(stylesheet) { 2 | if (stylesheet?.href?.includes('dataTables.bootstrap5')) { 3 | return (await import('datatables.net-bs5')).default; 4 | } 5 | else { 6 | return (await import('datatables.net-dt')).default; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /assets/dist/functions/loadResponsiveLibrary.js: -------------------------------------------------------------------------------- 1 | export async function loadResponsiveLibrary(stylesheet) { 2 | if (stylesheet?.href?.includes('dataTables.bootstrap5')) { 3 | (await import('datatables.net-responsive-bs5')).default; 4 | } 5 | else { 6 | (await import('datatables.net-responsive-dt')).default; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /assets/dist/functions/loadSelectLibrary.js: -------------------------------------------------------------------------------- 1 | export async function loadSelectLibrary(stylesheet) { 2 | if (stylesheet?.href?.includes('dataTables.bootstrap5')) { 3 | (await import('datatables.net-select-bs5')).default; 4 | } 5 | else { 6 | (await import('datatables.net-select-dt')).default; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pentiminax/ux-datatables", 3 | "description": "DataTables integration for Symfony", 4 | "license": "MIT", 5 | "version": "1.0.0", 6 | "type": "module", 7 | "main": "dist/controller.js", 8 | "symfony": { 9 | "controllers": { 10 | "datatable": { 11 | "main": "dist/controller.js", 12 | "webpackMode": "eager", 13 | "fetch": "eager", 14 | "enabled": true, 15 | "autoimport": { 16 | "datatables.net-bs5/css/dataTables.bootstrap5.min.css": false, 17 | "datatables.net-dt/css/dataTables.dataTables.min.css": true 18 | } 19 | } 20 | }, 21 | "importmap": { 22 | "@hotwired/stimulus": "^3.0.0", 23 | "datatables.net-bs5": "^2.3.1", 24 | "datatables.net-buttons": "^3.2.3", 25 | "datatables.net-buttons-bs5": "^3.2.3", 26 | "datatables.net-buttons-dt": "^3.2.3", 27 | "datatables.net-buttons/js/buttons.html5": "^3.2.3", 28 | "datatables.net-buttons/js/buttons.print": "^3.2.3", 29 | "datatables.net-dt": "^2.3.1", 30 | "datatables.net-select-bs5": "^3.0.0", 31 | "datatables.net-select-dt": "^3.0.0", 32 | "datatables.net-responsive-bs5": "^3.0.4", 33 | "datatables.net-responsive-dt": "^3.0.4", 34 | "jszip": "^3.10.1", 35 | "pdfmake": "^0.2.19", 36 | "pdfmake/build/vfs_fonts": "^0.2.18" 37 | } 38 | }, 39 | "peerDependencies": { 40 | "@hotwired/stimulus": "^3.0.0", 41 | "datatables.net-bs5": "^2.3.1", 42 | "datatables.net-buttons": "^3.2.3", 43 | "datatables.net-buttons-bs5": "^3.2.3", 44 | "datatables.net-buttons-dt": "^3.2.3", 45 | "datatables.net-buttons/js/buttons.html5": "^3.2.3", 46 | "datatables.net-buttons/js/buttons.print": "^3.2.3", 47 | "datatables.net-dt": "^2.3.1", 48 | "datatables.net-select-bs5": "^3.0.0", 49 | "datatables.net-select-dt": "^3.0.0", 50 | "datatables.net-responsive-bs5": "^3.0.4", 51 | "datatables.net-responsive-dt": "^3.0.4", 52 | "jszip": "^3.10.1", 53 | "pdfmake": "^0.2.19", 54 | "pdfmake/build/vfs_fonts": "^0.2.18" 55 | }, 56 | "devDependencies": { 57 | "@hotwired/stimulus": "^3.0.0", 58 | "datatables.net-bs5": "^2.3.1", 59 | "datatables.net-buttons": "^3.2.3", 60 | "datatables.net-buttons-bs5": "^3.2.3", 61 | "datatables.net-buttons-dt": "^3.2.3", 62 | "datatables.net-buttons/js/buttons.html5": "^3.2.3", 63 | "datatables.net-buttons/js/buttons.print": "^3.2.3", 64 | "datatables.net-dt": "^2.3.1", 65 | "datatables.net-select-bs5": "^3.0.0", 66 | "datatables.net-select-dt": "^3.0.0", 67 | "datatables.net-responsive-bs5": "^3.0.4", 68 | "datatables.net-responsive-dt": "^3.0.4", 69 | "jszip": "^3.10.1", 70 | "pdfmake": "^0.2.19", 71 | "pdfmake/build/vfs_fonts": "^0.2.18" 72 | } 73 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pentiminax/ux-datatables", 3 | "type": "symfony-bundle", 4 | "description": "DataTables.net integration for Symfony", 5 | "keywords": [ 6 | "symfony-ux" 7 | ], 8 | "homepage": "https://github.com/pentiminax/ux-datatables", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Tanguy Lemarié", 13 | "email": "tanguy.lemarie6@gmail.com" 14 | } 15 | ], 16 | "autoload": { 17 | "psr-4": { 18 | "Pentiminax\\UX\\DataTables\\": "src/" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "Pentiminax\\UX\\DataTables\\Tests\\": "tests/" 24 | } 25 | }, 26 | "require": { 27 | "php": ">=8.2", 28 | "symfony/config": "^7.0", 29 | "symfony/dependency-injection": "^7.0", 30 | "symfony/http-kernel": "^7.0", 31 | "symfony/stimulus-bundle": "^2.22" 32 | }, 33 | "require-dev": { 34 | "symfony/framework-bundle": "^7.0", 35 | "symfony/phpunit-bridge": "^7.0", 36 | "symfony/twig-bundle": "^7.0", 37 | "symfony/var-dumper": "^7.0", 38 | "phpunit/phpunit": "^11.5" 39 | }, 40 | "conflict": { 41 | "symfony/flex": "<1.13" 42 | }, 43 | "extra": { 44 | "thanks": { 45 | "name": "symfony/ux", 46 | "url": "https://github.com/symfony/ux" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /docs/action-columns.md: -------------------------------------------------------------------------------- 1 | # Action columns 2 | 3 | The `ActionColumn` class allows you to define a custom action column for your DataTables instance using the UX DataTables library. 4 | 5 | ## Overview 6 | 7 | `ActionColumn` is an implementation of the `ColumnInterface` designed for representing actions (such as delete) inside a DataTable. 8 | It provides a convenient way to add buttons or links that perform specific operations on each row. 9 | > **Note**: The ActionColumn relies on the presence of an id column in the dataset. 10 | > This id is used to execute the action (e.g., deletion) by identifying the corresponding row and sending it to the actionUrl. 11 | 12 | --- 13 | 14 | ## Usage 15 | 16 | ```php 17 | use Pentiminax\UX\DataTables\Model\ActionColumn; 18 | use Pentiminax\UX\DataTables\Enum\Action; 19 | 20 | $deleteColumn = ActionColumn::new( 21 | name: 'delete', 22 | title: 'Delete', 23 | action: Action::DELETE, 24 | actionLabel: 'Delete', 25 | actionUrl: '/api/resource/delete' 26 | ); 27 | ``` 28 | 29 | --- 30 | 31 | ## Attributes 32 | 33 | | Property | Type | Description | 34 | | ------------- |----------| ---------------------------------------------- | 35 | | `name` | `string` | Internal identifier for the column. | 36 | | `title` | `string` | Displayed column header title. | 37 | | `action` | `enum` | Type of action (`DELETE`, etc.). | 38 | | `actionLabel` | `string` | Text displayed inside the action button. | 39 | | `actionUrl` | `string` | Endpoint to call when the action is triggered. | -------------------------------------------------------------------------------- /docs/ajax.md: -------------------------------------------------------------------------------- 1 | # Ajax 2 | 3 | ## Introduction 4 | 5 | The `ajax` option in the UX DataTables library allows dynamic loading of table data from an external source via an HTTP request. This feature is particularly useful for handling large datasets without overloading the browser. 6 | 7 | ## Using with Symfony 8 | 9 | You can configure data loading using the `AjaxOption` class. Here’s how to use this option with a `DataTable` instance: 10 | 11 | ```php 12 | use Pentiminax\UX\DataTables\Model\DataTable; 13 | use Pentiminax\UX\DataTables\Model\Options\AjaxOption; 14 | 15 | class MyTableService 16 | { 17 | public function createTable(): DataTable 18 | { 19 | $dataTable = new DataTable('example_table'); 20 | 21 | $ajaxOption = new AjaxOption( 22 | url: '/api/data', // API endpoint to fetch data 23 | dataSrc: 'data', // Key in the JSON response containing the data (optional) 24 | type: 'POST' // HTTP method used (default is GET) 25 | ); 26 | 27 | $dataTable->ajax($ajaxOption); 28 | 29 | return $dataTable; 30 | } 31 | } 32 | ``` 33 | 34 | ## Expected JSON Response Format 35 | 36 | The server should return a JSON response containing the data under the key defined in `dataSrc` (default is `data`). Here is an example of a correct response: 37 | 38 | ```json 39 | { 40 | "data": [ 41 | { "id": 1, "name": "Product A", "price": 10.5 }, 42 | { "id": 2, "name": "Product B", "price": 20.0 } 43 | ], 44 | "recordsTotal": 100, 45 | "recordsFiltered": 100 46 | } 47 | ``` 48 | 49 | - `data`: Array containing the records to display. 50 | - `recordsTotal`: Total number of records in the database. 51 | - `recordsFiltered`: Total number of records after filtering. 52 | 53 | ### Important: Mapping Columns to JSON Keys 54 | 55 | In order for DataTables to correctly populate columns from the JSON response, you must explicitly define the data key for each column using one of the following methods: 56 | 57 | - **`setData(string $data): self`**: Sets the data source for the column. 58 | 59 | ```php 60 | Column::new('name', 'Name') 61 | ->setData('name'); 62 | ``` 63 | 64 | - Or set the fourth argument of Column::new() to true to use the column name as the data source automatically: 65 | 66 | ```php 67 | Column::new('name', 'Name', ColumnType::STRING, useNameAsDataSource: true); 68 | ``` 69 | 70 | If neither setData() nor $useNameAsDataSource = true is used, the column will not be mapped to a value in the JSON response. 71 | 72 | ### Using the Helper to Format JSON Response 73 | 74 | To ensure the correct response format, you can use the `DataTableResponseBuilder` helper: 75 | 76 | ```php 77 | use Pentiminax\UX\DataTables\Builder\DataTableResponseBuilder; 78 | 79 | $responseBuilder = new DataTableResponseBuilder(); 80 | 81 | $response = $responseBuilder->buildResponse( 82 | draw: 1, 83 | data: $data, 84 | recordsTotal: $totalRecords, 85 | recordsFiltered: $filteredRecords 86 | ); 87 | 88 | return $response; 89 | ``` 90 | 91 | ### Error Handling 92 | 93 | If the server returns an error, ensure that the JSON response format contains an explicit structure to handle the error on the client side. 94 | 95 | Example of an error response: 96 | 97 | ```json 98 | { 99 | "error": "An error occurred while loading the data." 100 | } 101 | ``` 102 | 103 | On the frontend, you can intercept these errors and display an appropriate message to the user. 104 | 105 | --- 106 | 107 | By properly configuring the `ajax` option, you can significantly improve the performance and user experience of your data tables in Symfony. 108 | 109 | -------------------------------------------------------------------------------- /docs/columns.md: -------------------------------------------------------------------------------- 1 | # Columns 2 | 3 | ## Introduction 4 | 5 | In the UX DataTables library, the `Column` class allows for precise definition and configuration of table columns. Each column can be customized in terms of type, visibility, sorting, searching, and more. 6 | 7 | ## Creating a Column 8 | 9 | To create a new column, use the static `new` method of the `Column` class: 10 | 11 | ```php 12 | use Pentiminax\UX\DataTables\Model\Column; 13 | use Pentiminax\UX\DataTables\Enum\ColumnType; 14 | 15 | $column = Column::new('firstName', 'First Name', ColumnType::STRING); 16 | ``` 17 | 18 | Here, `'firstName'` is the internal name of the column, `'First Name'` is the title displayed in the table header, and `ColumnType::STRING` defines the data type of the column. 19 | 20 | ## Available Properties 21 | 22 | The `Column` class provides several methods to configure column properties: 23 | 24 | - **`setClassName(string $className): self`**: Sets the CSS class name to be applied to the column cells. 25 | - **`setCellType(string $cellType): self`**: Specifies the cell type (`'td'` or `'th'`) to use for the column. 26 | - **`setData(string $data): self`**: Sets the data source for the column. 27 | - **`setOrderable(bool $orderable): self`**: Enables or disables sorting on this column. 28 | - **`setSearchable(bool $searchable): self`**: Enables or disables searching on this column. 29 | - **`setVisible(bool $visible): self`**: Determines whether the column is visible or not. 30 | - **`setWidth(string $width): self`**: Specifies the column width (e.g., `'100px'`, `'10%'`). 31 | 32 | ## Example Usage with DataTable 33 | 34 | Here's how to integrate columns into a `DataTable` instance: 35 | 36 | ```php 37 | use Pentiminax\UX\DataTables\Builder\DataTableBuilderInterface; 38 | use Pentiminax\UX\DataTables\Model\Column; 39 | use Pentiminax\UX\DataTables\Enum\ColumnType; 40 | 41 | class MyTableService 42 | { 43 | public function __construct( 44 | private DataTableBuilderInterface $builder, 45 | ) { 46 | } 47 | 48 | public function createDataTable(): DataTable 49 | { 50 | $dataTable = $this->builder->createDataTable('example_table'); 51 | 52 | $nameColumn = Column::new('name', 'Name', ColumnType::STRING) 53 | ->setClassName('col-name') 54 | ->setOrderable(true) 55 | ->setSearchable(true); 56 | 57 | $ageColumn = Column::new('age', 'Age', ColumnType::NUM) 58 | ->setWidth('50px') 59 | ->setOrderable(true) 60 | ->setSearchable(false); 61 | 62 | $dataTable->add($nameColumn); 63 | $dataTable->add($ageColumn); 64 | 65 | return $dataTable; 66 | } 67 | } 68 | ``` 69 | 70 | In this example, we create a table with two columns: one for the name and one for the age, each with specific configurations. 71 | 72 | ## Column Types 73 | 74 | The library provides several column types through the `ColumnType` enumeration: 75 | 76 | - **`ColumnType::DATE`**: For dates. 77 | - **`ColumnType::NUM`**: For numbers. 78 | - **`ColumnType::NUM_FMT`**: For formatted numbers. 79 | - **`ColumnType::HTML`**: For HTML content. 80 | - **`ColumnType::STRING`**: For string values. 81 | 82 | The choice of column type influences sorting and searching behavior for that column. 83 | 84 | ## Converting to an Array 85 | 86 | To retrieve the column configuration as an array (for example, for JSON serialization), use the `toArray` method: 87 | 88 | ```php 89 | $configColumn = $nameColumn->toArray(); 90 | ``` 91 | 92 | This method returns an associative array representing the column's properties, ready to be used in DataTables configuration options. 93 | 94 | --- 95 | 96 | By properly configuring columns using the `Column` class, you can customize the behavior and appearance of your tables to meet the specific needs of your Symfony application. 97 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # DataTables Configuration 2 | 3 | To configure the default DataTables options, you can define them in the configuration file `config/packages/datatables.yaml` as shown below: 4 | 5 | ```yaml 6 | data_tables: 7 | options: 8 | language: en-GB 9 | lengthMenu: [10, 25, 50] 10 | pageLength: 10 11 | template_parameters: 12 | class: 'table' 13 | extensions: 14 | buttons: [csv, excel, pdf, print] 15 | select: 16 | style: single 17 | ``` 18 | 19 | # Explanation of the options: 20 | 21 | **language**: This section allows you to customize the language settings for DataTables. You can specify translations for various elements such as "processing", "lengthMenu", "zeroRecords", etc. In the example, the language is set to English. 22 | 23 | **lengthMenu**: An array of values representing the number of rows to display per page. In this example, users can choose from 10, 25, or 50 rows per page. 24 | 25 | **pageLength**: The initial number of rows to display per page. In the example above, it is set to 10. 26 | 27 | **template_parameters**: An array of parameters to pass to the DataTables template. In this example, the class attribute is set to "table". 28 | 29 | - **class**: The CSS class to apply to the generated DataTables table. 30 | 31 | **extensions**: An array defining additional extensions for DataTables. 32 | 33 | - **select**: Configuration for the select extension. 34 | - **style**: Defines the selection style. In this case, it is set to "single". Can be "single" or "multi". 35 | 36 | These options allow you to customize the DataTables behavior directly from your configuration file. 37 | 38 | -------------------------------------------------------------------------------- /docs/extensions.md: -------------------------------------------------------------------------------- 1 | # Extensions 2 | 3 | The DataTables library comes with a number of useful extensions. 4 | 5 | ## Buttons 6 | 7 | The Buttons extension provides additional export and interaction options for DataTables, such as copying data, exporting to different formats (CSV, Excel, PDF), and printing. 8 | 9 | You can have more information about the Buttons extension [here](https://datatables.net/extensions/buttons/). 10 | 11 | ### Usage 12 | 13 | To enable the Buttons extension, instantiate `ButtonsExtension` with the desired button types and add it to your DataTable: 14 | 15 | ```php 16 | $buttonsExtension = new ButtonsExtension([ 17 | ButtonType::COPY, 18 | ButtonType::CSV, 19 | ButtonType::EXCEL, 20 | ButtonType::PDF, 21 | ButtonType::PRINT 22 | ]); 23 | 24 | $datatable = new DataTable('example'); 25 | $datatable->extensions([$buttonsExtension]); 26 | ``` 27 | 28 | ### Button Types 29 | 30 | The available button types are defined in the `ButtonType` enum: 31 | 32 | ```php 33 | enum ButtonType: string 34 | { 35 | case COPY = 'copy'; 36 | case CSV = 'csv'; 37 | case EXCEL = 'excel'; 38 | case PDF = 'pdf'; 39 | case PRINT = 'print'; 40 | } 41 | ``` 42 | 43 | ## Select 44 | 45 | Select adds item selection capabilities to a DataTable. Items can be rows, columns, or cells, which can be selected independently or together. 46 | 47 | You can have more information about the Select extension [here](https://datatables.net/extensions/select/). 48 | 49 | ### Usage 50 | 51 | To enable the Select extension, instantiate `SelectExtension` and add it to your DataTable: 52 | 53 | ```php 54 | $selectExtension = new SelectExtension(); 55 | $datatable = new DataTable('example'); 56 | $datatable->extensions([$selectExtension]); 57 | ``` 58 | 59 | You can also specify a selection style: 60 | 61 | ```php 62 | $selectExtension = new SelectExtension(SelectStyle::MULTI); 63 | $datatable = new DataTable('example'); 64 | $datatable->extensions([$selectExtension]); 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Before you start, make sure you have [StimulusBundle configured in your 4 | app](https://symfony.com/bundles/StimulusBundle/current/index.html). 5 | 6 | Install the bundle using Composer and Symfony Flex: 7 | 8 | ``` terminal 9 | $ composer require pentiminax/ux-datatables 10 | ``` 11 | 12 | If you\'re using WebpackEncore, install your assets and restart Encore 13 | (not needed if you\'re using AssetMapper): 14 | 15 | ``` terminal 16 | $ npm install --force 17 | $ npm run watch 18 | 19 | # or use yarn 20 | $ yarn install --force 21 | $ yarn watch 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/options.md: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | This document describes all available options for configuring your DataTable instance. 4 | 5 | ## Basic Configuration 6 | 7 | ### autoWidth 8 | Controls DataTables' smart column width handling. 9 | ```php 10 | $dataTable->autoWidth(bool $autoWidth) 11 | ``` 12 | 13 | ### caption 14 | Sets a caption for the table. 15 | ```php 16 | $dataTable->caption(string $caption) 17 | ``` 18 | 19 | ### order 20 | Sets the initial order (sort) to apply to the table. 21 | ```php 22 | $dataTable->order(array $order) 23 | ``` 24 | The order array can contain: 25 | - An array with [column_index, direction] 26 | - An object with {idx: number, dir: 'asc'|'desc'} 27 | - An object with {name: string, dir: 'asc'|'desc'} 28 | 29 | ## Data Loading 30 | 31 | ### ajax 32 | Loads data for the table's content from an Ajax source. 33 | ```php 34 | $dataTable->ajax(AjaxOptions $ajaxOption) 35 | ``` 36 | 37 | ### data 38 | Sets the display data for the table directly. 39 | ```php 40 | $dataTable->data(array $data) 41 | ``` 42 | 43 | ## Features Control 44 | 45 | ### deferRender 46 | Controls deferred rendering for additional speed of initialization. 47 | ```php 48 | $dataTable->deferRender(bool $deferRender) 49 | ``` 50 | 51 | ### info 52 | Controls the table information display field. 53 | ```php 54 | $dataTable->info(bool $info) 55 | ``` 56 | 57 | ### lengthChange 58 | Controls the end user's ability to change the paging display length. 59 | ```php 60 | $dataTable->lengthChange(bool $lengthChange) 61 | ``` 62 | 63 | ### ordering 64 | Controls sorting abilities in DataTables. 65 | ```php 66 | $dataTable->ordering(bool $ordering) 67 | ``` 68 | 69 | ### paging 70 | Enables or disables table pagination. 71 | ```php 72 | $dataTable->paging(bool $paging) 73 | ``` 74 | 75 | ### processing 76 | Controls the processing indicator display. 77 | ```php 78 | $dataTable->processing(bool $processing) 79 | ``` 80 | 81 | ### searching 82 | Controls search (filtering) abilities. 83 | ```php 84 | $dataTable->searching(bool $searching) 85 | ``` 86 | 87 | ### serverSide 88 | Enables server-side processing mode. 89 | ```php 90 | $dataTable->serverSide(bool $serverSide) 91 | ``` 92 | 93 | ### stateSave 94 | Enables state saving - allows the table to restore its state when reloaded. 95 | ```php 96 | $dataTable->stateSave(bool $stateSave) 97 | ``` 98 | 99 | ## Scrolling Options 100 | 101 | ### scrollX 102 | Enables horizontal scrolling. 103 | ```php 104 | $dataTable->scrollX(bool $scrollX) 105 | ``` 106 | 107 | ### scrollY 108 | Enables vertical scrolling with a fixed height. 109 | ```php 110 | $dataTable->scrollY(string $scrollY) 111 | ``` 112 | 113 | ## Pagination 114 | 115 | ### displayStart 116 | Defines the starting point for data display when using pagination. 117 | ```php 118 | $dataTable->displayStart(int $displayStart) 119 | ``` 120 | 121 | ## Initial search 122 | 123 | ### search 124 | Sets the initial search value for the table. 125 | ```php 126 | $dataTable->search(string $search) 127 | ``` 128 | 129 | ## Internationalisation 130 | 131 | ### language 132 | 133 | Sets the language options for DataTables. 134 | ```php 135 | $dataTable->language(Langage $language) 136 | ``` 137 | 138 | ### layout 139 | 140 | Sets the layout options for DataTables. 141 | ```php 142 | $dataTable->layout( 143 | new LayoutOption( 144 | topStart: Feature::PAGE_LENGTH, 145 | topEnd: Feature::SEARCH, 146 | bottomStart: Feature::INFO, 147 | bottomEnd: Feature::PAGING, 148 | ) 149 | ); 150 | ``` 151 | 152 | ## Example Usage 153 | 154 | ```php 155 | use Pentiminax\UX\DataTables\Model\DataTable; 156 | use Pentiminax\UX\DataTables\Model\Options\AjaxOption; 157 | 158 | $dataTable = new DataTable('example_table'); 159 | 160 | $dataTable 161 | ->autoWidth(true) 162 | ->caption('My Table') 163 | ->ordering(true) 164 | ->paging(true) 165 | ->searching(true) 166 | ->serverSide(false) 167 | ->scrollY('300px') 168 | ->ajax(new AjaxOption( 169 | url: '/api/data', 170 | dataSrc: 'data', 171 | type: 'POST' 172 | )); 173 | ``` 174 | 175 | This example creates a DataTable with common options configured, including Ajax data loading, scrolling, and basic features enabled. 176 | 177 | ## Styling DataTables 178 | 179 | In your ``assets/controllers.json`` file, you should see a line that automatically 180 | includes a CSS file for DataTables which will give you basic styles. 181 | 182 | If you're using Bootstrap, set ``datatables.net-dt/css/dataTables.dataTables.min.css`` to false 183 | and ``datatables.net-bs5/css/dataTables.bootstrap5.min.css`` to true: 184 | 185 | ```json 186 | { 187 | "autoimport": { 188 | "datatables.net-dt/css/dataTables.dataTables.min.css": false, 189 | "datatables.net-bs5/css/dataTables.bootstrap5.min.css": true 190 | } 191 | } 192 | ``` -------------------------------------------------------------------------------- /docs/usage.md: -------------------------------------------------------------------------------- 1 | 2 | # Usage 3 | 4 | To use UX DataTables, inject the `DataTableBuilderInterface` service and 5 | create tables in PHP: 6 | 7 | ``` php 8 | // ... 9 | use Pentiminax\UX\DataTables\Builder\DataTableBuilderInterface; 10 | use Pentiminax\UX\DataTables\Model\DataTable; 11 | use Pentiminax\UX\DataTables\Model\Column; 12 | 13 | class HomeController extends AbstractController 14 | { 15 | #[Route('/', name: 'app_homepage')] 16 | public function index(DataTableBuilderInterface $builder): Response 17 | { 18 | $table = $builder 19 | ->createDataTable('usersTable') 20 | ->columns([ 21 | Column::new('firstName', 'First name'), 22 | Column::new('lastName', 'Last name'), 23 | ]) 24 | ->data([ 25 | ['John', 'Doe'], 26 | ['Jane', 'Smith'], 27 | ]); 28 | 29 | return $this->render('home/index.html.twig', [ 30 | 'table' => $table, 31 | ]); 32 | } 33 | } 34 | ``` 35 | 36 | All options and data are provided as-is to DataTables. You can read 37 | [DataTables documentation](https://datatables.net/manual/) to discover 38 | them all. 39 | 40 | Once created in PHP, a table can be displayed using Twig: 41 | 42 | ``` html+twig 43 | {{ render_datatable(table) }} 44 | 45 | {# You can pass HTML attributes as a second argument to add them on the