germania-kg/pagination

分页你的可遍历对象

1.0.4 2022-03-30 10:04 UTC

This package is auto-updated.

Last update: 2024-08-29 04:54:43 UTC


README

Packagist PHP version Build Status Scrutinizer Code Quality Code Coverage Build Status

使用Composer安装

$ composer require germania-kg/pagination

概览

分页:简单的分页!支持当前页、下一页、上一页、第一页最后一页页码,以及总页数和可自定义的每页大小

PaginationFactory:用于创建Pagination实例的可调用类。与$_GET['page']配合使用效果极佳

PaginationIterator:根据Pagination状态限制你的可遍历对象。对于分页的JSON API资源非常有用。

JsonApiPaginationDecorator:为你的JSON API资源集合创建有用的linksmeta信息。

用法

Pagination 类

只需传递要分页的项目数量。默认页大小为25, Pagination类将计算页码。下面有自定义示例。

<?hpp
use Germania\Pagination\Pagination;

$items_count = 100; // count( $things ) or integer;
$pagination = new Pagination( $items_count );

$pagination->getPagesCount(); // 4, with 25 items each
$pagination->getFirst(); // 0
$pagination->getLast(); // 3

分页状态

在实例化后,用户没有选择任何页面。因此,Pagination被认为是非活动状态

请注意,当前页也可能为int(0) - 第一页。这就是为什么我们必须检查null的原因。 isActive方法是一个方便的别名,即$p->getCurrent() === null

$pagination->isActive();    // FALSE

$pagination->getCurrent();  // null
$pagination->getPrevious(); // null
$pagination->getNext();     // null

它首先需要调用setCurrent来变为活动状态

设置当前页

use Germania\Pagination\PaginationRangeException;

try {
  $pagination->setCurrent( 1 );
  
  $pagination->isActive();    // TRUE
  $pagination->getCurrent();  // 1  
  $pagination->getPrevious(); // null
  $pagination->getNext();     // 2  
}
catch ( PaginationRangeException $e )
{
  echo $e->getMessage(); // "Invalid Page number"
  echo $e->getCode();    // 400
}

设置页大小

虽然默认每页项目数为25,但你可以设置另一个大小——默认为100

use Germania\Pagination\PaginationRangeException;

try {
	$pagination = new Pagination( $items_count );  
	$pagination->getPageSize(); // 25
	$pagination->setPageSize( 999 );  
}
catch ( PaginationRangeException $e ) 
{
  echo $e->getMessage(); // "Invalid Page size (max. 100)"
  echo $e->getCode();    // 400
}

通过构造函数参数调整页大小

$custom_page_size =  50; // default: 25
$pagination = new Pagination( $items_count, $custom_page_size );

$max_page_size    = 200; // default: 100
$pagination = new Pagination( $items_count, $custom_page_size, $max_page_size );

PaginationFactory

PaginationFactory的构造函数还接受CountableTraversablearrays的实例,因此你不需要自己计数项目。第二个参数可以是页码整数或包含number和/或size值的数组。

<?php
use Germania\Pagination\PaginationFactory;

// Optinally set default page size
$factory = new PaginationFactory;
$factory = new PaginationFactory( 25 );

// Most simple: just integers
$items_count = 65;
$choose_page = 2;

// Create Pagination instance:
$pagination = $factory( $items_count, $choose_page );

从数组创建在处理查询参数(如$_GET['page'])时非常有用

// Both elements are optional.
$pagination = $factory( $items_count, [
	'number' => 2, // default: 0
  'size'   => 20
]);

// User Input
$pagination = $factory( $items_count, $_GET['page'] ?? [] );

PaginationIterator

根据分页状态将任何\Traversable迭代器限制为当前页大小。 PaginationIterator的构造函数接受你的迭代器和你的分页实例。它也是\Countable,可以计算当前页显示的项目数量。

<?php
use Germania\Pagination\PaginationIterator;

// Have your pagination at hand...
$pagination = ...
$pagination->setCurrent(2);

// Setup something really big
$collection = new MyHugeIterator( $thousand_items );

$paginated_collection = new PaginationIterator( $collection, $pagination );
echo count( $paginated_collection ); // 25

foreach( $paginated_collection as $item):
  // loop: 25 items on page 2
endforeach;

使用哪个迭代器?

根据分页状态,在foreach循环中使用的PaginationIterator的内部迭代器是\LimitIterator还是当分页不是活动状态时MyHugeIterator实例本身

// this time, we do not pick a page number!
$thousand_items = ...
$pagination = new Pagination( count($thousand_items) );
$pagination->isActive(); // null

$collection = new MyHugeIterator( $thousand_items );

