wwwision/relay-pagination

实现 Cursor Connections 规范的简单分页,请参阅 https://relay.graphql.net.cn/graphql/connections.htm

1.2.1 2023-02-13 10:26 UTC

This package is auto-updated.

Last update: 2024-09-13 14:34:42 UTC


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);
  // ...
}

反转顺序

无论使用向前还是向后导航,边的顺序都相同(如规范中定义的 所定义)。要按 反转 顺序导航结果,可以使用 Paginatorreversed() 方法

$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));

示例

请参阅 示例测试 文件夹