分页

CodeIgniter 提供了一个非常简单但灵活的分页库,它易于主题化,与模型一起工作,并且能够在一个页面上支持多个分页器。

加载库

与 CodeIgniter 中的所有服务一样,它可以通过 Config\Services 加载,但您通常不需要手动加载它。

<?php

$pager = \Config\Services::pager();

使用模型进行分页

在大多数情况下,您将使用 Pager 库来对从数据库检索的结果进行分页。当使用 模型 类时,您可以使用其内置的 paginate() 方法自动检索当前批次的结果,并设置 Pager 库,使其在您的控制器中可以使用。它甚至会通过 page=X 查询变量从当前 URL 读取它应该显示的当前页面。

为了在您的应用程序中提供分页的用户列表,您的控制器方法应该类似于以下示例:

<?php

namespace App\Controllers;

class UserController extends BaseController
{
    public function index()
    {
        $model = new \App\Models\UserModel();

        $data = [
            'users' => $model->paginate(10),
            'pager' => $model->pager,
        ];

        return view('users/index', $data);
    }
}

在这个例子中,我们首先创建一个新的 UserModel 实例。然后,我们填充要发送到视图的数据。第一个元素是来自数据库的结果,即 **users**,它是在正确页面检索到的,每页返回 10 个用户。必须发送到视图的第二个项目是 Pager 实例本身。为了方便起见,模型将保留它使用的实例,并将其存储在公共属性 $pager 中。因此,我们获取它并将其分配给视图中的 $pager 变量。

自定义分页查询

要在模型中自定义分页查询,您可以在 paginate() 方法之前添加 查询构建器 方法。

添加 WHERE

如果您想添加 WHERE 条件,您可以直接指定条件

// In your Controller.
$model = new \App\Models\UserModel();

$data = [
    'users' => $model->where('ban', 1)->paginate(10),
    'pager' => $model->pager,
];

您可以将条件移到单独的方法中

<?php

namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    // ...

    public function banned()
    {
        $this->builder()->where('ban', 1);

        return $this; // This will allow the call chain to be used.
    }
}
// In your Controller.
$model = new \App\Models\UserModel();

$data = [
    'users' => $model->banned()->paginate(10),
    'pager' => $model->pager,
];

添加 JOIN

您可以加入另一个表

<?php

namespace App\Models;

use CodeIgniter\Model;

class NewsModel extends Model
{
    protected $table = 'news';

    // ...

    public function getPagination(?int $perPage = null): array
    {
        $this->builder()
            ->select('news.*, category.name')
            ->join('category', 'news.category_id = category.id');

        return [
            'news'  => $this->paginate($perPage),
            'pager' => $this->pager,
        ];
    }
}

重要

重要的是要理解 Model::paginate() 方法使用模型和模型中的查询构建器实例。因此,尝试将 Model::paginate()$db->query() 一起使用将不起作用,因为 $db->query() 会立即执行查询,并且与查询构建器无关。

如果您需要一个使用 Query Builder 无法编写的复杂 SQL 查询,请尝试使用 $db->query()手动分页

对多个结果进行分页

如果您需要从两个不同的结果集中提供链接,可以将组名称传递给大多数分页方法,以使数据保持分离。

<?php

namespace App\Controllers;

class UserController extends BaseController
{
    public function index()
    {
        $userModel = new \App\Models\UserModel();
        $pageModel = new \App\Models\PageModel();

        $data = [
            'users' => $userModel->paginate(10, 'group1'),
            'pages' => $pageModel->paginate(15, 'group2'),
            'pager' => $userModel->pager,
        ];

        echo view('users/index', $data);
    }
}
?>

<!-- In your view file: -->
<?= $pager->links('group1') ?>
<?= $pager->simpleLinks('group2') ?>

手动设置页面

如果您需要指定要返回的结果的页面,可以将页面作为第三个参数指定。当您使用与默认 $_GET 变量不同的方式来控制要显示的页面时,这将非常有用。

<?php

$userModel = new \App\Models\UserModel();
$page      = 3;

$users = $userModel->paginate(10, 'group1', $page);

指定页面的 URI 段

也可以使用 URI 段来表示页码,而不是页面查询参数。只需指定要使用的段号作为第四个参数即可。分页器生成的 URI 将看起来像 https://domain.tld/foo/bar/[pageNumber] 而不是 https://domain.tld/foo/bar?page=[pageNumber]

<?php

$users = $userModel->paginate(10, 'group1', null, $segment);

请注意:$segment 值不能大于 URI 段数加 1。

手动分页

您可能会发现,有时您只需要根据已知数据创建分页。您可以使用 makeLinks() 方法手动创建链接,该方法分别将当前页、每页结果数和项目总数作为第一个、第二个和第三个参数。

<?php

namespace App\Controllers;

class UserController extends BaseController
{
    public function index()
    {
        // ...

        $pager = service('pager');

        $page    = (int) ($this->request->getGet('page') ?? 1);
        $perPage = 20;
        $total   = 200;

        // Call makeLinks() to make pagination links.
        $pager_links = $pager->makeLinks($page, $perPage, $total);

        $data = [
            // ...
            'pager_links' => $pager_links,
        ];

        return view('users/index', $data);
    }
}
?>

<!-- In your view file: -->
<?= $pager_links ?>

默认情况下,这将以正常方式显示链接,作为一系列链接,但您可以通过传入模板名称作为第四个参数来更改使用的显示模板。更多详细信息可以在以下部分找到。

$pager->makeLinks($page, $perPage, $total, 'template_name');

也可以使用 URI 段来表示页码,而不是页码查询参数,如上一节所述。将要使用的段号指定为 makeLinks() 的第五个参数。

$pager->makeLinks($page, $perPage, $total, 'template_name', $segment);

请注意:$segment 值不能大于 URI 段数加 1。

如果您需要在一个页面上显示多个分页器,那么定义一个组的附加参数可能会有所帮助。

<?php

$pager = service('pager');
$pager->setPath('path/for/my-group', 'my-group'); // Additionally you could define path for every group.
$pager->makeLinks($page, $perPage, $total, 'template_name', $segment, 'my-group');

分页库默认情况下使用 page 查询参数进行 HTTP 查询(如果没有给出组名或 default 组名),或者使用 page_[groupName] 来表示自定义组名。

仅使用预期查询进行分页

默认情况下,所有 GET 查询都显示在分页链接中。

例如,当访问 URL https://domain.tld?search=foo&order=asc&hello=i+am+here&page=2 时,可以生成第 3 页链接以及其他链接,如下所示。

<?php

echo $pager->links();
// Page 3 link: https://domain.tld?search=foo&order=asc&hello=i+am+here&page=3

only() 方法允许您将此限制为仅限于已预期的查询。

<?php

echo $pager->only(['search', 'order'])->links();
// Page 3 link: https://domain.tld?search=foo&order=asc&page=3

page 查询默认情况下已启用。并且 only() 在所有分页链接中起作用。