$paginated_collection = new PaginationIterator( $collection, $pagination );
$iterator = $paginated_collection->getIterator();

get_class( $iterator ); // MyHugeIterator instance

JsonApiPaginationDecorator

这个库提供了一个方便的JsonApiPaginationDecorator,它将使用给定的\Psr\Http\Message\UriInterface实例生成有用的信息,用于你的JSON API资源集合响应。

支持元信息

可以使用meta成员包含非标准元信息,如我们的分页

$pagination->setCurrent( 16 );
$pagination->setPageSize( 10 );

$links = $ja_decorator->getMeta();
// array(
//     numberOfPages => 23
//     currentPage   => 16
//     pageSize      => 10
// )

当分页不是活动状态时,结果数组将为空

支持链接对象

fetching pagination 部分的 JSON API specs 提议使用 page[number]page[size] 来自定义分页输出。并且它指出,在使用分页链接时,集合中的 links 对象必须使用这些键名。

  • first:数据的第一个页面
  • last:数据的最后一个页面
  • prev:前一个数据页面
  • next:下一个数据页面

JsonApiPaginationDecorator 为您生成这些元素。这个类也是 \JsonSerializable

<?php
use Germania\Pagination\JsonApiPaginationDecorator;

// Prepare dependencies
$uri = \GuzzleHttp\Psr7\uri_for('http://example.com');
$pagination = ...
$pagination->setCurrent( 2 );

new $ja_decorator = new JsonApiPaginationDecorator( $pagination, $uri);

// These are equivalent:
$links = $ja_decorator->getLinks();
$links = $ja_decorator->jsonSerialize();

// array(
//     first    => http://example.com/?page[number]=0
//     last     => http://example.com/?page[number]=42
//     previous => http://example.com/?page[number]=1
//     next     => http://example.com/?page[number]=3
// )
默认查询参数

JsonApiPaginationDecorator 在内部会调用 PSR-7 $uri 实例的 withQuery 方法。不幸的是,这将会替换 URI 中包含的任何查询参数。只需将需要的查询参数作为第三个构造函数参数传递即可。

$params = array(
	'foo'  => 'bar',
  'json' => 'cool'
);
new $ja_decorator = new JsonApiPaginationDecorator( $pagination, $uri, $params);

$links = $ja_decorator->getLinks();
// array(
//     first    => http://example.com/?page[number]=0&foo=bar&json=cool
//     last     => http://example.com/?page[number]=42&foo=bar&json=cool
//     previous => http://example.com/?page[number]=1&foo=bar&json=cool
//     next     => http://example.com/?page[number]=3&foo=bar&json=cool
// )
自定义页面大小

如果您设置了自定义的页面大小(与默认大小不同),链接将获得一个额外的 size 字段。

$pagination->setPageSize( 10 );

$links = $ja_decorator->getLinks();
// array(
//     first    => http://example.com/?page[number]=0&page[size]=10
//     last     => http://example.com/?page[number]=42&page[size]=10
//     previous => http://example.com/?page[number]=1&page[size]=10
//     next     => http://example.com/?page[number]=3&page[size]=10
// )
边缘情况

在第一页和最后一页,previousnext 链接没有意义。它们的值将是 null

$pagination = new Pagination (...);
new $ja_decorator = new JsonApiPaginationDecorator( $pagination, $uri);

$pagination->setCurrent( 0 );
$links = $ja_decorator->getLinks();
// array(
//     ...
//     previous => null
//     next     => http://example.com/?page[number]=1
// )

$pagination->setCurrent( 42 );
$links = $ja_decorator->getLinks();
// array(
//     ...
//     previous => http://example.com/?page[number]=41
//     next     => null
// )

当分页不活跃时,所有默认值都是 null

$pagination = new Pagination (...);
$pagination->isActive(); // FALSE

$ja_decorator->getLinks();
// array(
//     first    => null
//     last     => null
//     previous => null
//     next     => null
// )
过滤结果

为了得到一个干净、整洁的 links 数组,您可以将一个布尔值 filter 标志作为第四个构造函数参数传递。

$filter = true;
new $ja_decorator = new JsonApiPaginationDecorator( $pagination, $uri, [], $filter);

$ja_decorator->getLinks();
// array()

问题

请参阅 完整问题列表。

开发

$ git clone https://github.com/GermaniaKG/Pagination.git
$ cd Pagination
$ composer install

单元测试

您可以选择将 phpunit.xml.dist 复制到 phpunit.xml 并根据您的需求进行适配,或者保持原样。运行 PhpUnit 测试或 composer 脚本,如下所示

$ composer test
# or
$ vendor/bin/phpunit