esi / pagination
简单、轻量且通用的服务,用于实现事物集合的分页。
Requires
- php: ^8.2 <8.5
Requires (Dev)
- ext-pdo: *
- ext-pdo_sqlite: *
- friendsofphp/php-cs-fixer: dev-master
- phpstan/phpstan: ^1.11
- phpstan/phpstan-phpunit: ^1.4
- phpstan/phpstan-strict-rules: ^1.6
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2024-09-22 11:34:42 UTC
README
实现事物集合分页接口的分页库。
鸣谢
此库是AshleyDawson\SimplePagination
(https://github.com/AshleyDawson/SimplePagination)库的分支,由Ashley Dawson
(https://github.com/AshleyDawson)创建。
要查看与原始库相比此库中更改的列表,请参阅CHANGELOG.md文件。
安装
您可以通过Composer安装Pagination。为此,只需在您的composer.json
文件中require
该包即可,如下所示
{ "require": { "esi/pagination": "^2.0" } }
然后运行composer update
来安装包。
Pagination的工作原理
我尽量使Pagination尽可能简单、灵活和易于使用。Pagination的操作由四个主要元素描述。这些是
- Paginator服务
- 项目总数回调
- 切片回调
- 分页模型
Paginator服务执行分页算法,生成页面范围和项目集合切片。完成时,它将返回一个包含项目集合切片和元数据的Pagination对象。
Paginator服务对您的集合(或数据集)执行的两个主要操作由传递给Paginator服务的两个回调方法表示。第一个是项目总数回调。此回调用于确定您的集合中的项目总数(以整数形式返回)。第二个是切片回调。此回调根据提供的偏移量和长度参数实际切片您的集合。
使用这些回调的目的是使Pagination保持简单!真正的力量来自于灵活性。您可以使用Pagination与几乎任何您想要的集合一起使用。从简单的数组到数据库列表到Doctrine集合到Solr结果集 - 我们为您提供了所有这些!实际上,我们分页的内容并不重要 - 只要它是事物集合,并且您可以计数和切片它。
基本用法
好吧,让我们从最基本的例子开始 - 对数组进行分页。
use Esi\Pagination\Paginator; // Build a mock list of items we want to paginate through. $items = [ 'Banana', 'Apple', 'Cherry', 'Lemon', 'Pear', 'Watermelon', 'Orange', 'Grapefruit', 'Blackcurrant', 'Dingleberry', 'Snosberry', 'Tomato', ]; // Instantiate a new paginator service. $paginator = new Paginator(); // Set some parameters (optional). $paginator ->setItemsPerPage(10) // Give us a maximum of 10 items per page. ->setPagesInRange(5) // How many pages to display in navigation (e.g. if we have a lot of pages to get through). ; // Pass our item total callback. $paginator->setItemTotalCallback(function () use ($items): int { return count($items); }); // Pass our slice callback. $paginator->setSliceCallback(function (int $offset, int $length) use ($items): array { return array_slice($items, $offset, $length); }); // Paginate the item collection, passing the current page number (e.g. from the current request). $pagination = $paginator->paginate(filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT)); // Ok, from here on is where we'd be inside a template of view (e.g. pass $pagination to your view). // Iterate over the items on this page. foreach ($pagination->getItems() as $item) { echo $item . '<br />'; } // Let's build a basic page navigation structure. foreach ($pagination->getPages() as $page) { echo '<a href="?page=' . $page . '">' . $page . '</a> '; }
在分页对象中还有许多其他元数据。这些可以用于构建第一、最后、上一页和下一页按钮。
MySQL示例
让我们以上面的例子为基础,使用MySQL结果集而不是数组。
use Esi\Pagination\Paginator; // Instantiate a new paginator service. $paginator = new Paginator(); // Set some parameters (optional). $paginator ->setItemsPerPage(10) // Give us a maximum of 10 items per page. ->setPagesInRange(5) // How many pages to display in navigation (e.g. if we have a lot of pages to get through). ; // Connect to a database. $mysql = new mysqli('localhost', 'root', 'password', 'myDatabase'); // Pass our item total callback. $paginator->setItemTotalCallback(function () use($mysql): int { // Run count query. $result = $mysql->query("SELECT COUNT(*) AS `totalCount` FROM `TestData`"); $row = $result->fetch_array(MYSQLI_ASSOC); // Return the count, cast as an integer. return (int) $row['totalCount']; }); // Pass our slice callback. $paginator->setSliceCallback(function (int $offset, int $length) use ($mysql): array { // Run slice query. $result = $mysql->query("SELECT `Name` FROM `TestData` LIMIT $offset, $length"); // Build a collection of items. $collection = []; while ($row = $result->fetch_assoc()) { $collection[] = $row; } // Return the collection. return $collection; }); // Paginate the item collection, passing the current page number (e.g. from the current request). $pagination = $paginator->paginate(filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT)); // Ok, from here on is where we'd be inside a template of view (e.g. pass $pagination to your view). // Iterate over the items on this page. foreach ($pagination->getItems() as $item) { echo $item['Name'] . '<br />'; } // Let's build a basic page navigation structure. foreach ($pagination->getPages() as $page) { echo '<a href="?page=' . $page . '">' . $page . '</a> '; }
注意:上面的例子使用了mysqli
等,因为我尽量使其尽可能简单。在现实世界中,请使用PDO、Doctrine DBAL等。
您不需要从Paginator::setSliceCallback()回调返回什么样的集合。它最终都会出现在Pagination::getItems()中。
构造函数配置
您还可以通过将配置数组传递给构造函数来配置分页器。例如
$paginator = new Paginator([ 'itemTotalCallback' => function () { // ... }, 'sliceCallback' => function (int $offset, int $length) { // ... }, 'itemsPerPage' => 10, 'pagesInRange' => 5, ]);
分页作为迭代器
从 Paginator
服务返回的 Pagination
对象实现了 \IteratorAggregate
和 \Countable
,因此您可以在视图中进行如下操作
if (count($pagination) > 0) { foreach ($pagination as $item) { echo $item . '<br />'; } }
任意的分页元数据
在项目总数和切片回调期间,您可以选择将任意元数据传递给分页对象。这是一个可选功能,如果您有一个使用场景,其中这些操作返回额外的数据,并且您想在列出项目时访问它,则非常有用。一个很好的例子是在使用搜索引擎(如 ElasticSearch)时,您可以传递回二级信息,如聚合等。下面是一个通用示例
use Esi\Pagination\Pagination; // ... $paginator->setItemTotalCallback(function (Pagination $pagination) use ($items): int { // Pass arbitrary metadata to pagination object. $pagination->setMeta(['my', 'meta', 'data']); return count($items); }); $paginator->setSliceCallback(function (int $offset, int $length, Pagination $pagination) use ($items): array { // Pass more arbitrary metadata to pagination object. $pagination->setMeta(array_merge($pagination->getMeta(), ['more', 'stuff'])); return array_slice($items, $offset, $length); }); // ... // Perform the pagination $pagination = $paginator->paginate(filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT)); // Get the metadata from the pagination object. var_dump($pagination->getMeta());
查询前后回调
在计数和切片查询之前和之后,您可以设置触发回调。要设置它们,请执行以下操作
$paginator->setBeforeQueryCallback(function (Paginator $paginator, Pagination $pagination) { }); $paginator->setAfterQueryCallback(function (Paginator $paginator, Pagination $pagination) { });
如果您想在每次查询前后执行某些功能,这将非常有用。
分页对象
Paginator::paginate()
操作的结果是生成一个 Pagination
模型对象,它携带当前页的项目集合以及集合的元信息,例如页面数组、下一页编号、上一页编号等。
以下列出 Pagination
对象具有的属性列表。
- items : 数组(当前页的项目集合)
- pages : 数组(当前范围内的页面编号数组)
- totalNumberOfPages : int(总页数)
- currentPageNumber : int(当前页码)
- firstPageNumber : int(第一页码)
- lastPageNumber : int(最后一页码)
- previousPageNumber : int | null(上一页码)
- nextPageNumber : int | null(下一页码)
- itemsPerPage : int(每页项目数)
- totalNumberOfItems : int(项目总数)
- firstPageNumberInRange : int(当前范围内的第一页码)
- lastPageNumberInRange : int(当前范围内的最后一页码)
使用 Pagination
对象的一个好例子是构建一个简单的分页导航结构
// Render the first page link, echo '<a href="?page=' . $pagination->getFirstPageNumber() . '">First Page</a> '; // Render the previous page link (note: the previous page number could be null), echo '<a href="?page=' . $pagination->getPreviousPageNumber() . '">Previous Page</a> '; // Render page range links, foreach ($pagination->getPages() as $page) { echo '<a href="?page=' . $page . '">' . $page . '</a> '; } // Render the next page link (note: the next page number could be null), echo '<a href="?page=' . $pagination->getNextPageNumber() . '">Next Page</a> '; // Render the last page link, echo '<a href="?page=' . $pagination->getLastPageNumber() . '">Last Page</a>';
关于
要求
- 分页与 PHP 8.2.0 或更高版本兼容。
提交错误和功能请求
错误和功能请求在 GitHub 上跟踪
问题是最快报告错误的途径。如果您发现错误或文档错误,请首先检查以下内容
- 没有关于错误的已打开问题
- 问题尚未被解决(例如,在已关闭的问题中)
贡献
请参阅 CONTRIBUTING
作者
Eric Sizemore - admin@secondversion.com - https://www.secondversion.com
许可
分页采用 MIT 许可证 - 详细信息请参阅 LICENSE.md 文件