wieni / wmentity_overview
改进的EntityListBuilders,支持分页、表格排序、表格拖动、筛选、批量操作、数据库查询等。
Requires
- php: >=8.1
- drupal/core: ^10.1
Requires (Dev)
- ergebnis/composer-normalize: ^2.0
- wieni/wmcodestyle: ^1.3
README
改进的EntityListBuilders,支持分页、表格排序、表格拖动、筛选、批量操作、数据库查询等。
为什么?
在Wieni,我们不是很喜欢Views模块,原因有以下几点
- 我们是程序员,不喜欢通过点击Drupal界面创建功能,尤其是膨胀的Views界面
- 我们更喜欢编写自己的数据库或实体查询,这在我们进行筛选和包含非实体字段数据时提供了更多的灵活性,并使查询优化更容易
这就是为什么几年前我们决定完全禁用该模块,最终得到了基于EntityListBuilder的列表。
这些很快就显得功能不足且用户友好性差,这就是我们为什么最终创建了此模块:Views和EntityListBuilder之间的完美折衷。它提供了后者的所有功能,以及以下功能
- 暴露筛选带有自定义表单
- 幕后筛选使用自定义数据库查询
- 表格排序,可按列配置
- 批量操作使用核心操作插件
- 重写内置实体列表使用自定义列表,在实体类型或包级别上
- 重写任何路由使用自定义实体列表
安装
此包需要PHP 7.1和Drupal 8或更高版本。可以使用Composer进行安装
composer require wieni/wmentity_overview
它是如何工作的?
创建概述
概述是具有@OverviewBuilder
注解的Drupal插件。每个注解至少需要entity_type
和id
参数才能正常工作。
您可以选择以下三个基本类之一
OverviewBuilderBase
:最基本的支持数据库查询、分页和表格排序的实体概述FilterableOverviewBuilderBase
:结合基本功能与暴露筛选表单的实体概述DraggableOverviewBuilderBase
:具有可拖动、可重新排序表格的实体概述,但不支持分页或筛选
示例
<?php namespace Drupal\yourmodule\Plugin\EntityOverview; /** * @OverviewBuilder( * entity_type = "node", * ) */ class NodeOverview extends FilterableOverviewBuilderBase { }
覆盖现有的实体列表
您可以通过将override
参数添加到注解中,用自定义概述覆盖默认的实体列表。如果实体类型未被此模块识别,您可以添加route_name
并传递实体列表的路由名称。
也可以在激活某些筛选器组合的情况下仅重写实体列表。这样,您可以在概述通过特定包筛选时添加额外的筛选器或表格列。
示例
<?php namespace Drupal\yourmodule\Plugin\EntityOverview; /** * @OverviewBuilder( * id = "node", * entity_type = "node", * override = true, * ) */ class NodeOverview extends FilterableOverviewBuilderBase { }
<?php namespace Drupal\yourmodule\Plugin\EntityOverview; /** * @OverviewBuilder( * id = "redirect", * entity_type = "redirect", * route_name = "redirect.list", * ) */ class RedirectOverview extends FilterableOverviewBuilderBase { }
<?php namespace Drupal\yourmodule\Plugin\EntityOverview; /** * @OverviewBuilder( * id = "node.article", * entity_type = "node", * override = true, * filters = { * "type" = "article", * }, * ) */ class ArticleOverview extends NodeOverview { }
渲染概述
当您创建未覆盖现有路由的概述时,您必须手动将其渲染到某个位置。
创建实体概述实例的方式与其他Drupal插件相同,通过使用OverviewBuilderManager
的createInstance
方法。
另一种选项是在您的路由定义的defaults
部分添加_entity_overview
,值是插件ID。
示例
yourmodule.content_overview.article: path: '/admin/content/article' defaults: _entity_overview: 'node.article' _title: 'Articles' requirements: _permission: 'administer nodes' options: _admin_route: TRUE
过滤器存储
需要临时存储其过滤器值的实体概述,这是过滤器存储发挥作用的地方:这是一种存储这些值的抽象。
默认情况下,包含两种存储方法:将值存储为URL中的查询参数的query
,以及将值存储在会话存储中的session
。
可以通过创建一个带有@FilterStorage
注释和id
参数的Drupal插件,实现FilterStorageInterface
并可选地扩展FilterStorageBase
来添加自定义存储方法。
默认存储方法是query
,但可以通过向@OverviewBuilder
注释添加filter_storage
参数来更改。
添加批量操作
可以通过实现BulkActionOverviewBuilderInterface
和getBulkActionPlugins
方法来向概述添加批量操作。此方法可以返回两种类型的数组
- 一个以插件ID为键,标签为值的关联数组
- 一个包含插件ID的平面数组
在后一种情况下,将使用默认的插件标签。
可以通过实现PluginFormInterface
将配置表单附加到您的操作插件。如果您需要在表单的验证和/或提交处理程序中访问实体,则可以实现ActionPluginFormInterface
。请注意,与PluginFormInterface
不同,这是一个自定义接口,仅由本模块支持。
钩子和事件
hook_entity_overview_alter
此钩子仅在使用覆盖或使用路由中的_entity_overview
默认值时调用。还提供了一个与钩子等效的事件:WmEntityOverviewEvents::ENTITY_OVERVIEW_ALTER
示例
<?php use Drupal\wmentity_overview\Annotation\OverviewBuilder; function yourmodule_entity_overview_alter(OverviewBuilder $definition, array &$overview) { if (!empty($overview['form'])) { $overview['form']['#attributes']['class'][] = 'custom-entity-overview__form'; } $overview['table']['#attributes']['class'][] = 'custom-entity-overview__table'; }
<?php namespace Drupal\yourmodule\EventSubscriber; use Drupal\wmentity_overview\Event\EntityOverviewAlterEvent; use Drupal\wmentity_overview\WmEntityOverviewEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class EntityOverviewSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { $events[WmEntityOverviewEvents::ENTITY_OVERVIEW_ALTER][] = ['onAlter']; return $events; } public function onAlter(EntityOverviewAlterEvent $event): void { $overview = &$event->getOverview(); if (!empty($overview['form'])) { $overview['form']['#attributes']['class'][] = 'custom-entity-overview__form'; } $overview['table']['#attributes']['class'][] = 'custom-entity-overview__table'; } }
hook_entity_overview_alternatives_alter
此钩子仅在OverviewBuilderManager::getAlternatives
方法中调用。还提供了一个与钩子等效的事件:WmEntityOverviewEvents::ENTITY_OVERVIEW_ALTERNATIVES_ALTER
示例
<?php namespace Drupal\yourmodule\EventSubscriber; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\wmentity_overview\Event\EntityOverviewAlternativesAlterEvent; use Drupal\wmentity_overview\OverviewBuilder\OverviewBuilderManager; use Drupal\wmentity_overview\WmEntityOverviewEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class EntityOverviewAlternativesSubscriber implements EventSubscriberInterface { /** @var OverviewBuilderManager */ protected $overviewBuilders; /** @var RouteMatchInterface */ protected $routeMatch; public function __construct( OverviewBuilderManager $overviewBuilders, RouteMatchInterface $routeMatch ) { $this->overviewBuilders = $overviewBuilders; $this->routeMatch = $routeMatch; } public static function getSubscribedEvents() { $events[WmEntityOverviewEvents::ENTITY_OVERVIEW_ALTERNATIVES_ALTER][] = ['onTaxonomyAlternativesAlter']; return $events; } /** * Since taxonomy has a per-bundle overview, we get the bundle from * the route parameters and use it to add more possible alternatives. */ public function onTaxonomyAlternativesAlter(EntityOverviewAlternativesAlterEvent $event): void { if (!$vocabulary = $this->routeMatch->getParameter('taxonomy_vocabulary')) { return; } if ($event->getDefinition()->getEntityTypeId() !== 'taxonomy_term') { return; } $filters = ['vid' => $vocabulary->id()]; $alternatives = array_merge( $event->getAlternatives(), $this->overviewBuilders->getAlternativesByFilters($event->getDefinition(), $filters) ); $event->setAlternatives($alternatives); } }
变更日志
本项目的所有重大更改都将记录在CHANGELOG文件中。
安全
如果您发现任何与安全相关的问题,请通过电子邮件security@wieni.be而不是使用问题跟踪器。
许可证
在MIT许可证下分发。有关更多信息,请参阅LICENSE文件。