Backend lists 后端列表
- Introduction
- Configuring the list behavior
- Adding a toolbar
- Filtering the list
- Defining list columns
- Column options
- Available column types
- Displaying the list
- Multiple list definitions
- Using list filters
- Scope options
- Available scope types
- Extending list behavior
- Overriding controller action
- Overriding views
- Extending column definitions
- Inject CSS row class
- Extending filter scopes
- Extending the model query
- Extending the records collection
- Custom column types
Introduction 介绍
List behavior controller符号,
用于让大家方便的添加页面的record列表
该behavior提供了可排序和可搜索的列表,并在其record上带有可选链接。
该behavior提供了controller action index
这个list可以在任何地方被渲染并且可以使用多个列表定义。
列表behavior依赖 list column definitions 和 一个model class.
为了使用list behavior,你应该将其添加到controller类的$implement
属性中。
同样,应该定义$ listConfig
类属性,其值应引用用于配置behavior选项的YAML文件。
namespace Acme\Blog\Controllers;class Categories extends \Backend\Classes\Controller
{public $implement = ['Backend.Behaviors.ListController'];public $listConfig = 'list_config.yaml';
}
Note: 通常,列表和[表单behavior](form)在同一控制器中一起使用。
Configuring the list behavior 配置表单behavior
$listConfig
属性中引用的配置文件以YAML格式定义。
该文件应放置在控制器的 视图目录
下面是一个典型的list behavior配置文件的示例:
# ===================================
# List Behavior Config
# ===================================title: Blog Posts
list: ~/plugins/acme/blog/models/post/columns.yaml
modelClass: Acme\Blog\Models\Post
recordUrl: acme/blog/posts/update/:id
列表配置文件中必须包含以下字段:
Field | Description |
---|---|
title | 列表标题 |
list | 配置数组或对列表列定义文件的引用 参见 list columns. |
modelClass | 一个model类名,列表数据就是从这个model加载的。 |
下面列出的配置选项是可选的。
Option | Description |
---|---|
filter | 筛选配置 参见 filtering the list. |
recordUrl | 将每个list record链接到另一个页面。. Eg: users/update:id. :id 是变化值. 它把表单behaviorform behavior与列表behavior连接在了一起 |
recordOnClick | 单击record时执行的自定义JavaScript代码。 |
noRecordsMessage | 找不到记录时显示一条消息, 能关联到本地化 localization string. |
recordsPerPage | 每页显示的记录数,没有页数使用0。Default: 0 |
showPageNumbers | 分页显示页码。禁用此选项可提高使用大型表时的列表性能 Default: true |
toolbar | 引用工具栏小部件配置文件或带有配置的数组 (见下). |
showSorting | 是否显示排序 Default: true |
defaultSort | 未定义用户首选项时设置默认的排序列和方向 支持string或键为 column 和 direction 的数组. |
showCheckboxes | 在每个记录旁边显示复选框. Default: false. |
showSetup | 是否显示set up按钮. Default: false. |
showTree | 为父子records显示一个继承树结构 Default: false. |
treeExpanded | 树节点是否展开. Default: false. |
customViewPath | 指定一个自定义视图路径以覆盖列表使用的部分内容(可选)。 |
Adding a toolbar 添加一个工具栏
要将工具栏包含在列表中,请将以下配置添加到列表配置YAML文件中:
toolbar:buttons: list_toolbarsearch:prompt: Find records
工具栏配置:
Option | Description |
---|---|
buttons | 使用工具栏按钮对controller partial 文件的引用 Eg: _list_toolbar.htm |
search | 对Search Widget配置文件或具有配置的数组的引用。 |
搜索配置支持以下选项:
Option | Description |
---|---|
prompt | 没有活动搜索时显示的占位符,可以本地化 localization string. |
mode | 定义搜索策略以包含所有单词, 任何单词或确切短语. 支持项有: all, any, exact. Default: all. |
scope | 指定在list model 中定义的query scope method以应用于搜索查询,第一个参数将包含搜索项。 |
searchOnEnter | 将其设置为true将使搜索窗口小部件在开始搜索之前等待按下Enter键 (默认行为是,当有人在搜索字段中输入内容并停止一小段时间后,它就会自动开始搜索). Default: false. |
上面提到的工具栏 buttons partial里也应会包含一些按钮
这个partial也会包含一个带图表的scoreboard control 记分板
例如
一个带New Post按钮的工具栏partial会有一个对应的form behavior提供的 create action
<div data-control="toolbar"><ahref="<?= Backend::url('acme/blog/posts/create') ?>"class="btn btn-primary oc-icon-plus">New Post</a>
</div>
Filtering the list
用户自定义过滤列表,请将以下配置添加到YAML文件:
filter: config_filter.yaml
The filter option should make reference to a filter configuration file path or supply an array with the configuration.
filter 选项连接到过滤配置文件路径或者一个配置数组
Defining list columns 定义列
列表列是使用YAML文件定义的
列表行为使用列配置来创建记录表并在表单元格中显示model列
该文件放置在插件的** models 目录的子目录中。子目录名称与小写的模型类名称匹配。
文件名无关紧要
但是columns.yaml** 和 list_columns.yaml是通用名称。
示例列表列文件位置:
plugins/acme/blog/models/ <=== Plugin models directorypost/ <=== Model configuration directorylist_columns.yaml <=== Model list columns config filePost.php <=== model class
下一个示例显示列表列定义文件的典型内容。
# ===================================
# List Column Definitions
# ===================================columns:name: Nameemail: Email
Column options
对于每一列,可以指定以下选项(如果适用):
Option | Description |
---|---|
label | 向用户显示列表列时的名称。 |
type | 定义应如何呈现此列 (see Column types below). |
default | 如果值为空,则指定列的默认值。 |
searchable | 在列表搜索结果中包括此列。Default: false. |
invisible | 指定默认情况下是否隐藏此列。 Default: false. |
sortable | 指定此列是否可以排序. Default: true. |
clickable | 如果设置为false,则在单击列时禁用默认的单击行为。 Default: true. |
select | 定义用于该值的定制SQL select语句。 |
valueFrom | 定义要用于值的model属性。 |
relation | 定义model relation列。 |
useRelationCount | 将定义的relation 的计数作为此列的值。 Default: false |
cssClass | 将CSS类分配给列容器。 |
headCssClass | 将CSS类分配给列标题容器。 |
width | 设置列宽,可以以百分比(10%)或像素(50px)的形式指定。可能只有一列未指定宽度,它将被拉伸以占用可用空间。 |
align | 指定列对齐方式。可能的值为 left , right and center . |
permissions | 当前后端用户必须具有的[permissions](用户#users和权限)才能使用该列。支持单个权限的字符串或仅需要一个权限即可授予访问权限的一组权限。 |
Available column types 可用的列类型
type setting可以使用多种列类型,它们控制列表列的显示方式。除了下面指定的本机列类型之外,您还可以 自定义类型.
Text
text
- 显示一个文本列,向左对齐
full_name:label: Full Nametype: text
你还可以指定自定义文本格式, for example Admin:Full Name (active)
full_name:label: Full Nametype: textformat: Admin:%s (active)
Number
number
- 显示一个数字列,右对齐
age:label: Agetype: number
你还可以指定自定义数字格式 for example currency $ 99.00
price:label: Pricetype: numberformat: $ %.2f
Note: text和number列都支持format属性,此属性遵循PHP sprintf() function. 。值必须是字符串。
Switch
switch
- 显示布尔列的打开或关闭状态。
enabled:label: Enabledtype: switch
Date & Time
datetime
- 将列值显示为格式化的日期和时间.下面例子的日期为 Thu, Dec 25, 1975 2:15 PM.
created_at:label: Datetype: datetime
你还可以指定自定义日期格式 for example Thursday 25th of December 1975 02:15:16 PM:
created_at:label: Datetype: datetimeformat: l jS \of F Y h:i:s A
您可能还希望设置ignoreTimezone: true
,以防止在显示的日期和数据库中存储的日期之间进行时区转换,因为默认情况下,后端时区首选项应用于显示值。
created_at:label: Datetype: datetimeignoreTimezone: true
注意:
ignoreTimezone
选项也适用于其他与日期和时间相关的字段类型, 包括date
,time
,timesince
和timetense
.
Date
date
- 将列值显示为日期格式 M j, Y
created_at:label: Datetype: date
Time
time
- 将列值显示为时间格式 g:i A
created_at:label: Datetype: time
Time since
timesince
- 显示从值到当前时间的人类可读时间差. Eg: 10 minutes ago
created_at:label: Datetype: timesince
Time tense
timetense
- 使用当前日期的语法时态显示24小时时间和日期 Eg: Today at 12:49, Yesterday at 4:00 or 18 Sep 2015 at 14:33.
created_at:label: Datetype: timetense
Select
select
- 允许使用自定义的select语句创建列。任何有效的SQL SELECT语句均可在此处使用。
full_name:label: Full Nameselect: concat(first_name, ' ', last_name)
Relation
relation
- 允许显示相关的列,您可以提供一个关系选项。 The value of this option has to be the name of the Active Record relationship on your model. In the next example the name value will be translated to the name attribute found in the related model (eg: $model->name
).
此选项的值必须是model上Active Record relationship 的名称。
在下一个示例中,name值将转换为相关模型中的name属性(eg: $model->name
).
group:label: Grouprelation: groupsselect: name
要展现显示相关记录数的列,请使用useRelationCount
选项。
users_count:label: Usersrelation: usersuseRelationCount: true
注意: 在列上使用“ relation”选项会将“ select”列中的值加载到该列指定的属性中 。
建议您为显示关系数据的列命名不与现有模型属性冲突,如以下示例所示:
最佳实践:
group_name:label: Grouprelation: groupselect: name
不良实践:
# 这将覆写 $record->group_id 将中断从列表视图的访问关系
group_id:label: Grouprelation: groupselect: name
Partial
partial
- 渲染一个 partial, path
的值能与partial view文件关联,否则将列名用作partial名称。
partial内部变量为:$value
是默认的单元格值, $record
是用于该单元格的模型,$column
是已配置的类对象Backend\Classes\ListColumn
.
content:type: partialpath: ~/plugins/acme/blog/models/comments/_content_column.htm
Color Picker
colorpicker
- displays a color from colorpicker column
color:label: Backgroundtype: colorpicker
Displaying the list
Usually lists are displayed in the index view file. Since lists include the toolbar, the view file will consist solely of the single listRender
method call.
<?= $this->listRender() ?>
Multiple list definitions
The list behavior can support multiple lists in the same controller using named definitions. The $listConfig
property can be defined as an array where the key is a definition name and the value is the configuration file.
public $listConfig = ['templates' => 'config_templates_list.yaml','layouts' => 'config_layouts_list.yaml'
];
Each definition can then be displayed by passing the definition name as the first argument when calling the listRender
method:
<?= $this->listRender('templates') ?>
Using list filters
Lists can be filtered by adding a filter definition to the list configuration. Similarly filters are driven by their own configuration file that contain filter scopes, each scope is an aspect by which the list can be filtered. The next example shows a typical contents of the filter definition file.
# ===================================
# Filter Scope Definitions
# ===================================scopes:category:label: CategorymodelClass: Acme\Blog\Models\Categoryconditions: category_id in (:filtered)nameFrom: namestatus:label: Statustype: groupconditions: status in (:filtered)options:pending: Pendingactive: Activeclosed: Closedpublished:label: Hide publishedtype: checkboxdefault: 1conditions: is_published <> trueapproved:label: Approvedtype: switchdefault: 2conditions:- is_approved <> true- is_approved = truecreated_at:label: Datetype: dateconditions: created_at >= ':filtered'published_at:label: Datetype: daterangeconditions: created_at >= ':after' AND created_at <= ':before'
Scope options
For each scope you can specify these options (where applicable):
Option | Description |
---|---|
label | a name when displaying the filter scope to the user. |
type | defines how this scope should be rendered (see Scope types below). Default: group. |
conditions | specifies a raw where query statement to apply to the list model query, the :filtered parameter represents the filtered value(s). |
scope | specifies a query scope method defined in the list model to apply to the list query. The first argument will contain the query object (as per a regular scope method) and the second argument will contain the filtered value(s) |
options | options to use if filtering by multiple items, this option can specify an array or a method name in the modelClass model. |
nameFrom | if filtering by multiple items, the attribute to display for the name, taken from all records of the modelClass model. |
default | can either be integer(switch,checkbox,number) or array(group,date range,number range) or string(date). |
permissions | the permissions that the current backend user must have in order for the filter scope to be used. Supports either a string for a single permission or an array of permissions of which only one is needed to grant access. |
dependsOn | a string or an array of other scope names that this scope depends on. When the other scopes are modified, this scope will update. |
Filter Dependencies
Filter scopes can declare dependencies on other scopes by defining the dependsOn
scope option, which provide a server-side solution for updating scopes when their dependencies are modified. When the scopes that are declared as dependencies change, the defining scope will update dynamically. This provides an opportunity to change the available options to be provided to the scope.
country:label: Countrytype: groupconditions: country_id in (:filtered)modelClass: October\Test\Models\Locationoptions: getCountryOptionscity:label: Citytype: groupconditions: city_id in (:filtered)modelClass: October\Test\Models\Locationoptions: getCityOptionsdependsOn: country
In the above example, the city
scope will refresh when the country
scope has changed. Any scope that defines the dependsOn
property will be passed all current scope objects for the Filter widget, including their current values, as an array that is keyed by the scope names.
public function getCountryOptions()
{return Country::lists('name', 'id');
}public function getCityOptions($scopes = null)
{if (!empty($scopes['country']->value)) {return City::whereIn('country_id', array_keys($scopes['country']->value))->lists('name', 'id');} else {return City::lists('name', 'id');}
}
Note: Scope dependencies with
type: group
are only supported at this stage.
Available scope types
These types can be used to determine how the filter scope should be displayed.
Group
group
- filters the list by a group of items, usually by a related model and requires a nameFrom
or options
definition. Eg: Status name as open, closed, etc.
status:label: Statustype: groupconditions: status in (:filtered)default:pending: Pendingactive: Activeoptions:pending: Pendingactive: Activeclosed: Closed
Checkbox
checkbox
- used as a binary checkbox to apply a predefined condition or query to the list, either on or off. Use 0 for off and 1 for on for default value
published:label: Hide publishedtype: checkboxdefault: 1conditions: is_published <> true
Switch
switch
- used as a switch to toggle between two predefined conditions or queries to the list, either indeterminate, on or off. Use 0 for off, 1 for indeterminate and 2 for on for default value
approved:label: Approvedtype: switchdefault: 1conditions:- is_approved <> true- is_approved = true
Date
date
- displays a date picker for a single date to be selected.
created_at:label: Datetype: dateminDate: '2001-01-23'maxDate: '2030-10-13'yearRange: 10conditions: created_at >= ':filtered'
Date Range
daterange
- displays a date picker for two dates to be selected as a date range. The conditions parameters are passed as :before
and :after
.
published_at:label: Datetype: daterangeminDate: '2001-01-23'maxDate: '2030-10-13'yearRange: 10conditions: created_at >= ':after' AND created_at <= ':before'
To use default value for Date and Date Range
myController::extendListFilterScopes(function($filter){
'Date Test' => ['label' => 'Date Test','type' => 'daterange','default' => $this->myDefaultTime(),'conditions' => "created_at >= ':after' AND created_at <= ':before'"],]);});// return value must be instance of carbonpublic function myDefaultTime(){
return [0 => Carbon::parse('2012-02-02'),1 => Carbon::parse('2012-04-02'),];}
You may also wish to set ignoreTimezone: true
to prevent a timezone conversion between the date that is displayed and the date stored in the database, since by default the backend timezone preference is applied to the display value.
published_at:label: Datetype: daterangeminDate: '2001-01-23'maxDate: '2030-10-13'yearRange: 10conditions: created_at >= ':after' AND created_at <= ':before'ignoreTimezone: true
Note: the
ignoreTimezone
option also applies to thedate
filter type as well.
Number
number
- displays input for a single number to be entered.
age:label: Agetype: numberdefault: 14conditions: age >= ':filtered'
Number Range
numberrange
- displays inputs for two numbers to be entered as a number range. The conditions parameters are passed as :min
and :max
. You may leave either the minimum value blank to search everything up to the maximum value, and vice versa, you may leave the maximum value blank to search everything at least the minimum value.
visitors:label: Visitor Counttype: numberrangedefault:0: 101: 20conditions: visitors >= ':min' and visitors <= ':max'
Text
text
- display text input for a string to be entered. You can specify a size
attribute that will be injected in the input size attribute (default: 10).
username:label: Usernametype: textconditions: username = :valuesize: 2
Extending list behavior 扩展列表行为
有时您可能希望修改默认列表行为,有几种方法可以执行此操作。
- Overriding controller action
- Overriding views
- Extending column definitions
- Inject CSS row class
- Extending filter scopes
- Extending the model query
- Custom column types
Overriding controller action 覆写controller action
覆写controller中的 index
action方法,然后选择调用List behavior index
父方法。
public function index()
{//// Do any custom code here//// Call the ListController behavior index() method$this->asExtension('ListController')->index();
}
Overriding views 覆写views
ListController
有一个主容器视图,您可以通过在控制器目录中创建一个名为_list_container.htm
的特殊文件来覆盖它。 以下示例将向列表添加一个边栏:
<?php if ($toolbar): ?><?= $toolbar->render() ?>
<?php endif ?><?php if ($filter): ?><?= $filter->render() ?>
<?php endif ?><div class="row row-flush"><div class="col-sm-3">[Insert sidebar here]</div><div class="col-sm-9 list-with-sidebar"><?= $list->render() ?></div>
</div>
behavior调用包含许多你可以覆盖的视图的 Lists
widget
如 list configuration options 列表配置选项. 中所述,可以通过指定customViewPath
选项来实现。
This is possible by specifying a customViewPath
option as described in the list configuration options. 小部件将首先在此路径中查找视图,然后退回到默认位置。
# Custom view path
customViewPath: $/acme/blog/controllers/reviews/list
Note:最好使用子目录(例如
list
)以避免冲突。
例如,要修改列表主体行标记,请在控制器目录中创建一个名为list/_list_body_row.htm
的文件。
<?php foreach ($columns as $key => $column): ?>
<?= $this->getColumnValue($record, $column) ?>
<?php endforeach ?>
Extending column definitions 扩展列定义
你可以通过在控制器类上调用extendListColumns
静态方法来从外部扩展另一个控制器的列
此方法可以使用两个参数
$list 代表Lists窗口小部件对象
$model 代表列表使用的模型
以这个控制器为例:
class Categories extends \Backend\Classes\Controller
{public $implement = ['Backend.Behaviors.ListController'];public $listConfig = 'list_config.yaml';
}
使用extendListColumns
方法,您可以在此控制器呈现的任何列表中添加额外的列。最好检查 $model 的类型正确。例子:
Categories::extendListColumns(function($list, $model){if (!$model instanceof MyModel) {return;}$list->addColumns(['my_column' => ['label' => 'My Column']]);});
你还可以通过覆盖控制器类内的listExtendColumns
方法在内部扩展列表列。
class Categories extends \Backend\Classes\Controller
{[...]public function listExtendColumns($list){$list->addColumns([...]);}
}
$ list对象上可以使用以下方法。
Method | Description |
---|---|
addColumns | 将新列添加到列表 |
removeColumn | 从列表中删除一列 |
每种方法都采用类似于 list column configuration.的列数组。
Inject CSS row class 注入CSS行类
您可以通过在控制器类上添加listInjectRowClass
方法来注入定制的CSS行类。该方法可以接受两个参数,
$record代表单个模型record,
$definition包含List小部件定义的名称。
你可以返回任何包含行类的字符串值。这些类将添加到行的HTML标记中。
class Lessons extends \Backend\Classes\Controller
{[...]public function listInjectRowClass($lesson, $definition){// 总结过去的课程if ($lesson->lesson_date->lt(Carbon::today())) {return 'strike';}}
}
特殊的CSS类nolink
可用于强制行不可单击,即使为List小部件定义了recordUrl
或recordOnClick
选项也是如此。
在事件中返回此class类将使records不可单击-例如,对于软删除的行或信息行:
public function listInjectRowClass($record, $value){if ($record->trashed()) {return 'nolink';}}
Extending filter scopes 扩展过滤范围
您可以通过在控制器类上调用extendListFilterScopes
静态方法来从外部扩展另一个控制器的过滤范围。此方法可以使用参数**$filter**,它表示Filter小部件对象。以这个控制器为例:
Categories::extendListFilterScopes(function($filter) {// 将自定义CSS类添加到Filter小部件本身$filter->cssClasses = array_merge($filter->cssClasses, ['my', 'array', 'of', 'classes']);$filter->addScopes(['my_scope' => ['label' => 'My Filter Scope']]);});
提供的作用域数组类似于list filters configuration列表过滤器配置.。
您还可以在内部将过滤器作用域扩展到controller类,只需覆盖listFilterExtendScopes
方法即可。
class Categories extends \Backend\Classes\Controller
{[...]public function listFilterExtendScopes($filter){$filter->addScopes([...]);}
}
在$filter对象上可以使用以下方法。
Method | Description |
---|---|
addScopes | 向过滤器小部件添加新范围 |
removeScope | 从过滤器小部件中删除范围 |
Extending the model query 扩展模型查询
列表 database model 的查找查询可以通过覆盖控制器类内的listExtendQuery
方法来扩展
通过将 withTrashed 范围应用于查询,此示例将确保将软删除的记录包括在列表数据中:
public function listExtendQuery($query)
{$query->withTrashed();
}
list filter model查询也可以通过重写listFilterExtendQuery
方法来扩展:
public function listFilterExtendQuery($query, $scope)
{if ($scope->scopeName == 'status') {$query->where('status', '<>', 'all');}
}
Extending the records collection 扩展记录收集
可以通过覆盖控制器类中的listExtendRecords
方法来扩展列表使用的记录的集合。
本示例在record collection 上使用sort
方法来更改记录的排序顺序。
public function listExtendRecords($records)
{return $records->sort(function ($a, $b) {return $a->computedVal() > $b->computedVal();});
}
Custom column types 自定义列类型
Custom list column types can be registered in the back-end with the registerListColumnTypes
method of the Plugin registration class. The method should return an array where the key is the type name and the value is a callable function. The callable function receives three arguments, the native $value
, the $column
definition object and the model $record
object.
自定义列表列类型可以使用 Plugin registration class的registerListColumnTypes
方法在后端注册。
该方法应返回一个数组,其中键是类型名,值是可调用函数。
可调用函数接收三个参数,本地$value
、$column
定义对象和模型$record
对象。
public function registerListColumnTypes()
{return [// 一个本地方法, i.e $this->evalUppercaseListColumn()'uppercase' => [$this, 'evalUppercaseListColumn'],// 使用内联闭包'loveit' => function($value) { return 'I love '. $value; }];
}public function evalUppercaseListColumn($value, $column, $record)
{return strtoupper($value);
}
使用自定义列表列类型就像使用类型选项按名称调用一样简单
# ===================================
# List Column Definitions
# ===================================columns:secret_code:label: Secret codetype: uppercase