Symfony Bundle to create HTML tables with bootstrap-table for Doctrine Entities.

Overview

HelloBootstrapTableBundle

This Bundle provides simple bootstrap-table configuration for your Doctrine Entities.

Used bootstrap-table version 1.18.3.

Inspired by SgDatatablesBundle and omines/datatables-bundle

Overview

  1. Features
  2. Installation
  3. Your First Table
  4. Columns
    1. TextColumn
    2. BooleanColumn
    3. DateTimeColumn
    4. HiddenColumn
    5. LinkColumn
    6. CountColumn
    7. ActionColumn
  5. Filters
    1. TextFilter
    2. ChoiceFilter
    3. BooleanChoiceFilter
    4. CountFilter
  6. Configuration
    1. Table Dataset Options
    2. Table Options
  7. Common Use-Cases
    1. Custom Doctrine Queries
    2. Detail View
    3. Use Icons as action buttons
  8. Contributing

Features

  • Create bootstrap-tables in PHP
  • Twig render function
  • global filtering (server side)
  • column based filtering (advanced search)
  • column sorting (server side)
  • Pagination (service side)
  • different column types
  • bootstrap-table extensions

Installation

Step 1: Download the Bundle

Open a command console, enter your project directory and execute the following command to download this bundle:

$ composer require hello-sebastian/hello-bootstrap-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:

// config/bundles.php

return [
    // ...
    HelloSebastian\HelloBootstrapTableBundle\HelloBootstrapTableBundle::class => ['all' => true],
];

Step 3: Assetic Configuration

Install the web assets

# if possible, make absolute symlinks (best practice) in public/ if not, make a hard copy

$ php bin/console assets:install --symlink

Add Assets into your base.html.twig

CSS:

{{ hello_bootstrap_table_css() }}">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">


{{ hello_bootstrap_table_css() }}

JavaScript:

{{ hello_bootstrap_table_js() }}">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js">script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js">script>


{{ hello_bootstrap_table_js() }}

You can also use other CSS frameworks. See the bootstrap-table documentation for more information.


Your First Table

Step 1: Create a Table class

