wwwision / relay-pagination
实现 Cursor Connections 规范的简单分页,请参阅 https://relay.graphql.net.cn/graphql/connections.htm
Requires
- php: >= 8.1
- webmozart/assert: ^1.10
Requires (Dev)
- phpunit/phpunit: ^9
Suggests
- doctrine/dbal: To make use of the DbalLoader
- doctrine/orm: To make use of the OrmLoader
README
实现 Cursor Connections 规范的简单分页,请参阅 https://relay.graphql.net.cn/graphql/connections.htm
安装
通过 composer 安装
composer require wwwision/relay-pagination
使用
$loader = # ... instance of \Wwwision\RelayPagination\Loader\Loader $resultsPerPage = 5; // edges to load per page $paginator = new Paginator($loader); $firstPage = $paginator->first($resultsPerPage); foreach ($firstPage as $edge) { // $edge->cursor; contains the cursor string // $edge->node; contains the payload } // $firstPage->pageInfo; contains an object with pagination information
下一页
每个 connection
都包含关于下一页和上一页的信息。要导航到下一页,可以将前一个连接的 endCursor
作为 after
参数的输入
if ($firstPage->pageInfo->hasNextPage) { $secondPage = $paginator->first($resultsPerPage, $firstPage->pageInfo->endCursor); // ... }
向后导航
要导航到前一页,可以将 startCursor
传递给 last()
方法
if ($secondPage->pageInfo->hasPreviousPage) { $firstPage = $paginator->last($resultsPerPage, $secondPage->pageInfo->startCursor); // ... }
反转顺序
无论使用向前还是向后导航,边的顺序都相同(如规范中定义的 所定义)。要按 反转 顺序导航结果,可以使用 Paginator
的 reversed()
方法
$loader = new ArrayLoader(range('a', 'e')); $paginator = (new Paginator($loader))->reversed(); $page1 = $paginator->first(3); Assert::same(['e', 'd', 'c'], array_map(fn($edge) => $edge->node, $page1->toArray())); Assert::false($page1->pageInfo->hasPreviousPage); Assert::true($page1->pageInfo->hasNextPage); $page2 = $paginator->first(3, $page1->pageInfo->endCursor); Assert::same(['b', 'a'], array_map(fn($edge) => $edge->node, $page2->toArray())); Assert::true($page2->pageInfo->hasPreviousPage); Assert::false($page2->pageInfo->hasNextPage);
加载器
此包包含四个适配器(即“加载器”)
ArrayLoader
ArrayLoader
允许对任意数组进行分页。注意:此加载器主要用于测试和调试目的,不应用于大型数据集,因为显然必须将整个数组加载到内存中。
使用
$arrayLoader = new ArrayLoader($arbitraryArray);
注意:指定的数组可以是关联数组,但在分页过程中键将丢失,因为 ArrayLoader 只使用数组值以保证确定性排序。
CallbackLoader
CallbackLoader
调用闭包以确定分页结果。注意:此加载器主要用于快速开发、测试和调试目的。通常,您会希望创建一个自定义的 Loader 接口实现
使用
$callbackLoader = new CallbackLoader( fn(int $limit, string $startCursor = null) => Edges::fromRawArray(...), fn(int $limit, string $endCursor = null) => Edges::fromRawArray(...) );
DbalLoader
DbalLoader
允许对任意 DBAL 结果进行分页。注意:此加载器需要安装 doctrine/dbal
包
composer require doctrine/dbal
使用
$queryBuilder = (new QueryBuilder($dbalConnection)) ->select('*') ->from('some_table'); $dbalLoader = new DbalLoader($queryBuilder, 'id');
OrmLoader
OrmLoader
允许对任意 Doctrine ORM 结果进行分页。注意:此加载器需要安装 doctrine/orm
包
composer require doctrine/orm
使用
$queryBuilder = $entityManager->createQueryBuilder() ->select('e') ->from(SomeEntity::class, 'e'); $ormLoader = new OrmLoader($queryBuilder, 'id');
转换节点
在包中,node
是唯一的无类型属性,因为加载器定义了节点的结构与类型。对于 DbalLoader
,节点是一个关联数组,包含来自相应数据库行的原始结果,例如。
为了更容易重用加载器,可以指定一个 Node Converter
,该转换器应用于返回之前的所有结果
$paginator = (new Paginator($someLoader)) ->withNodeConverter(fn(string $node) => json_decode($node));
上述示例假设节点包含有效的 JSON 字符串。可以采用相同的机制将数据库结果转换为特定的领域模型实例
$paginator = (new Paginator($dbalLoader)) ->withNodeConverter(fn(array $row) => MyModel::fromDatabaseRow($row));