“中国要复兴、富强,必须在开源软件领域起到主导作用,为了国家安全和人类发展,责无旁贷,我们须为此而奋斗”——By:云客
实体列表构建和实体视图构建有相似之处,但并不是一样的概念,从字面意思看列表构建似乎是用于产生实体的索引页面(比如摘要列表页),但产生索引页面是视图构建器的工作,而列表构建则是用于管理工作:用来列出实体以便操作它们
列表路由:
比如“管理-结构-内容类型”(地址:/admin/structure/types),这个页面就是实体列表构建器产生的列表页面,用于对内容类型进行管理,其路由定义如下:
entity.node_type.collection:
path: '/admin/structure/types'
defaults:
_entity_list: 'node_type'
_title: 'Content types'
requirements:
_permission: 'administer content types'
如果路由中没有设置控制器,只设置了“_entity_list”,那么会使用以下通用列表控制器:
\Drupal\Core\Entity\Controller\EntityListController::listing
这在以下路由增强器中处理
\Drupal\Core\Entity\Enhancer\EntityRouteEnhancer::enhanceEntityList
如果路由中设置了“_entity_list”,则其值应是实体类型id,表示对该实体类型进行列表操作,在以上通用实体列表控制器中当做参数“$entity_type”的值,以字符串方式传入
产生实体列表页的代码如下:
$listBuilder = \Drupal::entityTypeManager()->getListBuilder($entityTypeID);
return $listBuilder->render();
这调用实体列表构建器并返回列表页面的渲染数组
实体列表构建器:
列表构建核心是列表构建器,这是实体的一个处理器,定义在实体释文处理器键下的“list_builder”项中,并不是所有实体类型都有列表构建器,比如“entity_view_display”就不需要因此没有,可通过以下代码来查看实体类型的列表构建器:
$definitions = \Drupal::entityTypeManager()->getDefinitions();
$data = [];
foreach ($definitions as $entity_type => $definition) {
$data[$entity_type] = $definition->getHandlerClass('list_builder');
}
print_r($data);die;
列表构建器以处理器方式进行实例化,其实现接口如下:
\Drupal\Core\Entity\EntityListBuilderInterface
默认基类:
\Drupal\Core\Config\Entity\ConfigEntityListBuilder(配置实体)
\Drupal\Core\Entity\EntityListBuilder(内容实体)
通常自定义的实体类型需要继承她们,默认系统中的列表构建器均继承自她们,实体类型:comment和taxonomy_term甚至直接使用了默认基类
下文分别介绍这两个默认基类
实体列表构建器默认基类:
类如下:
\Drupal\Core\Entity\EntityListBuilder
方法说明:
public function getStorage()
返回实体的储存处理器,见本系列储存处理器主题
public function load()
通过储存处理器加载要在列表中显示的实体
protected function getEntityIds()
决定加载哪些实体,返回实体类型id,默认以实体id键升序排序,设置每页加载数量,默认每页50条
public function getOperations(EntityInterface $entity)
返回实体的操作链接,值为一个数组,以操作名做键名,键值为一个数组,有以下键值:
title:翻译后的标题,做链接文字,可为翻译对象,如:t('Edit')
weight:操作排序权重,浮点数
url:操作链接的url对象
该方法会派发以下构建了钩子:
entity_operation
函数:
hook_entity_operation(\Drupal\Core\Entity\EntityInterface $entity)
默认的操作类型和模块构建的操作类型以“+”合并,默认的优先级更高,合并后再派发该钩子的修改钩子
protected function getDefaultOperations(EntityInterface $entity)
返回实体的默认操作,也就是实体释文中定义的操作,默认有两个:更新和删除,需要有权限且有对应的链接模板,由该方法可见链接模板的键名定义需要遵循规范
public function buildHeader()
构建列表头部标题栏,默认只有一列,子类往往需要重写该方法以添加更多列数据
public function buildRow(EntityInterface $entity)
构建列表行,默认只有一列,子类往往需要重写该方法以添加更多列数据
public function buildOperations(EntityInterface $entity)
构建操作单元格中显示的操作链接的渲染数组
public function render()
返回列表页的主渲染数组,以表格方式渲染(默认只有操作栏一列),附加分页链接
protected function ensureDestination(Url $url)
为操作链接附加目的地“destination”查询参数,以便操作后的调跳转
配置实体列表构建器默认基类:
该类继承自前一节的默认基类,以特别处理配置实体,类如下:
\Drupal\Core\Config\Entity\ConfigEntityListBuilder
方法解释如下:
public function load()
加载未经配置覆写的配置实体,和内容实体以实体id排序不同,配置实体以实体类的sort()方法排序
public function getDefaultOperations(EntityInterface $entity)
配置实体的默认操作链接比内容实体多出启用禁用链接,在该方法中特别处理
子类例举:
以上基类只显示了列表中的一个列(操作列),并为提供其他列的显示,因此子类需要添加更多的列,通常需要实现以下方法:
添加头部其他列数据:
public function buildHeader()
添加每行其他列数据:
public function buildRow(EntityInterface $entity)
可参考内容类型的列表构建器:
\Drupal\node\NodeTypeListBuilder
\Drupal\node\NodeListBuilder
处理重定向目的地:
在drupal的网址中GET参数:“destination”(目的地)具有特殊含义,指示请求处理完成后跳转到这个参数值所示的网址,根据该参数的值分几种情况:
如果存在但指向外部站点将禁止跳转,而重定向到网站首页
如果存在且为网站内部地址将正常跳转
如果不存在将跳转到当前页
该逻辑被大量使用,因此系统定义了重定向目的地服务以便于使用,定义如下:
容器id:redirect.destination
类:Drupal\Core\Routing\RedirectDestination
获取方法:\Drupal::destination();
方法如下:
public function get()
以字符串方式返回处理后的目的地链接
public function set($new_destination)
设置一个目的地链接,参数为字符串
public function getAsArray()
返回一个数组,键名为“destination”,键值为字符串方式的目的地链接,该返回值通常用于给url对象设置选项值,如:
$url->mergeOptions(['query' =>\Drupal::destination()->getAsArray()]);
这将给url的查询参数添加上“destination”参数
补充:
1、实体对象的toUrl方法可以依据实体释文中的链接模板(links键)产生指向自己的某种操作链接(URL对象),如查看、编辑等,我们知道有链接是不够的,还需要路由定义,那么链接模板和路由之间是什么样的关系呢?你可能会想到让系统自动依据链接模板定义路由,这是可行的,但目前系统尚未实现这个功能,需要由实体类型所属模块自行定义,这就需要模块开发者明确知道二者的对应规范了,首先路径的格式需要相同,其次假设链接模板的键名为$rel,路由名和$rel有如下对应关系:
$route_name = "entity.{$entityTypeId}." . str_replace(['-', 'drupal:'], ['_', ''], $rel);
如节点实体链接模板中的编辑表单$rel 为:edit-form,路由名就是entity.node.edit_form
再次就是路由变量问题,变量名和其含义对应如下:
实体类型id:实体id,如“node:28”
实体类型id_revision:版本id,如“node_revision:28”
bundle实体类型名:bundle类型值,如“node_type:article”,bundle实体类型名以释文中的bundle_entity_type优先,如果不存在将以标准实体键bundle的值为准
2、实体链接模板中的键名$rel也有标准规范,不可随意定义,如编辑表单应为“edit-form”,删除表单应为“delete-form”,否则像列表构建器这样的组件将无法正确处理
反馈互动