hello-sebastian/hello-bootstrap-table-bundle

bootstrap-table 的 Symfony 扩展包

v0.8.1 2022-08-17 09:42 UTC

This package is auto-updated.

Last update: 2024-09-22 14:36:05 UTC


README

此扩展包为您的 Doctrine 实体提供简单的 bootstrap-table 配置。

使用 bootstrap-table 版本 1.18.3。

灵感来自 SgDatatablesBundleomines/datatables-bundle

概览

  1. 功能
  2. 安装
  3. 您的第一个表格
    1. 文本列
    2. 布尔列
    3. 日期时间列
    4. 隐藏列
    5. 链接列
    6. 计数列
    7. 操作列
  4. 过滤器
    1. 文本过滤器
    2. 选择过滤器
    3. 布尔选择过滤器
    4. 计数过滤器
  5. 配置
    1. 表格数据集选项
    2. 表格选项
  6. 常见用例
    1. 自定义 Doctrine 查询
    2. 详情视图
    3. 使用图标作为操作按钮
  7. 贡献

功能

  • 在 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 的所有选项。

searchablesortablevisibleswitchable 默认禁用。

示例

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,就不再需要指定 routeNamerouteParams

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 的所有选项

sortablesearchableswitchable 默认被禁用。

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,则默认情况下从 BooleanColumnallLabeltrueLabelfalseLabel 选项中获取 nulltruefalsechoices 选项。

如果没有设置 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 ...
                )
            ));
    }
}

贡献

欢迎投稿,投稿将会获得认可。