ashleydawson / simple-pagination
简单、轻量级且通用的服务,实现了对事物集合的分页
Requires
- php: >=5.3.3
Requires (Dev)
- phpunit/phpunit: ^3.7
README
非常感谢BrowserStack支持此类开源项目。
Simple pagination library实现了对事物集合的分页接口。如果您想在Symfony 2项目中使用Simple Pagination,为什么不试试我的Simple Pagination Bundle呢。
安装
您可以通过Composer安装Simple Pagination。要做到这一点,只需在您的composer.json
文件中像这样require
包
{ "require": { "ashleydawson/simple-pagination": "~1.0" } }
然后运行composer update
来安装该包。
Simple Pagination的工作原理
我已经尽力使Simple Pagination尽可能易于使用和灵活。描述Simple Pagination操作有四个主要元素。这些是
- Paginator服务
- 项目总数回调
- 切片回调
- 分页模型
Paginator服务执行分页算法,生成页面范围和项目集合切片。完成时,它将返回一个填充了项目集合切片和元数据的Pagination对象。
Paginator服务将对您的集合(或数据集)执行两个主要操作,这两个操作由传递给Paginator服务的两个回调方法表示。第一个是项目总数回调。此回调用于确定您的集合中的项目总数(作为整数返回)。第二个是切片回调。此回调根据提供的偏移量和长度参数实际切片您的集合。
使用这些回调的目的是保持Simple Pagination简单!真正的力量来自灵活性。您可以使用Simple Pagination与几乎任何您想要的集合。从简单的数组到数据库列表,再到Doctrine集合和Solr结果集——我们都有!实际上,我们分页的内容并不重要——只要它是一个事物集合,并且您可以对其进行计数和切片。
基本用法
好吧,让我们从最基本示例开始——对数组进行分页。
use AshleyDawson\SimplePagination\Paginator; // Build a mock list of items we want to paginate through $items = array( '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) { return count($items); }); // Pass our slice callback $paginator->setSliceCallback(function ($offset, $length) use ($items) { return array_slice($items, $offset, $length); }); // Paginate the item collection, passing the current page number (e.g. from the current request) $pagination = $paginator->paginate((int) $_GET['page']); // 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 AshleyDawson\SimplePagination\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) ; // Pass our item total callback $paginator->setItemTotalCallback(function () { // Run count query $result = mysql_query("SELECT COUNT(*) FROM `TestData`"); // Return the count (the value of the first result column), cast as an integer return (int) mysql_result($result, 0); }); // Pass our slice callback $paginator->setSliceCallback(function ($offset, $length) { // Run slice query $result = mysql_query("SELECT `Name` FROM `TestData` LIMIT {$offset}, {$length}"); // Build a collection of items $collection = array(); while ($row = mysql_fetch_assoc($result)) { $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((int) $_GET['page']); // 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> '; }
注意:上面的示例使用了mysql_connect()
等,因为我尽量使其尽可能简单。在实际应用中,请使用PDO、Doctrine DBAL等。
实际上,您从Paginator::setSliceCallback()回调返回的集合类型并不重要。它最终都会出现在Pagination::getItems()中。
构造函数配置
您还可以通过向构造函数传递配置数组来配置分页器。例如:
$paginator = new Paginator(array( 'itemTotalCallback' => function () { // ... }, 'sliceCallback' => function ($offset, $length) { // ... }, 'itemsPerPage' => 10, 'pagesInRange' => 5 ));
分页作为迭代器
从分页器服务返回的分页对象实现了 \IteratorAggregate 和 \Countable,因此您可以在视图中执行如下操作
if (count($pagination) > 0) { foreach ($pagination as $item) { echo $item . '<br />'; } }
任意分页元数据
在项目总数和切片回调期间,您可以选择向分页对象传递任意元数据。这是一个可选功能,如果您有这些操作返回额外数据的使用场景,并且您希望在列出项目时访问这些数据,则很有用。一个好的例子是当使用像 ElasticSearch 这样的搜索引擎时,您可以传递回二级信息 - 如聚合等。以下是一个通用示例:
use AshleyDawson\SimplePagination\Pagination; // ... $paginator->setItemTotalCallback(function (Pagination $pagination) use ($items) { // Pass arbitrary metadata to pagination object $pagination->setMeta(['my', 'meta', 'data']); return count($items); }); $paginator->setSliceCallback(function ($offset, $length, Pagination $pagination) use ($items) { // 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((int) $_GET['page']); // 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() 操作的结果是生成一个分页模型对象,该对象携带当前页面的项目集合以及集合的元信息,例如页面数组、下一页号、上一页号等。请参见以下分页对象具有的属性列表。
- items : 混合型(当前页面的项目集合)
- pages : 数组(当前范围内的页面号数组)
- totalNumberOfPages : 整数(总页数)
- currentPageNumber : 整数(当前页码)
- firstPageNumber : 整数(第一页码)
- lastPageNumber : 整数(最后一页码)
- previousPageNumber : 整数 | null(上一页码)
- nextPageNumber : 整数 | null(下一页码)
- itemsPerPage : 整数(每页项目数)
- totalNumberOfItems : 整数(项目总数)
- firstPageNumberInRange : 整数(当前范围内的第一页码)
- lastPageNumberInRange : 整数(当前范围内的最后一页码)
使用分页对象的良好例子是构建简单的分页导航结构
// 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>';