bagisto-datagrid-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

DataGrid Development

DataGrid 开发

An admin listing page is a
DataGrid
subclass plus three lines of wiring. The engine (
packages/Webkul/DataGrid
) owns paging, search, filtering, sorting, saved filters and export; the subclass supplies a query and describes its columns. There are 51 of them in the codebase — copy the closest one rather than inventing a shape.
后台列表页由一个
DataGrid
子类加上三行配置代码构成。核心引擎(
packages/Webkul/DataGrid
)负责分页、搜索、筛选、排序、保存筛选条件和导出功能;子类则提供查询语句并定义列信息。代码库中已有51个此类实现——建议参考最相似的实现,而非自行设计结构。

The four methods

四个核心方法

Webkul\DataGrid\DataGrid
declares two abstract methods and two optional hooks:
MethodRequiredPurpose
prepareQueryBuilder()
yesReturn a query builder, not a collection
prepareColumns()
yes
addColumn([...])
per column
prepareActions()
noPer-row actions, each ACL-gated
prepareMassActions()
noCheckbox actions, each ACL-gated
Tunable properties, overridden only when the default is wrong:
$primaryColumn
(default
'id'
),
$sortColumn
,
$sortOrder
(
'desc'
),
$itemsPerPage
(10),
$perPageOptions
.
Webkul\DataGrid\DataGrid
定义了两个抽象方法和两个可选钩子方法:
方法名是否必填作用
prepareQueryBuilder()
返回查询构建器,而非集合
prepareColumns()
为每个列调用
addColumn([...])
prepareActions()
定义每行操作,每个操作需做ACL权限校验
prepareMassActions()
定义复选框批量操作,每个操作需做ACL权限校验
可调整属性,仅在默认值不符合需求时覆盖:
$primaryColumn
(默认值
'id'
)、
$sortColumn
$sortOrder
(默认值
'desc'
)、
$itemsPerPage
(默认值10)、
$perPageOptions

The shape

代码结构示例

php
class CurrencyDataGrid extends DataGrid
{
    /**
     * Prepare query builder.
     *
     * @return Builder
     */
    public function prepareQueryBuilder()
    {
        return DB::table('currencies')
            ->select('id', 'name', 'code');
    }

    /**
     * Add Columns.
     *
     * @return void
     */
    public function prepareColumns()
    {
        $this->addColumn([
            'index'      => 'name',
            'label'      => trans('admin::app.settings.currencies.index.datagrid.name'),
            'type'       => 'string',
            'searchable' => true,
            'filterable' => true,
            'sortable'   => true,
        ]);
    }

    /**
     * Prepare actions.
     *
     * @return void
     */
    public function prepareActions()
    {
        if (bouncer()->hasPermission('settings.currencies.edit')) {
            $this->addAction([
                'index'  => 'edit',
                'icon'   => 'icon-edit',
                'title'  => trans('admin::app.settings.currencies.index.datagrid.edit'),
                'method' => 'GET',
                'url'    => fn ($row) => route('admin.settings.currencies.edit', $row->id),
            ]);
        }
    }
}
Align the
=>
inside an
addColumn
/
addAction
array only if the file you are editing already does; Pint does not enforce alignment either way, and the codebase has both.
php
class CurrencyDataGrid extends DataGrid
{
    /**
     * Prepare query builder.
     *
     * @return Builder
     */
    public function prepareQueryBuilder()
    {
        return DB::table('currencies')
            ->select('id', 'name', 'code');
    }

    /**
     * Add Columns.
     *
     * @return void
     */
    public function prepareColumns()
    {
        $this->addColumn([
            'index'      => 'name',
            'label'      => trans('admin::app.settings.currencies.index.datagrid.name'),
            'type'       => 'string',
            'searchable' => true,
            'filterable' => true,
            'sortable'   => true,
        ]);
    }