add('username', TextColumn::class) ->add('email', TextColumn::class, array( 'title' => 'E-Mail', 'visible' => false )) ->add('firstName', TextColumn::class, array( 'title' => 'First name' )) ->add('lastName', TextColumn::class, array( 'title' => 'Last name' )) ->add('createdAt', DateTimeColumn::class, array( 'title' => 'Created at' )) ->add('department.name', TextColumn::class, array( 'title' => 'Department', 'emptyData' => 'No Department', 'addIf' => function() { // In this callback it is decided if the column will be rendered. return $this->security->isGranted('ROLE_DEPARTMENT_VIEWER'); } )) ->add("isActive", BooleanColumn::class, array( 'title' => 'is active', 'trueLabel' => 'yes', 'falseLabel' => 'no' )) ->add('department.costCentre.name', TextColumn::class, array( 'title' => 'Cost Centre', 'data' => function (User $user) { return "#" . $user->getDepartment()->getCostCentre()->getName(); } )) ->add("actions", ActionColumn::class, array( 'title' => 'Actions', 'width' => 150, 'buttons' => array( //see ActionButton for more examples. array( 'displayName' => 'open', 'routeName' => 'show_user', 'classNames' => 'btn btn-xs' 'additionalClassNames' => 'btn-success mr-1' ), array( 'displayName' => 'edit', 'routeName' => 'edit_user', 'classNames' => 'btn btn-xs btn-warning', 'addIf' => function(User $user) { // In this callback it is decided if the button will be rendered. return $this->security->isGranted('ROLE_USER_EDITOR'); } ) ) )); } protected function getEntityClass() { return User::class; } }">
// src/HelloTable/UserTable.php



namespace App\HelloTable;

use App\Entity\User; // your entity class ...
use HelloSebastian\HelloBootstrapTableBundle\Columns\ColumnBuilder;
use HelloSebastian\HelloBootstrapTableBundle\Columns\TextColumn;
use HelloSebastian\HelloBootstrapTableBundle\Columns\DateTimeColumn;
use HelloSebastian\HelloBootstrapTableBundle\Columns\HiddenColumn;
use HelloSebastian\HelloBootstrapTableBundle\Columns\ActionColumn;
use HelloSebastian\HelloBootstrapTableBundle\Columns\BooleanColumn;
use HelloSebastian\HelloBootstrapTableBundle\HelloBootstrapTable;

class UserTable extends HelloBootstrapTable
{
  
    protected function buildColumns(ColumnBuilder $builder, $options)
    {
        $builder
            ->add("id", HiddenColumn::class)
            ->add('username', TextColumn::class)
            ->add('email', TextColumn::class, array(
                'title' => 'E-Mail',
                'visible' => false
            ))
            ->add('firstName', TextColumn::class, array(
                'title' => 'First name'
            ))
            ->add('lastName', TextColumn::class, array(
                'title' => 'Last name'
            ))
            ->add('createdAt', DateTimeColumn::class, array(
                'title' => 'Created at'
            ))
            ->add('department.name', TextColumn::class, array(
                'title' => 'Department',
                'emptyData' => 'No Department',
                'addIf' => function() {
                    // In this callback it is decided if the column will be rendered.
                    return $this->security->isGranted('ROLE_DEPARTMENT_VIEWER');
                }
            ))
            ->add("isActive", BooleanColumn::class, array(
                'title' => 'is active',
                'trueLabel' => 'yes',
                'falseLabel' => 'no'
            ))
            ->add('department.costCentre.name', TextColumn::class, array(
                'title' => 'Cost Centre',
                'data' => function (User $user) {
                    return "#" . $user->getDepartment()->getCostCentre()->getName();
                }
            ))
            ->add("actions", ActionColumn::class, array(
                'title' => 'Actions',
                'width' => 150,
                'buttons' => array( //see ActionButton for more examples.
                    array(
                        'displayName' => 'open',
                        'routeName' => 'show_user',
                        'classNames' => 'btn btn-xs' 
                        'additionalClassNames' => 'btn-success mr-1'
                    ),
                    array(
                        'displayName' => 'edit',
                        'routeName' => 'edit_user',
                        'classNames' => 'btn btn-xs btn-warning',
                        'addIf' => function(User $user) {
                            // In this callback it is decided if the button will be rendered.
                            return $this->security->isGranted('ROLE_USER_EDITOR');
                        }
                    )
                )
            ));
    }

    protected function getEntityClass()
    {
        return User::class;
    }
}

Step 2: In the Controller

create(UserTable::class); $table->handleRequest($request); if ($table->isCallback()) { return $table->getResponse(); } return $this->render('index.html.twig', array( 'table' => $table->createView() )); }">
// src/Controller/UserController.php

use HelloSebastian\HelloBootstrapTableBundle\HelloBootstrapTableFactory;
use App\HelloTable\UserTable;
// ...

/**
 * @Route("/", name="default")
 */
public function index(Request $request, HelloBootstrapTableFactory $tableFactory) : Response
{
    $table = $tableFactory->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

{# index.html.twig #}

{% extends 'base.html.twig' %}

{% block body %}
    {{ hello_bootstrap_table_render(table) }}
{% endblock %}

The Twig function will render a table with all attributes configured.


Columns

TextColumn

Represents column with text. With formatter you can create complex columns.

Options from bootstrap-table

The following options were taken from bootstrap-table. For more information about the options, see the bootstrap-table documentation: https://bootstrap-table.com/docs/api/column-options/

Option Type Default Description
title string / null null Set column title. If no value is set, the specified attribute name is taken.
field string / null null Set internal field name for bootstrap-table. If no value is set, the specified attribute name is taken.
width integer / null null column width in px
widthUnit string "px" Unit of width.
class string / null null The column class name.
formatter string / null null JavaScript function name for formatter. (see formatter)
footerFormatter string / null null JavaScript function name for footer formatter.
searchable bool true enable / disable filtering for this column
sortable bool true enable / disable sortable for this column
switchable bool true enable / disable interactive hide and show of column.
visible bool true show / hide column
align string / null null Indicate how to align the column data. 'left', 'right', 'center' can be used.
halign string / null null Indicate how to align the table header. 'left', 'right', 'center' can be used.
valign string / null null Indicate how to align the cell data. 'top', 'middle', 'bottom' can be used.
falign string / null null Indicate how to align the table footer. 'left', 'right', 'center' can be used.
filterControl string "input" render text field in column header
titleTooltip string / null null add tooltip to header

Options from HelloBootstrapTable

The following options are not included in bootstrap-table. They were added separately.

Option Type Default Description
emptyData string "" default value if attribute from entity is null
filter array [TextFilter::class, array()] Set filter to column (see Filters)
addIf Closure function() {return true;} In this callback it is decided if the column will be rendered.
data Closure / null null custom data callback (see example)
sort Closure / null null custom sort query callback (see example)
search Closure / null null custom search query callback (see example)

Example

function (User $user) { //entity from getEntityClass //you can return what ever you want ... return $user->getId() . " " . $user->getUsername(); }, 'sort' => function (QueryBuilder $qb, $direction) { //execute if user sort this column $qb->addOrderBy('username', $direction); }, 'search' => function (Composite $composite, QueryBuilder $qb, $search) { //first add condition to $composite //don't forget the ':' before the parameter for binding $composite->add($qb->expr()->like($dql, ':username')); //then bind search to query $qb->setParameter("username", $search . '%'); } ))">
//use statements for search and sort option
use Doctrine\ORM\Query\Expr\Composite;
use Doctrine\ORM\QueryBuilder;

->add('username', TextColumn::class, array(
  'title' => 'Username',
  'emptyData' => "No Username found.",
  
  //optional overrides ...
  'data' => function (User $user) { //entity from getEntityClass
      //you can return what ever you want ...  
      return $user->getId() . " " . $user->getUsername();
  },

  'sort' => function (QueryBuilder $qb, $direction) { //execute if user sort this column
      $qb->addOrderBy('username', $direction);
  },

  'search' => function (Composite $composite, QueryBuilder $qb, $search) {
    	//first add condition to $composite
      //don't forget the ':' before the parameter for binding
      $composite->add($qb->expr()->like($dql, ':username'));
    
    	//then bind search to query
      $qb->setParameter("username", $search . '%');
  }
))

search Option:

Paramenter name Description
Composite $composite In the global search all columns are connected as or. In the advanced search all columns are combined with an and-connection. With $composite more parts can be added to the query. Composite is the parent class of AndX and OrX.
QueryBuilder $qb $qb holds the use QueryBuilder. It is the same instance as can be queried with getQueryBuilder() in the table class.
$search The search in the type of a string.

BooleanColumn

Represents column with boolean values.

Options

All options of TextColumn.

advancedSearchType is set to checkbox by default.

filter is set to array(BooelanChoiceFilter::class, array()) by default.

And:

Option Type Default Description
allLabel string "All" label for "null" values
trueLabel string "True" label for true values
falseLabel string "False" label for false values

Example

use HelloSebastian\HelloBootstrapTableBundle\Columns\BooleanColumn;

->add('isActive', BooleanColumn::class, array(
    'title' => '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

use HelloSebastian\HelloBootstrapTableBundle\Columns\DateTimeColumn;

->add('createdAt', DateTimeColumn::class, array(
    'title' => 'Created at',
    'format' => 'd.m.Y'
))

HiddenColumn

Represents column that are not visible in the table. Can used for data which are required for other columns.

Options

All Options of TextColumn.

searchable, sortable, visible and switchable are disabled by default.

Example

use HelloSebastian\HelloBootstrapTableBundle\Columns\HiddenColumn;

->add("id", HiddenColumn::class)

LinkColumn

Represents column with a link.

Options

All Options of TextColumn.

formatter is set to defaultLinkFormatter.

And:

Option Type Default Description
routeName string null Route name. This option is required.
routeParams array [] Array of route parameters. The key is the parameter of the route. The value is the property path.
attr array [ ] Array of any number of attributes formatted as HTML attributes. The array ["class" => "btn btn-success"] is formatted as class="btn btn-success".

Example

use HelloSebastian\HelloBootstrapTableBundle\Columns\LinkColumn;

->add('department.name', LinkColumn::class, array(
    'title' => 'Department',
    'routeName' => 'show_department', // this option is required
    'routeParams' => array(
        'id' => 'department.id' // "id" is the route parameter of "show_department". "department.id" is the property path to fetch the value for the route parameter.
    )
))

If the route parameters cannot be determined automatically based on the entity, user-defined routes can be created by overwriting data. Once data is overwritten, routeName and routeParams are no longer necessary to specify.

use HelloSebastian\HelloBootstrapTableBundle\Columns\LinkColumn;

->add('department.name', LinkColumn::class, array(
    'title' => 'Department',
    'data' => function (User $user) {
        return array(
            'displayName' => $user->getDepartment()->getName(),
            'route' => $this->router->generate('show_department', array('some_parameter' => 'Hello'),
            'attr' => ''
        );
    }
))

CountColumn

Represents column for counting OneToMany relations (for ArrayCollection attributes).

Only works with direct attributes so far. For example, "users" would work in a DepartmentTable, but "users.items" would not.

Options

All Options of TextColumn.

filter is set to array(CountFilter::class, array()) by default.

Example

add('users', CountColumn::class, array( 'title' => 'Users' ))">
// App\Entity\Department.php

/**
 * @var ArrayCollection|User[]
 * @ORM\OneToMany(targetEntity="App\Entity\User", mappedBy="department")
 */
private $users;


// App\HelloTable\UserTable.php
use HelloSebastian\HelloBootstrapTableBundle\Columns\CountColumn;

->add('users', CountColumn::class, array(
    'title' => 'Users'
))

ActionColumn

Represents column for action buttons (show / edit / remove ...).

Options

All Options of TextColumn

sortable, searchable and switchable are disable by default.

formatter is set to defaultActionFormatter.

And:

Option Type Default Description
buttons array [ ] array of buttons configuration as array.

Example

'Actions', 'width' => 120, //optional 'buttons' => array( array( 'displayName' => 'show', 'routeName' => 'show_user', 'additionalClassNames' => 'btn-success', 'attr' => array( 'title' => 'Show', // any number of other attributes ) ), array( 'displayName' => 'edit', 'routeName' => 'edit_user', // 'classNames' => 'btn btn-xs' (see below for more information) 'additionalClassNames' => 'btn-warning', 'addIf' => function(User $user) { // you can use your entity in the function // In this callback it is decided if the button will be rendered. return $this->security->isGranted('ROLE_ADMIN'); } ) ) ))">
->add("actions", ActionColumn::class, array( // key "actions" can be chosen freely but must be unique in the table
    'title' => 'Actions',
    'width' => 120, //optional
    'buttons' => array(
        array(
            'displayName' => 'show',
            'routeName' => 'show_user',
            'additionalClassNames' => 'btn-success',
            'attr' => array(
                'title' => 'Show',
                // any number of other attributes
            )
        ),
        array(
            'displayName' => 'edit',
            'routeName' => 'edit_user',
            // 'classNames' => 'btn btn-xs' (see below for more information)
            'additionalClassNames' => 'btn-warning',
            'addIf' => function(User $user) { // you can use your entity in the function
                // In this callback it is decided if the button will be rendered.
                return $this->security->isGranted('ROLE_ADMIN');
            }
       )
  	)
))

ActionButtons

Option Type Default Description
displayName string "" label of button
routeName string "" route name
routeParams 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.
attr array [ ] Array of any number of attributes formatted as HTML attributes. The array ["title" => "Show"] is formatted as title="Show". The href and class attributes are created by the other options and should not be defined here.
addIf Closure function($entity) {return true;} In this callback it is decided if the button will be rendered.

YAML Example

# config/packages/hello_table.yaml

hello_bootstrap_table:
    action_button_options:
        classNames: 'btn btn-xs'

YAML config options are set to all buttons. If you want override global options from YAML config use classNames option.


Filters

Filters can be used to generate predefined queries. In addition, different input fields for the filters are displayed (currently only under the Advanced Search).


TextFilter

With the TextFilter you can filter by text within the column. TextFilter is set by default to all columns.

Options

Option Type Default Description
advSearchFieldFormatter string "defaultAdvSearchTextField" Set JavaScript function name to format input field.
placeholder string / null title option from column with " ..." Set HTML placeholder for input field.

If you want to change advSearchFieldFormatter, you also need to create a JavaScript function with the same name in the window scope. As an example here is the default function:

`; };">
//value can be undefined
window.defaultAdvSearchTextField = function (field, filterOptions, value) {
    let val = value || "";
    return `${val}" class="form-control" name="${field}" placeholder="${filterOptions.placeholder}" id="${field}">`;
};

Example

use HelloSebastian\HelloBootstrapTableBundle\Filters\TextFilter;

->add('firstName', TextColumn::class, array(
    'title' => 'First name',
    'filter' => array(TextFilter::class, array(
        'placeholder' => 'Enter first name ...'
    ))
))

ChoiceFilter

With the ChoiceFilter you can create a select input field.

Options

All Options from TextFilter.

advSearchFieldFormatter is set to defaultAdvSearchChoiceField.

And:

Option Type Default Description
choices array [ ] Key - Values pair of choices. Key: value attribute of select field; Value: display name of options in select field.
selectedValue string | int "null" Default selected value when table is rendered.

Example

use HelloSebastian\HelloBootstrapTableBundle\Filters\ChoiceFilter;

->add('department.name', TextColumn::class, array(
    'title' => 'Department',
    'filter' => array(ChoiceFilter::class, array(
        'choices' => array(
            'null' => 'All', //null is special key word. If 'null' is set QueryBuilder skip this column.
            'IT' => 'IT',
            'Sales' => 'Sales'
        )
    ))
))

BooleanChoiceFilter

BooleanChoiceFilter is a special ChoiceFilter with default choices and query expression. The expression is optimized for boolean values.

Options

All Options from ChoiceFilter.

If you use BooleanChoiceFilter inside a BooleanColumn, the allLabel, trueLabel and falseLabel options from BooleanColumn are taken for null, true and false for the choices option by default.

If not choices is set to:

array( "null" => "All", // key must be "null", if you want allow to show all results "true" => "True", // key must be "true", if you want allow true "false" => "False" // key must be "false", if you want allow false )">
"choices" => array(
    "null" => "All",    // key must be "null", if you want allow to show all results
    "true" => "True",   // key must be "true", if you want allow true
    "false" => "False"  // key must be "false", if you want allow false
)

Example

'is active', 'filter' => array(BooleanChoiceFilter::class, array( // only if you want to override the choices 'choices' => array( "null" => "Alle", // instead of "all" "true" => "Ja", // instead of "yes" "false" => "Nein" // instead of "no" ) )), 'trueLabel' => 'yes', 'falseLabel' => 'no' ))">
->add("isActive", BooleanColumn::class, array(
    'title' => 'is active',
  	'filter' => array(BooleanChoiceFilter::class, array( // only if you want to override the choices
        'choices' => array(
            "null" => "Alle",   // instead of "all"
            "true" => "Ja",     // instead of "yes"
            "false" => "Nein"   // instead of "no"
        )
    )),
    'trueLabel' => 'yes',
    'falseLabel' => 'no'
))

CountFilter

With the CountFilter you can filtering and sorting by counting OneToMany relations.

Options

All Options from TextFilter.

And:

Option Type Default Description
condition string "gte" Operation to compare counting.
Available options: "gt", "gte", "eq", "neq", "lt", "lte"
primaryKey string "id" Primary key of the target entity in the OneToMany relation.
For example: A user is in one deparment. One department has many users. In the user entity there is a $department attribute that is pointing to the department entity. With this option you specify the primary key of the department entity (the target entity).

Example

use HelloSebastian\HelloBootstrapTableBundle\Filters\CountFilter;

->add('users', CountColumn::class, array(
    'title' => 'Users',
    'filter' => array(CountFilter::class, array(
        'condition' => 'lte',
        'primaryKey' => 'uuid'
    ))
))

Configuration

Table Dataset Options

Table Dataset are provided directly to the bootstrap-table as data-attributes and are a collection of setting options for the table. For more information check bootstrap-table documentation: https://bootstrap-table.com/docs/api/table-options/

Options

Option Type Default
pagination bool true
search bool true
show-columns bool true
show-columns-toggle-all bool false
show-footer bool true
filter-control bool true
show-refresh bool true
toolbar string "#toolbar"
page-list string "[10, 25, 50, 100, 200, 500, All]"
page-size int 25
sort-reset bool true
pagination-V-Align string "both"
undefined-text string ""
locale string "en-US"
advanced-search bool false
id-table string class name of table. ($this->getTableName())
icons-prefix string "fa"
icons array see under table*
click-to-select bool true
show-jump-to bool true
show-export bool true
export-types string "['csv', 'txt'', 'excel']"
export-options array see under table*
detail-view bool false
detail-formatter string ""
detail-view-align string ""
detail-view-icon bool true
detail-view-by-click bool false
sticky-header bool true
sticky-header-offset-left int 0
sticky-header-offset-right int 0
sticky-header-offset-y int 0
checkbox-header bool true
escape bool false
height int / null null
multiple-select-row bool false
sort-name string / null null
sort-order string / null null

icons:

Option Type Default
advancedSearchIcon string "fa-filter"
paginationSwitchDown string "fa-caret-square-o-down"
paginationSwitchUp string "fa-caret-square-o-up"
columns string "fa-columns"
refresh string "fa-sync"
export string "fa-download"
detailOpen string "fa-plus"
detailClose string "fa-minus"
toggleOff string "fa-toggle-off"
toggleOn string "fa-toggle-on"
fullscreen string "fa-arrows-alt"
search string "fa-search"
clearSearch string "fa-trash"

export-options:

';' )">
array(
    'fileName' => (new \DateTime('now'))->format('Y-m-d_H-i-s') . '_export',
    'ignoreColumn' => array("checkbox", "actions"),
    'csvSeparator' => ';'
)

Examples

Inside from Table class:

// src/HelloTable/UserTable.php

class UserTable extends HelloBootstrapTable
{
    ...
      
    protected function buildColumns(ColumnBuilder $builder, $options)
    {
        $this->setTableDataset(array(
            'locale' => 'de-DE'
        ));
      
      	// ... $builder->add()
    }
}

Outside from Table class:

// src/Controller/UserController.php

public function index(Request $request, HelloBootstrapTableFactory $tableFactory) : Response
{
    $table = $tableFactory->create(UserTable::class);

    // other options will be merged.
    $table->setTableDataset(array(
        'locale' => 'de-DE'
    ));

    // ...
}

YAML config:

YAML config options are set to all tables. If you want override global options from YAML config use setTableDataset method in or outside from HelloBootstrapTable.

# config/packages/hello_table.yaml

hello_bootstrap_table:
    table_dataset_options:
        locale: 'de-DE' # see Table Dataset Options

Table Options

All options that should not be provided directly as data-attributes of the table are managed here.

Options

Option Type Default
tableClassNames string "table table-stripped table-sm"
enableCheckbox bool false
bulkIdentifier string "id"
bulkUrl string ""
bulkActionSelectClassNames string "form-control"
bulkActions array [ ]
bulkButtonName string "Okay"
bulkButtonClassNames string "btn btn-primary"

Examples

Inside from Table class:

// src/HelloTable/UserTable.php

class UserTable extends HelloBootstrapTable
{
    ...

    protected function buildColumns(ColumnBuilder $builder, $options)
    {
        $this->setTableOptions(array(
            'enableCheckbox' => false
        ));
      
      	// ... $builder->add()
    }
}

Outside from Table class:

// src/Controller/UserController.php

public function index(Request $request, HelloBootstrapTableFactory $tableFactory) : Response
{
    $table = $tableFactory->create(UserTable::class);

    $table->setTableOptions(array(
        'enableCheckbox' => false
    ));

    // ...
}

YAML config:

YAML config options are set to all tables. If you want override global options from YAML config use setTableDataset method in or outside from HelloBootstrapTable.

# config/packages/hello_table.yaml

hello_bootstrap_table:
    table_options:
        enableCheckbox: false # see Table Options

Common Use-Cases

Custom Doctrine Queries

Sometimes you don't want to display all the data in a database table. For this you can "prefilter" the Doctrine query.

Example

create(TestTable::class); //then you can access the QueryBuilder from the table $table->getQueryBuilder() ->andWhere('department.name = :departmentName') ->setParameter('departmentName', 'IT'); $table->handleRequest($request); if ($table->isCallback()) { return $table->getResponse(); } return $this->render("index.html.twig", array( "table" => $table->createView() )); }">
/**
  * @Route("/", name="default")
  */
public function index(Request $request, HelloBootstrapTableFactory $tableFactory)
{
    //first create a instance of your table
    $table = $tableFactory->create(TestTable::class);

    //then you can access the QueryBuilder from the table
    $table->getQueryBuilder()
        ->andWhere('department.name = :departmentName')
        ->setParameter('departmentName', 'IT');

    $table->handleRequest($request);
    if ($table->isCallback()) {
      	return $table->getResponse();
    }

    return $this->render("index.html.twig", array(
      	"table" => $table->createView()
    ));
}

Default table sorting

bootstrap-table allows you to specify a default sort order. For this purpose there are two options "sort-name" and "sort-order". These can be set by the setTableDataset method. "sort-name" expects the dql (or if set field name) of the column. "sort-order" can be set by "asc" or "desc".

// inside table class
protected function buildColumns(ColumnBuilder $builder, $options)
{
    $this->setTableDataset(array(
        'sort-name' => 'firstName', // dql (or if set field name) of column
        'sort-order' => 'desc' // or asc
    ));

    $builder->add('firstName', TextColumn::class, array(
        'title' => 'First name'
    ));
}

// outside table class
$table = $tableFactory->create(UserTable::class);
$table->setTableDataset(array(
    'sort-name' => 'firstName',
    'sort-order' => 'desc'
));

HelloBootstrapTable provides a helper method setDefaultSorting to set the default sort order.

add('firstName', TextColumn::class, array( 'title' => 'First name' )); } // outside table class $table = $tableFactory->create(UserTable::class); $table->setDefaultSorting("firstName", "desc"); ">
// inside table class
protected function buildColumns(ColumnBuilder $builder, $options)
{
    $this->setDefaultSorting("firstName", "desc");

    $builder->add('firstName', TextColumn::class, array(
        'title' => 'First name'
    ));
}

// outside table class
$table = $tableFactory->create(UserTable::class);
$table->setDefaultSorting("firstName", "desc");

Detail View

You can expand rows in bootstrap-table. This option is called "detail view" and can be enabled in the datasets (by default this is disabled). For displaying the content of detail-view a formatter is needed (also to be specified in datasets). In the formatter you have access to the data of the table row. For complex representations Twig can also be used. See the example below.

 protected function buildColumns(ColumnBuilder $builder, $options)
 {
     //enable detail-view and set formatter
     $this->setTableDataset(array(
         'detail-view' => true,
         'detail-formatter' => 'detailViewFormatter'
     ));

     $builder
       // other columns ...
       
       // detailView is not a database field and can be named as you like.
       // but the column should not displayed in the table (HiddenColumn)
       ->add('detailView', HiddenColumn::class, array(
           // override data callback (as attribute you can access the entity that you specified in getEntityClass())
           'data' => function (User $user) {
              // now you can return everthing you want (twig render included)
              // twig is provided by HelloBootstrapTable
              return $this->twig->render('user/detail_view.html.twig', array(
                 'user' => $user
              ));
           }
       ));
}

To display detailView as content of the expanded table row a formatter function must be created and detailView must be returned. Remember to create the formatter before calling {{ hello_bootstrap_table_js() }}.

// index   => index of row inside table
// row     => data object of the row
// element => row DOM element
window.detailViewFormatter = function (index, row, element) {
    // detailView matched with the name from add('detailView', HiddenColumn::class). If you use a different name you must changed it here too.
    return row.detailView;
};

Alternative you can of course create your HTML with JavaScript inside the formatter.


Use Icons as action buttons

To save space in the table, it makes sense to use icons instead of written out buttons. This is easily possible by using HTML instead of a word in the displayName option of the action buttons.

'Actions', 'buttons' => array( array( 'displayName' => "", // <-- e.g. FontAwesome icon 'routeName' => 'show_user', 'additionalClassNames' => 'btn-success', ), // more buttons ... ) )); } }">
// src/HelloTable/UserTable.php

class UserTable extends HelloBootstrapTable
{
    // ...

    protected function buildColumns(ColumnBuilder $builder, $options)
    {
      	$builder
            // more columns ...
            ->add("actions", ActionColumn::class, array(
                'title' => 'Actions',
                'buttons' => array(
                    array(
                        'displayName' => "", // <-- e.g. FontAwesome icon
                        'routeName' => 'show_user',
                        'additionalClassNames' => 'btn-success',
                    ),
                    // more buttons ...
                )
            ));
    }
}

Contributing

Contributions are welcome and will be credited.

Comments
  • Default table sorting

    Default table sorting

    Hello, Is there a way to sort a table by default on a given column? I've looked at all the options, but I can't find how to do this.

    If I do this in my controller, my table is not sortable anymore :

    $table->getQueryBuilder()
                ->addOrderBy("field", "desc");
    

    Thanks

    opened by SwyZeOff 9
  • Add

    Add "AddIf" options

    • Add "syfmony/security-bundle" to dependencies
    • Add "AddIf" option to columns
    • Add "AddIf" option to action buttons
    • Add .php-version with version 7.4
    opened by HelloSebastian 1
  • Add option to DateTimeColumn

    Add option to DateTimeColumn "disableKeydownEvent"

    Add Option disableKeydownEvent to DateTimeColumn.

    This options prevent keyboard input to input field. Only useful when filterControl is set to datetime (because of date picker)

    opened by HelloSebastian 0
  • Add parameter types and return types

    Add parameter types and return types

    In this update, missing parameter types and return types to all internal and external functions have been added.

    Also fixed a bug with the new enableTotalCountCache option. (see #34)

    Breaking Changes: Missing types were also added to the methods in the table classes. Among them, the methods buildColumns, getEntityClass, configureTableDataset and configureTableOptions are affected.

    buildColumns - before:

    protected function buildColumns(ColumnBuilder $builder, $options) { }
    

    after:

    protected function buildColumns(ColumnBuilder $builder, array $options): void { }
    

    getEntityClass - before:

    protected function getEntityClass() { }
    

    after:

    protected function getEntityClass(): string { }
    

    configureTableDataset - before:

    public function configureTableDataset(OptionsResolver $resolver) { }
    

    after:

    public function configureTableDataset(OptionsResolver $resolver): void { }
    

    configureTableOptions - before:

    public function configureTableOptions(OptionsResolver $resolver) { }
    

    after:

    public function configureTableOptions(OptionsResolver $resolver): void { }
    
    opened by HelloSebastian 0
  • Add total count cache options

    Add total count cache options

    When large and complex tables are built over multiple entities and have several 100k records, the initial count of the total amount of records takes a very long time. This is most likely due to the LEFT JOINS.

    With the option enableTotalCountCache the result of the count can now be cached.

    opened by HelloSebastian 0
  • fix filter control and search

    fix filter control and search

    If filter control and and the global search are active, the value of the global search "search" is set when entering a column filtering.

    This was already fixed in bootstrap-table in 2019, but the extension "cookie" sets the value again. Therefore, the extension cookie is deactivated for now. Compare https://github.com/wenzhixin/bootstrap-table/issues/3966

    opened by HelloSebastian 0
  • fix LinkColumn

    fix LinkColumn

    This fix resolves a bug in LinkColumn. The option "routeParams" was changed so that the key represents the route parameter. The Value specifies the property path for the value of the route parameters.

    The ReadMe file has also been modified accordingly.

    opened by HelloSebastian 0
  • add entity to addIf function for action buttons

    add entity to addIf function for action buttons

    Before:

    'addIf' => function () {
        return true;
    }
    

    After:

    'addIf' => function ($entity) {
        return true;
    }
    

    Example

    // UserTable
    'addIf' => function (User $user) {
        return $user->isActive();
    }
    

    No changing break. Old function call still works.

    opened by HelloSebastian 0
  • Add icons options to HelloBootstrapTable

    Add icons options to HelloBootstrapTable

    • Add "icons" option to HelloBootstrapTable
    • Add "icons" option to Configuration
    • Add "child" OptionResolver to "icons"
    • Update Readme
    • Rebuild assets
    opened by HelloSebastian 0
  • Add Count column

    Add Count column

    Add CountColumn to provide a solution to display counts of OneToMany relations. CountColumn provide filter and sort functions and display the count of OneToMany relations in the table.

    In this PR the column option search callback function interface was changed.

    Before: 'search' => function (Composite $composite, QueryBuilder $qb, $dql, $search, $key) {}

    After: 'search' => function (Composite $composite, QueryBuilder $qb, $search) {}

    In the table you know the attribute name of the column. Therefore, the $dql parameter is no longer needed.

    The $key parameter is used to uniquely bind the search parameters in the query. In the callback function you can provide a unique name for the search parameters yourself.

    opened by HelloSebastian 0
  • Symfony >= 5.4 remove deprecations

    Symfony >= 5.4 remove deprecations

    Hello, Could you please remove the deprecation and ensure compatibility with Symfony >= 5.4?

    Method "Symfony\Component\Config\Definition\ConfigurationInterface::getConfigTreeBuilder()" might add "TreeBuilder" as a native return type declaration in the future. Do the same in implementation "HelloSebastian\HelloBootstrapTableBundle\DependencyInjection\Configuration" now to avoid errors or add an explicit @return annotation to suppress this message.

    opened by funmobi 1
  • Update data-url using Jquery

    Update data-url using Jquery

    Hello,

    Is there a way to update the data-url using JQuery ? I tried something like this,

    var datatableCanva = $('.hello-bootstrap-table');
    var url = datatableCanva.data('url');
    var newUrl = url + '?' + form.serialize();
    datatableCanva.bootstrapTable('refreshOptions', {
        url: newUrl
    });
    

    It made a call to the URI but didn't update the data-url of the table !

    thanks

    opened by manaka02 2
  • using advanced search or external field

    using advanced search or external field

    Hello, First, really thanks for your works ! I'm new on it and on Boostrap table ! I want to create a custom filter (using multiple field with checkbox, dateInterval , ....). My question is, if I have a form, how can I pass all the value to the datatable, and how can I refresh the table manually !

    Cheers !

    opened by manaka02 2
Releases(v0.8.1)
  • v0.8.1(Aug 17, 2022)

  • v0.8.0(May 16, 2022)

  • v0.7.0(Nov 7, 2021)

    • ADD: LinkColumn (#21)
    • ADD: Choice filter option (#20)
    • ADD: More table dataset and column options (#24)
    • ADD: allLabel option for select field filter (#20)
    • CHANGED: filter-control to true and advanced-search to false by default (#22)
    • FIX: ActionColumn CSS issues (#22)
    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Oct 10, 2021)

    • ADD: icons-prefix option and sets to "fa" (#14)
    • ADD: AddIf option to columns and action buttons (#16)
    • ADD: Add attr option to action buttons (#16)
    • ADD: Add CountColumn (#17)
    • FIX: Replaced Exception with LogicExceptions (#15)
    • FIX: Move icons option inside HelloBootstrapTable (#18)
    • FIX: filter control select field template (#19)
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(May 21, 2021)

    • ADD: bulk identifier to improve bulk actions (#9)
    • FIX: Rename button in advanced filter modal (#10)
    • ADD: Detail view options (#11)
    • ADD: Twig to HelloBootstrapTable to render templates (#12)
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Mar 28, 2021)

  • v0.3.1(Feb 10, 2021)

    • ADD: hello_bootstrap_table_css() and hello_bootstrap_table_js() Twig function to fix caching problem
    • FIX: Global Search (ignore BooleanChoiceFilter)
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Feb 1, 2021)

  • v0.2.0(Jan 27, 2021)

Owner
Sebastian B
Sebastian B
A set of PHP scripts which leverage MySQL INFORMATION_SCHEMA to create log tables and insert / update triggers

mysql-logtable-php mysql-logtable-php is a set of PHP scripts which leverage MySQL INFORMATION_SCHEMA to create log tables and insert / update trigger

null 3 Feb 27, 2022
Pageon Doctrine Data Grid Bundle

Pageon Doctrine Data Grid Bundle A bundle that wraps around the knp paginator bundle and doctrine to generate a data grid from your entity Documentati

null 1 Dec 14, 2021
A bundle to handle encoding and decoding of parameters using OpenSSL and Doctrine lifecycle events.

SpecShaper Encrypt Bundle A bundle to handle encoding and decoding of parameters using OpenSSL and Doctrine lifecycle events. Features include: Master

Mark Ogilvie 48 Nov 4, 2022
Sanitize untrustworthy HTML user input (Symfony integration for https://github.com/tgalopin/html-sanitizer)

html-sanitizer is a library aiming at handling, cleaning and sanitizing HTML sent by external users (who you cannot trust), allowing you to store it and display it safely. It has sensible defaults to provide a great developer experience while still being entierely configurable.

Titouan Galopin 86 Oct 5, 2022
A plugin that adds worker entities to minecraft.

WorkersDemo A plugin that adds worker entities to minecraft. Workers does things that players does such as mining wood/stone etc. How to use? You can

Oğuzhan 6 Dec 17, 2021
TYPO3 CMS extension which extends TYPO3 page cache, by tags based on entities used in fluid templates.

Fluid Page Cache for TYPO3 CMS This TYPO3 CMS extension allows you to clear frontend page caches, automatically when a displayed record has been updat

Armin Vieweg 1 Apr 8, 2022
A smart way of seeding tables in Laravel

SmartSeeder for Laravel For Laravel 5, please use the 5.0 branch! For Laravel 4, please use the 4.2 branch! Seeding as it is currently done in Laravel

Jordan Lapp 190 Oct 6, 2022
BetterWPDB - Keeps you safe and sane when working with custom tables in WordPress.

BetterWPDB - Keeps you safe and sane when working with custom tables in WordPress.

Snicco 21 Dec 15, 2022
Tables migrations seeded with data according to the Algerian education system structure.

Laravel algerian education system structure If you are building a Learning Management System or a School Management System and targeting the Algerian

Elaborate Code 12 Oct 8, 2022
A Symfony Feature Flag Bundle which easily allows you to configure and use your favorite feature flag provider.

Metro Markets FF Metro Markets FF is a Feature Flag Symfony Bundle. It easily allows you to configure and use your favorite feature flag provider. Ins

METRO Markets 14 May 23, 2022
A Symfony bundle built to schedule/consume repetitive tasks

Daily runs Code style Infection PHPUnit Rector Security Static analysis A Symfony bundle built to schedule/consume repetitive tasks Main features Exte

Guillaume Loulier 98 Jan 4, 2023
Tabler.io bundle for Symfony - a backend/admin theme for easy integration

Tabler Bundle for Symfony This repository contains a Symfony bundle, integrating the fantastic Tabler.io HTML Template into your Symfony project. It s

Kevin Papst 22 Jan 2, 2023
Symfony bundle for class/method memoization

Symfony service memoization bundle This bundle provides memoization for your services - every time you call the same method with the same arguments a

Dominik Chrástecký 16 Oct 31, 2022
A Symfony2 bundle that integrates Select2 as a drop-in replacement for a standard entity field on a Symfony form.

select2entity-bundle Introduction This is a Symfony bundle which enables the popular Select2 component to be used as a drop-in replacement for a stand

Ross Keatinge 214 Nov 21, 2022
Laravel style FormRequests for Symfony; inspired by adamsafr/form-request-bundle

Somnambulist Form Request Bundle An implementation of form requests from Laravel for Symfony based on the original work by Adam Sapraliev. Requirement

Somnambulist Tech 1 Dec 14, 2021
RSQueue Bundle for Symfony

RSQueueBundle for Symfony Simple queuing system based on Redis Table of contents Installing/Configuring Tags Installing Redis Installing PHPRedis Inst

RSQueue 11 Oct 8, 2018
🕧 Provides an scheduler bundle for symfony framework.

?? PHP Scheduler Bundle Provides the integration of the PHP Scheduler library into Symfony Framework. Installation Run composer require flexic/schedul

FlexicSystems 3 Nov 15, 2022
Formulário de contato utilizando HTML, CSS, Bootstrap, PHP, Javascript e conexão ao banco de dados MySQL.

Formulário de Contato Tecnologias | Projeto | Licença | ?? Tecnologias Esse projeto foi desenvolvido com as seguintes tecnologias: HTML CSS PHP JavaSc

Douglas Duarte 3 Feb 10, 2022
First SQL Project - HTML, Bootstrap, PHP enabling CRUD from web

DB-Project First SQL Project with HTML, Bootstrap, PHP enabling CRUD from web Java for mocking data, enabling .csv input Idea This model corresponds t

null 2 Jun 16, 2022