lampager / lampager-cakephp
CakePHP 5 的快速分页
Requires
- php: ^8.1
- cakephp/cakephp: ^5.0
- lampager/lampager: ^0.4
Requires (Dev)
- nilportugues/sql-query-formatter: ^1.2
- phpunit/phpunit: ^10.1
README
CakePHP 的 Lampager
无需使用 OFFSET 的快速分页
要求
- PHP: ^8.1
- CakePHP: ^5.0
- lampager/lampager: ^0.4
注意
- 对于 CakePHP 2.x,请使用 lampager/lampager-cakephp2。
- 对于 CakePHP 3.x,请使用 lampager/lampager-cakephp v1.x。
- 对于 CakePHP 4.x,请使用 lampager/lampager-cakephp v2.x。
- 对于 CakePHP 5.x,请使用 lampager/lampager-cakephp v3.x(此版本)。
安装
composer require lampager/lampager-cakephp:^3.0
对于 SQLite 用户,请参阅 SQLite 进行配置。
基本用法
简单地将它作为 Composer 包安装,并在以下方法之一中使用它
- 在控制器中使用(通过
\Lampager\Cake\Datasource\Paginator
) - 在表中使用(通过
\Lampager\Cake\Model\Behavior\LampagerBehavior
)
在控制器中使用
首先,在您的控制器类中配置 $paginate
以使用 \Lampager\Cake\Datasource\Paginator
。
namespace App\Controller; use Cake\Controller\Controller; use Lampager\Cake\Datasource\Paginator; class AppController extends Controller { public $paginate = [ 'className' => Paginator::class, ]; }
使用烹饪书中的描述: 分页。注意 Lampager 的特定选项,如 forward
、seekable
或 cursor
。
$query = $this->Posts ->where(['Posts.type' => 'public']) ->orderByDesc('created') ->orderByDesc('id') ->limit(10); $posts = $this->paginate($query, [ 'forward' => true, 'seekable' => true, 'cursor' => [ 'id' => 4, 'created' => '2020-01-01 10:00:00', ], ]); $this->set('posts', $posts);
在表中使用
在您的表类(建议使用 AppTable
)中初始化 LampagerBehavior
并简单使用 lampager()
。
namespace App\Model\Table; use Cake\ORM\Table; use Lampager\Cake\Model\Behavior\LampagerBehavior; class AppTable extends Table { public function initialize(array $config): void { parent::initialize($config); $this->addBehavior(LampagerBehavior::class); } }
查询构建器(\Lampager\Cake\ORM\Query
)扩展了普通的 \Cake\ORM\Query
并与 \Lampager\Paginator
混合。请注意,\Lampager\Paginator
中的某些方法,如 orderBy()
、orderByDesc()
和 clearOrderBy()
,没有公开,因为它们的签名与 CakePHP 查询构建器不兼容。
$cursor = [ 'id' => 4, 'created' => '2020-01-01 10:00:00', 'modified' => '2020-01-01 12:00:00', ]; /** @var \Lampager\Cake\PaginationResult $latest */ $latest = $this->lampager() ->forward() ->seekable() ->cursor($cursor) ->limit(10) ->orderByDesc('Posts.modified') ->orderByDesc('Posts.created') ->orderByDesc('Posts.id') ->paginate(); foreach ($latest as $post) { /** @var \Cake\ORM\Entity $post */ debug($post->id); debug($post->created); debug($post->modified); }
CakePHP 查询构建器的方法,例如 where()
,是可用的。也接受 \Cake\Database\Expression\QueryExpression
。
/** @var \Lampager\Cake\PaginationResult $drafts */ $drafts = $this->lampager() ->where(['type' => 'draft']) ->forward() ->seekable() ->cursor($cursor) ->limit(10) ->orderByDesc($this->selectQuery()->newExpr('modified')) ->orderByDesc($this->selectQuery()->newExpr('created')) ->orderByDesc($this->selectQuery()->newExpr('id')) ->paginate(); /** @var \Cake\ORM\Entity $sample */ $sample = $drafts->sample(); /** @var int $count */ $count = $drafts->count();
类
另请参阅: lampager/lampager。
API
另请参阅: lampager/lampager。
LampagerBehavior::lampager()
以与 CakePHP 完全相同的方式从表中构建 Lampager 查询。
LampagerBehavior::lampager(): \Lampager\Cake\ORM\Query
Paginator::__construct()
Paginator::create()
创建一个新的分页器实例。这些方法不打算直接在您的代码中使用。
static Paginator::create(\Cake\ORM\Query\SelectQuery $builder): static Paginator::__construct(\Cake\ORM\Query\SelectQuery $builder)
Paginator::transform()
将 Lampager 查询转换为 CakePHP 查询。
Paginator::transform(\Lampager\Query $query): \Cake\ORM\Query\SelectQuery
Paginator::build()
执行配置 + 转换。
Paginator::build(\Lampager\Contracts\Cursor|array $cursor = []): \Cake\ORM\Query\SelectQuery
Paginator::paginate()
执行配置 + 转换 + 处理。
Paginator::paginate(\Lampager\Contracts\Cursor|array $cursor = []): \Lampager\Cake\PaginationResult
参数
(mixed)
$cursor
包含$column => $value
的关联数组或实现\Lampager\Contracts\Cursor
的对象。它必须是 全部或无。- 对于第一页,省略此参数或传递一个空数组。
- 对于后续页面,传递所有参数。不允许部分参数。
返回值
例如,
(使用 \Cake\ORM\Query
的默认格式时)
object(Lampager\Cake\PaginationResult)#1 (6) { ["(help)"]=> string(44) "This is a Lampager Pagination Result object." ["records"]=> array(3) { [0]=> object(Cake\ORM\Entity)#2 (11) { ... } [1]=> object(Cake\ORM\Entity)#3 (11) { ... } [2]=> object(Cake\ORM\Entity)#4 (11) { ... } ["hasPrevious"]=> bool(false) ["previousCursor"]=> NULL ["hasNext"]=> bool(true) ["nextCursor"]=> array(2) { ["created"]=> object(Cake\I18n\Time)#5 (3) { ["date"]=> string(26) "2017-01-01 10:00:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } ["id"]=> int(1) } }
PaginationResult::__call()
\Lampager\Cake\PaginationResult
实现 \Cake\Datasource\Paging\PaginatedInterface
。
示例
本节描述了 lampager-cakephp 的实际用法。
在控制器中使用
下面的示例显示了如何从请求中接受一个游标参数并将其通过 PaginatorComponent::paginate()
传递。请确保您的 AppController
正确初始化了 Paginator
,如上所述。
namespace App\Controller; class PostsController extends AppController { public $Posts = null; /** * This method shows how to pass options by a query and array. */ public function query(): void { // Get cursor parameters $previous = json_decode($this->request->getQuery('previous_cursor'), true); $next = json_decode($this->request->getQuery('next_cursor'), true); $cursor = $previous ?: $next ?: []; // Query expression can be passed to PaginatorComponent::paginate() as normal $query = $this->Posts ->where(['Posts.type' => 'public']) ->orderByDesc('created') ->orderByDesc('id') ->limit(15); /** @var \Lampager\Cake\PaginationResult<\Cake\ORM\Entity> $posts */ $posts = $this->paginate($query, [ // If the previous_cursor is not set, paginate forward; otherwise backward 'forward' => !$previous, 'cursor' => $cursor, 'seekable' => true, ]); $this->set('posts', $posts); } /** * This method shows how to pass options from an array. */ public function options(): void { // Get cursor parameters $previous = json_decode($this->request->getQuery('previous_cursor'), true); $next = json_decode($this->request->getQuery('next_cursor'), true); $cursor = $previous ?: $next ?: []; /** @var \Lampager\Cake\PaginationResult<\Cake\ORM\Entity> $posts */ $posts = $this->paginate('Posts', [ // Lampager options // If the previous_cursor is not set, paginate forward; otherwise backward 'forward' => !$previous, 'cursor' => $cursor, 'seekable' => true, // PaginatorComponent config 'conditions' => [ 'type' => 'public', ], 'order' => [ 'created' => 'DESC', 'id' => 'DESC', ], 'limit' => 15, ]); $this->set('posts', $posts); } }
分页链接可以按以下方式输出
// If there is a next page, print pagination link if ($posts->hasPrevious) { echo $this->Html->link('<< Previous', [ 'controller' => 'posts', 'action' => 'index', '?' => [ 'previous_cursor' => json_encode($posts->previousCursor), ], ]); } // If there is a next page, print pagination link if ($posts->hasNext) { echo $this->Html->link('Next >>', [ 'controller' => 'posts', 'action' => 'index', '?' => [ 'next_cursor' => json_encode($posts->nextCursor), ], ]); }
支持的数据库引擎
MySQL、MariaDB 和 PostgreSQL
支持!
Microsoft SQL Server
不支持。
SQLite
支持但需要额外的配置。
在SQLite中,UNION ALL
语句不能结合带有ORDER BY
子句的SELECT
语句。为了使其工作,这些SELECT
语句必须被一个子查询包裹,例如SELECT * FROM (...)
。CakePHP没有原生处理这种情况,Lampager for CakePHP引入了\Lampager\Cake\Database\Driver\Sqlite
,需要在您的应用程序中安装。在您的config/app.php
中进行如下配置
return [ 'Datasources' => [ 'default' => [ 'className' => Connection::class, 'driver' => \Lampager\Cake\Database\Driver\Sqlite::class, 'username' => '********', 'password' => '********', 'database' => '********', ], ], ];