https://github.com/hellosebastian/react-table-bundle
Symfony Bundle for React Table configuration in PHP.
https://github.com/hellosebastian/react-table-bundle
bundle react-table symfony
Last synced: 3 months ago
JSON representation
Symfony Bundle for React Table configuration in PHP.
- Host: GitHub
- URL: https://github.com/hellosebastian/react-table-bundle
- Owner: HelloSebastian
- License: mit
- Created: 2020-12-20T17:49:18.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2021-01-12T16:53:26.000Z (about 5 years ago)
- Last Synced: 2025-07-05T22:01:55.878Z (7 months ago)
- Topics: bundle, react-table, symfony
- Language: PHP
- Homepage:
- Size: 912 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ReactTableBundle
**This Bundle provides *simple* [react-table](https://github.com/tannerlinsley/react-table/tree/v6) configuration for your Doctrine Entities.** With the option to create your own columns in JavaScript.
ReactTableBundle uses React Table v6. (React Table v7 is headless, means no CSS and layout. I'm not a CSS expert,
so I'm still using v6 at the moment. Once a flex layout for v7 is ready, the bundle can be easily adapted, since the
API for the columns is very similar.)
Highly inspired by [SgDatatablesBundle](https://github.com/stwe/DatatablesBundle).
**The project is currently still under development. It can not be excluded that configuration changes.**
## When should I not use ReactTableBundle
ReactTableBundle is designed for simple tables that are strongly bound to the entities. If you are creating highly customized tables with many components and a lot of client-side programming, ReactTableBundle is not suitable for that. However, you can of course use ReactTableBundle alongside your complex tables.
## Overview
1. [Features](#features)
2. [Installation](#installation)
3. [Your First Table](#your-first-table)
4. [Columns](#columns)
5. [Table Props Configuration](#table-props)
6. [Persistence Options Configuration](#persistence-options)
## Features
* Table Configuration in PHP
* Filtering*
* Sorting*
* Pagination*
* Persist table state (sorting, filtering, current page, ...) in cookies
* Column Types: [TextColumn](#textcolumn), [BooleanColumn](#booleancolumn), [DateTimeColumn](#datetimecolumn), [ActionColumn](#actioncolumn)
* Custom Columns with [OwnColumn](#owncolumn)
*server-side
## Installation
### Step 1: Download the Bundle
Open a command console, enter your project directory and execute the following command to download this bundle:
``` bash
$ composer require hello-sebastian/react-table-bundle
```
### Step 2: Enable the Bundle (without flex)
Then, enable the bundle by adding it to the list of registered bundles in the `config/bundles.php` file of your project:
``` php
// config/bundles.php
return [
// ...
HelloSebastian\ReactTableBundle\ReactTableBundle::class => ['all' => true],
];
```
### Step 3: Assetic Configuration
#### Install the web assets
``` bash
# if possible, make absolute symlinks (best practice) in public/ if not, make a hard copy
$ php bin/console assets:install --symlink
```
``` bash
# make a hard copy of assets in public/
$ php bin/console assets:install
```
#### Add Assets into your base.html.twig
``` html
```
## Your First Table
### Step 1: Create a ReactTable class
``` php
// src/ReactTable/UserTable.php
add('username', TextColumn::class, array(
'Header' => 'Username'
))
->add('email', TextColumn::class, array(
'Header' => 'E-Mail',
'show' => false
))
->add('firstName', TextColumn::class, array(
'Header' => 'First name'
))
->add('lastName', TextColumn::class, array(
'Header' => 'Last name'
))
->add('createdAt', DateTimeColumn::class, array(
'Header' => 'Created at',
'format' => 'd.m.Y'
))
->add('department.name', TextColumn::class, array(
'Header' => 'Department',
'emptyData' => 'No Department',
'filter' => array(SelectFilter::class, array(
'choices' => array(
'IT' => 'IT',
'Sales' => 'Sales'
)
))
))
->add('department.costCentre.name', TextColumn::class, array(
'Header' => 'Cost Centre',
'emptyData' => 'No Cost Centre',
'filter' => array(SelectFilter::class, array(
'choices' => array(
'001' => '001',
'002' => '002',
'null' => 'empty'
)
))
))
->add('isActive', BooleanColumn::class, array(
'Header' => 'is active',
'trueValue' => 'yes'
))
->add(null, ActionColumn::class, array(
'Header' => 'Actions',
'width' => 120,
'buttons' => array(
array(
'displayName' => 'show',
'routeName' => 'show_user',
'additionalClassNames' => 'btn-success'
),
array(
'displayName' => 'edit',
'routeName' => 'edit_user'
)
)
));
}
protected function getEntityClass(): string
{
return User::class;
}
}
```
### Step 2: In the Controller
``` php
// src/Controller/UserController.php
// ...
use HelloSebastian\ReactTableBundle\ReactTableFactory;
// ...
/**
* @Route("/", name="default")
*/
public function index(Request $request, ReactTableFactory $reactTableFactory) : Response
{
$table = $reactTableFactory->create(UserTable::class);
$table->handleRequest($request);
if ($table->isCallback()) {
return $table->getResponse();
}
return $this->render('index.html.twig', array(
'table' => $table->createView()
));
}
```
### Step 3: Add table in Template
``` html
{% extends 'base.html.twig' %}
{% block body %}
{% endblock %}
```
## Columns
### TextColumn
Represents column with text.
#### Options
| Option | Type | Default | Description |
| --------------- | -------------- | ---------------------------- | ------------------------------------------------------------ |
| Header | string | "" | set colum header |
| width | integer / null | null | width in px for column |
| filterable | bool | true | enable / disable filtering for this column |
| sortable | bool | true | enable / disable sortable for this column |
| resizable | bool | true | enable / disable resizable for this column |
| show | bool | true | show / hide column |
| className | string | "" | set the classname of the `td` element of the column |
| headerClassName | string | "" | set the classname of the `th` element of the column |
| footerClassName | string | "" | set the classname of the `td` element of the column's footer |
| filter | array / null | [TextFilter::class, array()] | first element in array is a filter class, second element is a configuration array for the filter class (see Filters) |
| emptyData | string | "" | default value if attribute from entity is null |
| sortQuery | Closure / null | null | custom sort query |
| dataCallback | Closure / null | null | custom data callback |
#### Example
```php
->add('username', TextColumn::class, array(
'Header' => 'Username',
'emptyData' => "No Username found.",
//optional overrides ...
'dataCallback' => function (User $user) { //entity class from getEntityClass
//you can return what ever you want ... but only string or number
return $user->getId() . " " . $user->getUsername();
},
'sortQuery' => function (QueryBuilder $qb, $direction) {
$qb->addOrderBy('username', $direction);
},
'filter' => array(TextFilter::class, array(
'placeholder' => 'Search ...',
'filterQuery' => function (QueryBuilder $qb, $field, $value) {
//add custom expressions to QueryBuilder ...
//field = "username"
//value = text from filter
}
))
))
```
### BooleanColumn
Represents column with boolean values.
#### Options
All options of TextColumn
The option `filter` is set to `SelectFilter` by default.
**And**:
| Option | Type | Default | Description |
| ---------- | ------ | ------- | ---------------------- |
| trueLabel | string | "True" | label for true values |
| falseLabel | string | "False" | label for false values |
#### Example
```php
->add('isActive', BooleanColumn::class, array(
'Header' => 'is active',
'trueLabel' => 'yes',
'falseLabel' => 'no'
))
```
### DateTimeColumn
Represents column with DateType values.
#### Options
All Options of TextColumn
**And:**
| Option | Type | Default | Description |
| ------ | ------ | ------------- | ---------------------- |
| format | string | "Y-m-d H:i:s" | DateTime format string |
#### Example
```php
->add('createdAt', DateTimeColumn::class, array(
'Header' => 'Created at',
'format' => 'd.m.Y'
))
```
### OwnColumn
With OwnColumn you can provided custom data und JavaScript configuration to the table. E.g. you can create a Image or Link column with OwnColumn.
#### Options
All Options of TextColumn.
`sortable` and `filterable` are disabled by default. If you want to enable that you must provide custom `sortQuery` and `filter` with `filterQuery`.
`dataCallback` is required.
#### Example
**Table configuration in PHP**
```php
->add("custom", OwnColumn::class, array(
'Header' => 'My Column',
'dataCallback' => function (User $user) {
return "Hello";
},
'sortQuery' => function (QueryBuilder $qb, $direction) {
}
))
```
**Extend table configuration in JavaScript**
In your `base.html.twig` **before** you include the bundle JS file you can listen to the custom event `rtb:componentDidMount`. Inside the event you can access the array of JavaScript column objects.
```javascript
document.addEventListener("rtb:componentDidMount", function (e) {
e.detail.persistenceOptions.filtered = false; //see Persistence Options
//loop over all columns and filter by type "own". If you have multiply OwnColumns you must extend the filtering
//Then you can set and access all provided attributes by react-table. E.g. React Cell, Footer, Header, Filter - components ...
e.detail.columns.forEach(col => {
if (col.type === "own") {
col.Header = "Custom Column";
col.show = true;
col.Cell = (row) => { //row is provided by react-table
//if you import React you can render a customer component here as well.
// return ;
return row.original.username;
}
}
});
});
```
### ActionColumn
Represents column for action buttons (show / edit / remove ...).
#### Options
All Options of TextColumn
`sortable` and `filterable` are disable by default.
**And:**
| Option | Type | Default | Description |
| ------- | ----- | ------- | ---------------------------------------- |
| buttons | array | [] | array of buttons configuration as array. |
#### Example
```php
->add(null, ActionColumn::class, array(
'Header' => 'Actions',
'width' => 120, //optional
'buttons' => array(
array(
'displayName' => 'show',
'routeName' => 'show_user',
'additionalClassNames' => 'btn-success'
),
array(
'displayName' => 'edit',
'routeName' => 'edit_user',
'additionalClassNames' => 'btn-success'
)
)
))
```
#### ActionButtons
| Option | Type | Default | Description |
| -------------------- | ------ | ----------- | ------------------------------------------------------------ |
| displayName | string | "" | label of button in table |
| routeName | string | "" | route name |
| routeParams | array | array("id") | Array of property value names for the route parameters. By default is `id` set. |
| classNames | string | "" | CSS class names which added directly to the `a` element. Overrides default class names from YAML config. |
| additionalClassNames | string | "" | You can set default class names in YAML config. Then you can add additional class names to the button without override the default config. |
**YAML Config**
```yaml
# config/packages/react_table.yaml
react_table:
# other configuration ...
default_column_options:
action_column:
default_class_names: 'btn btn-xs'
```
## Configuration
### Table Props
Table Props are provided directly to ReactTable and are a collection of setting options for the table.
#### Options
| Option | Type | Default |
|-------------------------------|---------|--------------------------|
| showPagination | bool | true |
| showPaginationTop | bool | false |
| showPaginationBottom | bool | true |
| showPageSizeOptions | bool | true |
| pageSizeOptions | array | [5, 10, 20, 25, 50, 100] |
| defaultPageSize | int | 20 |
| showPageJump | bool | true |
| collapseOnSortingChange | bool | true |
| collapseOnPageChange | bool | true |
| collapseOnDataChange | bool | true |
| freezeWhenExpanded | bool | false |
| sortable | bool | true |
| multiSort | bool | true |
| resizable | bool | true |
| filterable | bool | true |
| defaultSortDesc | bool | false |
| className | string | '' |
| previousText | string | 'Previous' |
| nextText | string | 'Next' |
| loadingText | string | 'Loading...' |
| noDataText | string | 'No rows found' |
| pageText | string | 'Page' |
| ofText | string | 'of' |
| rowsText | string | 'Rows' |
| pageJumpText | string | 'jump to page' |
| rowsSelectorText | string | 'rows per page' |
You can either perform settings for all tables via a YAML file or set each individual table
#### YAML-Configuration
```yaml
// config/packages/react_table.yaml
react_table:
default_table_props:
className: "-striped -highlight"
sortable: false
```
#### PHP-Configuration
Inside from Table class:
``` php
// src/ReactTable/UserTable.php
class UserTable extends ReactTable
{
...
public function configureTableProps(OptionsResolver $resolver)
{
parent::configureTableProps($resolver);
$resolver->setDefaults(array(
'defaultPageSize' => 10
));
}
}
```
Outside from Table class:
``` php
// src/Controller/UserController.php
public function index(Request $request, ReactTableFactory $reactTableFactory) : Response
{
$table = $reactTableFactory->create(UserTable::class);
$table->setTableProps(array(
'defaultPageSize' => 10
));
...
}
```
In the `configureTableProps` method, you can specify custom data that can be provided directly to the ReactTable.
### Persistence Options
#### Options
With the Persistence Options you can set which settings (filtering, sorting, current page, ...) should be stored in the cookies. By default, all of them are activated.
| Option | Type | Default |
|----------------|---------|----------|
| resized | bool | true |
| filtered | bool | true |
| sorted | bool | true |
| page | bool | true |
| page_size | bool | true |
#### YAML-Configuration
```yaml
// config/packages/react_table.yaml
react_table:
default_persistence_options:
sorted: true
```
#### PHP-Configuration
Inside from Table class:
``` php
// src/ReactTable/UserTable.php
class UserTable extends ReactTable
{
...
public function configurePersistenceOptions(OptionsResolver $resolver)
{
parent::configurePersistenceOptions($resolver);
$resolver->setDefaults(array(
'sorted' => false
));
}
}
```
Outside from Table class:
``` php
// src/Controller/UserController.php
public function index(Request $request, ReactTableFactory $reactTableFactory) : Response
{
$table = $reactTableFactory->create(UserTable::class);
$table->setPersistenceOptions(array(
'page' => true
));
...
}
```
## ToDo's
* Documentation
* More Examples
* Twig extension to render `div` element
* Tests
* Unit Tests