    /**
     * Prepare actions.
     *
     * @return void
     */
    public function prepareActions()
    {
        if (bouncer()->hasPermission('settings.currencies.edit')) {
            $this->addAction([
                'index'  => 'edit',
                'icon'   => 'icon-edit',
                'title'  => trans('admin::app.settings.currencies.index.datagrid.edit'),
                'method' => 'GET',
                'url'    => fn ($row) => route('admin.settings.currencies.edit', $row->id),
            ]);
        }
    }
}
仅当你正在编辑的文件已对齐
addColumn
/
addAction
数组中的
=>
时,才保持对齐;Pint(Laravel代码规范工具)不强制要求对齐方式,代码库中两种格式都存在。

Wiring

关联配置

The controller serves JSON on an AJAX hit and the view otherwise — one route, two responses:
php
public function index()
{
    if (request()->ajax()) {
        return datagrid(CurrencyDataGrid::class)->process();
    }

    return view('admin::settings.currencies.index');
}
The Blade side is one tag pointing at that same route:
blade
<x-admin::datagrid :src="route('admin.settings.currencies.index')" />
datagrid()
throws
InvalidDataGridException
unless the class extends
DataGrid
, so the class name is the only contract.
控制器在AJAX请求时返回JSON数据,否则返回视图——一个路由,两种响应:
php
public function index()
{
    if (request()->ajax()) {
        return datagrid(CurrencyDataGrid::class)->process();
    }

    return view('admin::settings.currencies.index');
}
Blade视图侧只需一个标签指向同一路由:
blade
<x-admin::datagrid :src="route('admin.settings.currencies.index')" />
除非类继承自
DataGrid
,否则
datagrid()
会抛出
InvalidDataGridException
,因此类名是唯一的约定。

Reference files

参考文档

FileLoad when
columns.mdColumn types, search/filter/sort flags, dropdown options, closures, joins and
addFilter
actions.mdRow actions, mass actions, ACL gating, export
文件适用场景
columns.md列类型、搜索/筛选/排序标记、下拉选项、闭包、关联查询和
addFilter
方法
actions.md行操作、批量操作、ACL权限校验、导出功能

Non-negotiables

必须遵守的规则

  • prepareQueryBuilder()
    returns a builder.
    Calling
    ->get()
    ,
    ->paginate()
    or mapping to a collection breaks paging, filtering and export, because the engine appends to the query you return.
  • The query builder is the one place
    DB::
    is expected.
    Everywhere else in Bagisto goes through a repository; a DataGrid is built on the query builder by design.
  • Every action and mass action is wrapped in
    bouncer()->hasPermission(...)
    .
    An ungated action renders for admins who cannot perform it, and the grid is the most common place this is forgotten.
  • Every
    label
    goes through
    trans()
    , with the key added to all 22 locales.
  • A joined query needs
    addFilter()
    for every aliased column
    — see columns.md. Without it, filtering and sorting on that column produce an ambiguous-column SQL error.
  • Escape whatever a closure interpolates. Cells render through
    v-html
    . The engine strips tags from raw values first, but not quotes — so a value placed inside an attribute can break out. See columns.md.
REQUIRED SUB-SKILL: Use bagisto-change-verification before calling any change done.
  • prepareQueryBuilder()
    必须返回查询构建器。
    调用
    ->get()
    ->paginate()
    或转换为集合会破坏分页、筛选和导出功能,因为核心引擎会在你返回的查询基础上追加条件。
  • 查询构建器是唯一允许使用
    DB::
    的地方。
    Bagisto的其他所有地方都通过仓库层操作;DataGrid在设计上就是基于查询构建器实现的。
  • 每个行操作和批量操作都必须用
    bouncer()->hasPermission(...)
    包裹。
    未做权限校验的操作会对无权限的管理员显示,而列表页是最容易遗漏权限校验的地方。
  • 所有
    label
    都必须通过
    trans()
    进行翻译
    ,且翻译键需添加到全部22种语言包中。
  • 关联查询中每个别名列都需要调用
    addFilter()
    ——详见columns.md。如果不这么做,对该列进行筛选或排序会导致SQL歧义列错误。
  • 闭包中插入的任何内容都必须转义。 单元格通过
    v-html
    渲染。核心引擎会先从原始值中剥离标签,但不会处理引号——因此插入到属性中的值可能会导致注入问题。详见columns.md
必备子技能: 在完成任何修改前,使用bagisto-change-verification工具进行验证。