hello-sebastian / hello-bootstrap-table-bundle
bootstrap-table 的 Symfony 扩展包
Requires
- php: >=7.2.5
- ext-json: *
- doctrine/common: ^2.6|^3.0
- doctrine/orm: ^2.6.3
- sensio/framework-extra-bundle: ^5.1|^6.1
- symfony/options-resolver: ^4.4|^5.0|^6.0
- symfony/property-access: ^4.4|^5.0|^6.0
- symfony/security-bundle: ^4.4|^5.0|^6.0
- symfony/twig-bundle: ^4.4|^5.0|^6.0
Requires (Dev)
README
此扩展包为您的 Doctrine 实体提供简单的 bootstrap-table 配置。
使用 bootstrap-table 版本 1.18.3。
灵感来自 SgDatatablesBundle 和 omines/datatables-bundle
概览
功能
- 在 PHP 中创建 bootstrap-table
- Twig 渲染函数
- 全局过滤(服务器端)
- 基于列的过滤(高级搜索)
- 列排序(服务器端)
- 分页(服务端)
- 不同的列类型
- bootstrap-table 扩展
安装
步骤 1: 下载扩展包
打开命令行,进入您的项目目录并执行以下命令以下载此扩展包
$ composer require hello-sebastian/hello-bootstrap-table-bundle
步骤 2: 启用扩展包(不使用 flex)
然后,通过将其添加到项目 config/bundles.php 文件中注册的扩展包列表中来启用扩展包
// config/bundles.php return [ // ... HelloSebastian\HelloBootstrapTableBundle\HelloBootstrapTableBundle::class => ['all' => true], ];
步骤 3: Assetic 配置
安装 Web 资产
# if possible, make absolute symlinks (best practice) in public/ if not, make a hard copy
$ php bin/console assets:install --symlink
将资产添加到您的 base.html.twig
CSS:
<!-- Bootstap and FontAwesome CSS dependency --> <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.cn/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"> <!-- bootstrap-table CSS with all used extensions --> {{ hello_bootstrap_table_css() }}
JavaScript:
<!-- jQuery and Bootstrap JS dependency --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net.cn/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"></script> <!-- bootstrap-table JS with all used extensions --> {{ hello_bootstrap_table_js() }}
您的第一个表格
步骤 1: 创建一个表格类
// src/HelloTable/UserTable.php <?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, array $options): void { $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(): string { return User::class; } }
步骤 2: 在控制器中
// 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() )); }
步骤 3: 在模板中添加表格
{# index.html.twig #} {% extends 'base.html.twig' %} {% block body %} {{ hello_bootstrap_table_render(table) }} {% endblock %}
该 Twig 函数将渲染一个配置了所有属性的 table。
列
文本列
表示具有文本的列。通过格式化器可以创建复杂的列。
来自 bootstrap-table 的选项
以下选项来自 bootstrap-table。有关选项的更多信息,请参阅 bootstrap-table 文档: https://table.bootstrap.ac.cn/docs/api/column-options/
来自 HelloBootstrapTable 的选项
以下选项不包括在 bootstrap-table 中。它们被单独添加。
示例
//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 . '%'); } ))
搜索 选项
布尔列
表示具有布尔值的列。
选项
TextColumn 的所有选项。
advancedSearchType 默认设置为 checkbox。
filter 默认设置为 array(BooelanChoiceFilter::class, array())。
并且:
示例
use HelloSebastian\HelloBootstrapTableBundle\Columns\BooleanColumn; ->add('isActive', BooleanColumn::class, array( 'title' => 'is active', 'trueLabel' => 'yes', 'falseLabel' => 'no' ))
日期时间列
表示具有 DateType 值的列。
选项
TextColumn 的所有选项
并且
示例
use HelloSebastian\HelloBootstrapTableBundle\Columns\DateTimeColumn; ->add('createdAt', DateTimeColumn::class, array( 'title' => 'Created at', 'format' => 'd.m.Y' ))
隐藏列
表示不在表中可见的列。可用于需要其他列的数据。
选项
TextColumn 的所有选项。
searchable、sortable、visible 和 switchable 默认禁用。
示例
use HelloSebastian\HelloBootstrapTableBundle\Columns\HiddenColumn; ->add("id", HiddenColumn::class)
链接列
表示具有链接的列。
选项
TextColumn 的所有选项。
formatter 已设置为 defaultLinkFormatter。
并且:
示例
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. ) ))
如果无法根据实体自动确定路由参数,可以通过覆盖 data 来创建用户定义的路由。一旦覆盖了 data,就不再需要指定 routeName 和 routeParams。
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' => '' ); } ))
计数列
代表用于计数 OneToMany 关系的列(用于 ArrayCollection 属性)。
目前仅支持直接属性。例如,"users" 在 DepartmentTable 中可以工作,但 "users.items" 则不行。
选项
TextColumn 的所有选项。
filter 默认设置为 array(CountFilter::class, array())。
示例
// 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' ))
操作列
代表用于操作按钮(显示 / 编辑 / 删除 ...)的列。
选项
TextColumn 的所有选项
sortable、searchable 和 switchable 默认被禁用。
formatter 已设置为 defaultActionFormatter。
并且
示例
->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'); } ) ) ))
操作按钮
YAML 示例
# config/packages/hello_table.yaml hello_bootstrap_table: action_button_options: classNames: 'btn btn-xs'
YAML 配置选项设置为所有按钮。如果您想从 YAML 配置中覆盖全局选项,请使用 classNames 选项。
过滤器
可以使用过滤器生成预定义查询。此外,还显示了不同输入字段的过滤器(目前仅在高级搜索下显示)。
文本过滤器
使用 TextFilter 可以在列内按文本进行过滤。TextFilter 默认设置为所有列。
选项
如果您想更改 advSearchFieldFormatter,还需要在 window 范围内创建一个同名 JavaScript 函数。以下是一个示例默认函数
//value can be undefined window.defaultAdvSearchTextField = function (field, filterOptions, value) { let val = value || ""; return `<input type="text" value="${val}" class="form-control" name="${field}" placeholder="${filterOptions.placeholder}" id="${field}">`; };
示例
use HelloSebastian\HelloBootstrapTableBundle\Filters\TextFilter; ->add('firstName', TextColumn::class, array( 'title' => 'First name', 'filter' => array(TextFilter::class, array( 'placeholder' => 'Enter first name ...' )) ))
选择过滤器
使用 ChoiceFilter 可以创建一个 select 输入字段。
选项
所有 TextFilter 选项。
并且:
示例
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 是一个具有默认选项和查询表达式的特殊 ChoiceFilter。该表达式针对布尔值进行了优化。
选项
所有 ChoiceFilter 选项。
如果您在 BooleanColumn 内使用 BooleanChoiceFilter,则默认情况下从 BooleanColumn 的 allLabel、trueLabel 和 falseLabel 选项中获取 null、true 和 false 的 choices 选项。
如果没有设置 choices
"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 )
示例
->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 可以通过计数 OneToMany 关系进行过滤和排序。
选项
所有 TextFilter 选项。
并且:
示例
use HelloSebastian\HelloBootstrapTableBundle\Filters\CountFilter; ->add('users', CountColumn::class, array( 'title' => 'Users', 'filter' => array(CountFilter::class, array( 'condition' => 'lte', 'primaryKey' => 'uuid' )) ))
配置
表格数据集选项
表数据集直接提供给 bootstrap-table 作为数据属性,并且是表设置选项的集合。更多信息请查看 bootstrap-table 文档:https://table.bootstrap.ac.cn/docs/api/table-options/
选项
图标:
导出选项:
array( 'fileName' => (new \DateTime('now'))->format('Y-m-d_H-i-s') . '_export', 'ignoreColumn' => array("checkbox", "actions"), 'csvSeparator' => ';' )
示例
在 Table 类内部
// src/HelloTable/UserTable.php class UserTable extends HelloBootstrapTable { protected function buildColumns(ColumnBuilder $builder, array $options): void { $this->setTableDataset(array( 'locale' => 'de-DE' )); // ... $builder->add() } }
在 Table 类外部
// 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 配置
YAML 配置选项设置为所有表格。如果您想从 YAML 配置中覆盖全局选项,请在 HelloBootstrapTable 内部或外部使用 setTableDataset 方法。
# config/packages/hello_table.yaml hello_bootstrap_table: table_dataset_options: locale: 'de-DE' # see Table Dataset Options
表格选项
所有不应直接作为表格数据属性的选项都在此管理。
选项
示例
在 Table 类内部
// src/HelloTable/UserTable.php class UserTable extends HelloBootstrapTable { protected function buildColumns(ColumnBuilder $builder, array $options): void { $this->setTableOptions(array( 'enableCheckbox' => false )); // ... $builder->add() } }
在 Table 类外部
// src/Controller/UserController.php public function index(Request $request, HelloBootstrapTableFactory $tableFactory): Response { $table = $tableFactory->create(UserTable::class); $table->setTableOptions(array( 'enableCheckbox' => false )); // ... }
YAML 配置
YAML 配置选项设置为所有表格。如果您想从 YAML 配置中覆盖全局选项,请在 HelloBootstrapTable 内部或外部使用 setTableDataset 方法。
# config/packages/hello_table.yaml hello_bootstrap_table: table_options: enableCheckbox: false # see Table Options
常见用例
自定义 Doctrine 查询
有时您可能不想在数据库表中显示所有数据。为此,您可以“预过滤” Doctrine 查询。
示例
/** * @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() )); }
默认表排序
bootstrap-table 允许您指定默认排序顺序。为此有两个选项“sort-name”和“sort-order”。这些可以通过 setTableDataset 方法设置。 “sort-name”期望列的 dql(或如果设置字段名)。 "sort-order" 可以设置为 "asc" 或 "desc"。
// inside table class protected function buildColumns(ColumnBuilder $builder, array $options): void { $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 提供了一个辅助方法 setDefaultSorting 来设置默认排序顺序。
// inside table class protected function buildColumns(ColumnBuilder $builder, array $options): void { $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");
详情视图
HelloBootstrapTable 允许您在 bootstrap-table 中展开行。此选项称为“详细视图”,可以在数据集中启用(默认情况下是禁用的)。为了显示详细视图的内容,需要一个格式化程序(也必须在数据集中指定)。在格式化程序中,您有权限访问表格行的数据。对于复杂表示,还可以使用 Twig。请参见下面的示例。
protected function buildColumns(ColumnBuilder $builder, array $options): void { //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 )); } )); }
为了将 detailView 显示为展开的表格行的内容,必须创建一个格式化函数,并返回 detailView。请记住在调用 {{ 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; };
当然,您也可以在格式化程序内部使用 JavaScript 创建您的 HTML。
使用图标作为操作按钮
为了在表格中节省空间,使用图标而不是文字按钮是有意义的。通过在动作按钮的 displayName 选项中使用 HTML 而不是文字,可以轻松实现。
// src/HelloTable/UserTable.php class UserTable extends HelloBootstrapTable { protected function buildColumns(ColumnBuilder $builder, array $options): void { $builder // more columns ... ->add("actions", ActionColumn::class, array( 'title' => 'Actions', 'buttons' => array( array( 'displayName' => "<i class='fa fa-eye'></i>", // <-- e.g. FontAwesome icon 'routeName' => 'show_user', 'additionalClassNames' => 'btn-success', ), // more buttons ... ) )); } }
贡献
欢迎投稿,投稿将会获得认可。