wedevelopnl / ux-table
v0.4.1
2024-04-25 13:43 UTC
Requires
- php: >=8.1
- symfony/form: >5.4
- symfony/routing: >5.4
- symfony/ux-twig-component: >2
- twig/twig: >2
Suggests
- symfony/ux-turbo: *
- symfony/webpack-encore-bundle: to use the Stimulus assets included in this bundle
README
实验性:此包仍在开发中,一切均可能更改。
描述
UX Table 是一款旨在与 Symfony UX Turbo 和 Stimulus(Symfony Encore 的一部分)良好协作的数据表。此包旨在利用 超媒体驱动应用(HDA)架构的美丽简洁性。
此包包含用于创建完全灵活数据表的构建块。具体来说,它有助于生成保留 UX 表状态的表单(带有隐藏输入)和链接。
此方法的优势
- 完全控制模板
- 无 JavaScript(即使在禁用 JavaScript 的情况下也能工作)
- 无序列化
先决条件
Symfony UX Turbo
请确保已安装并设置 Symfony UX Turbo。我们严重依赖此功能以提供良好的用户体验。
安装
composer require wedevelopnl/ux-table
使用 Symfony Flex
您应该能够开始。
不使用 Symfony Flex
npm i -D vendor/wedevelopnl/ux-table/assets
- 添加到
bundles.php
WeDevelop\UXTable\WeDevelopUXTableBundle::class => ['all' => true],
- 添加到
assets/controllers.json
{ "controllers": { "@wedevelopnl/ux-table": { "ux-table": { "enabled": true, "fetch": "eager" } } }, "entrypoints": [] }
入门
创建表单
首先我们创建一个新的表单,它扩展了 WeDevelop\UXTable\Table\AbstractTable
<?php namespace App\UXTable; use Symfony\Component\Form\Extension\Core\Type\SearchType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use WeDevelop\UXTable\Table\AbstractTable; final class ProjectsTable extends AbstractTable { public function getName(): string { return 'projects'; } protected function buildFilterForm(FormBuilderInterface $builder, array $options): void { $builder ->add('name', SearchType::class, [ 'attr' => $this->stimulusSearchAttributes(), 'required' => false, ]) ; } protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setDefaults([ 'data_class' => \App\Entity\Project::class, 'sortable_fields' => ['name'], ]); } }
这是一个基本的数据表,它为 name
字段添加了过滤器。
创建控制器操作
#[Route('/projects', name: 'app_project_list')] public function listAction(Request $request, ProjectsTable $projectsTable): Response { $projectsTable->process($request); return $this->render( 'project/list.html.twig', ['projectsTable' => $projectsTable] ); }
模板
{# Optional optimization #} {% extends app.request.headers.has('turbo-frame') ? 'empty.html.twig' : 'page.html.twig' %} {% block main %} <h2>Projects</h2> <twig:UXTable:Table :table="projectsTable"> <table> <thead> <tr> <th> <twig:UXTable:SortLink :table="projectsTable" title="Name" field="name" /> <twig:UXTable:Filter :table="projectsTable" filter="name" /> </th> <th></th> </tr> </thead> <tbody> {% for project in projectsTable.results %} <tr> <td>{{ project.name }}</td> <td><a href="{{ path('app_project_view', {projectId: project.id}) }}" data-turbo-frame="_top">View</a> </td> </tr> {% endfor %} </tbody> </table> Page size {{ form_widget(projectsTable.formView.pageSize) }} Pagination {{ knp_pagination_render(projectsTable.results) }} </twig:UXTable:Table> {% endblock %}
这里有几个重要的事情。
{% extends app.request.headers.has('turbo-frame') ? 'empty.html.twig' : 'page.html.twig' %}
这确保了在 Turbo Frame 内导航时,我们确保不渲染整个布局,以提高性能。
<twig:UXTable:Table :table="projectsTable">
我们使用 UX Table Twig 组件,这是一个非常精简的组件,确保一切都被包裹在 stimulus 控制器、turbo frame 和表单标签中
<twig:UXTable:SortLink :table="projectsTable" title="Name" field="name" />
这里我们利用 SortLink Twig 组件生成一个保留 UX 表状态的查询参数的链接。
<twig:UXTable:Filter :table="projectsTable" filter="name" />
这里我们利用 Filter Twig 组件显示该过滤器的表单字段。
数据提供者
默认情况下,此包依赖于 DoctrineORMProvider 以自动查询数据库。
如果您想使用自定义填充,可以为 DoctrineORMProvider 配置填充器
protected function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setDefaults([ 'data_class' => \App\Entity\Project::class, 'hydrator' => function (array $project) { return new \App\ReadModel\Project($project['id'], $project['name']); }, 'sortable_fields' => ['name'], ]); }
您也可以通过创建一个实现 WeDevelop\UXTable\DataProvider\DataProviderInterface
的类来创建自己的数据提供者。
final class ProjectsProvider implements DataProviderInterface { public function __construct( private readonly ApiClient $api, private readonly PaginatorInterface $paginator, ) { } public function search( array $filters = [], array $sort = [], int $page = 1, int $pageSize = 50, array $options = [] ): PaginationInterface { $status = $options['status']; $projects = $this->api->getProjects($status, $filters, $sort, $page, $pageSize); return $this->paginator->paginate($projects, $page, $pageSize, [PaginatorInterface::PAGE_OUT_OF_RANGE => PaginatorInterface::PAGE_OUT_OF_RANGE_THROW_EXCEPTION]); } public function configureOptions(OptionsResolver $resolver): void { $resolver ->define('status')->allowedTypes(ProjectStatus::class)->required() ; } }
这里我们还定义了一个可以传递给 process 函数的状态选项
$projectsTable->process($request, options: ['status' => 'active']);