ashleydawson/simple-pagination

简单、轻量级且通用的服务,实现了对事物集合的分页

1.0.8 2019-01-17 12:38 UTC

This package is auto-updated.

Last update: 2024-09-19 07:01:39 UTC


README

Build Status

非常感谢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()等,因为我尽量使其尽可能简单。在实际应用中,请使用PDODoctrine 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>';