后端微服务【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/gh_mirrors/hy/hyperf点击查看免费下载Hyperf 的hyperf/paginator是一个轻量、独立的分页组件只要你有数据集和分页需求就可以实例化Hyperf\Paginator\Paginator来完成分页处理它同样可以用于其他框架。本指南以官方文档为主线结合仓库源码带你掌握分页器的构造方式、全部核心方法、URL 生成机制、LengthAwarePaginator与游标分页的使用以及它与hyperf/database组件的集成方式。阅读完本文你将能够在控制器、查询构建器与模型中灵活实现带完整分页元数据的分页接口。安装分页组件是独立发布的包通过 Composer 即可安装composer require hyperf/paginator安装后组件会通过自身的ConfigProvider自动注册相关配置与监听器源码见 ConfigProvider.php无需手动修改任何配置文件。多数场景下分页器与数据库查询配合使用hyperf/database组件已经内置了对分页组件的适配查询数据时可直接使用分页能力详见 Database - Paginator。基本用法在控制器中手动分页只要有数据集和分页需求就可以实例化一个Hyperf\Paginator\Paginator类进行分页处理。其构造函数签名如下__construct($items, int $perPage, ?int $currentPage null, array $options [])$items数据集以「数组Array」或Hyperf\Collection\Collection集合类的形式传入$perPage每页数据量$currentPage当前页码可省略$options以「键-值」形式定义分页器实例的所有属性具体可参考分页器类内部属性下文详解。以下是一个完整的控制器示例从请求中读取page与per_page参数对内存中的集合数据完成分页并返回?php namespace App\Controller; use Hyperf\HttpServer\Annotation\AutoController; use Hyperf\HttpServer\Contract\RequestInterface; use Hyperf\Paginator\Paginator; use Hyperf\Collection\Collection; #[AutoController] class UserController { public function index(RequestInterface $request) { $currentPage (int) $request-input(page, 1); $perPage (int) $request-input(per_page, 2); // Perform query according to $currentPage and $perPage. The Collection type is used here. $collection new Collection([ [id 1, name Tom], [id 2, name Sam], [id 3, name Tim], [id 4, name Joe], ]); $users array_values($collection-forPage($currentPage, $perPage)-toArray()); return new Paginator($users, $perPage, $currentPage); } }这里先用集合的forPage($currentPage, $perPage)方法切出当前页数据再交给Paginator包装。Paginator本身在构造时也会对传入数据做一次切片从而保证实例内只保留当前页的数据。Paginator 核心方法详解Paginator的父类 AbstractPaginator.php 提供了绝大多数分页操作方法Paginator与LengthAwarePaginator共用这套实现。获取当前页码?php $currentPage $paginator-currentPage();获取当前页数据条数?php $count $paginator-count();从源码看该方法返回的是内部集合$this-items-count()即切片后的当前页条数并非总数据量。获取当前页第一个条目的序号?php $firstItem $paginator-firstItem();源码实现为($this-currentPage - 1) * $this-perPage 1当当前页为空时返回null。获取当前页最后一个条目的序号?php $lastItem $paginator-lastItem();源码实现为firstItem() count() - 1即「起始序号 当前页条数 - 1」页为空时返回null。判断是否还有下一页?php if ($paginator-hasMorePages()) { // ... }获取对应页面的 URL?php // URL of the next page $nextPageUrl $paginator-nextPageUrl(); // URL of the previous page $previousPageUrl $paginator-previousPageUrl(); // URL of the $page $url $paginator-url($page);nextPageUrl()仅当存在更多页时返回url($currentPage 1)否则返回nullpreviousPageUrl()仅当当前页大于 1 时返回url($currentPage - 1)否则返回nullurl($page)生成指定页码的完整 URL页码小于等于 0 时会被修正为 1。判断是否在第一页?php $onFirstPage $paginator-onFirstPage();源码实现为$this-currentPage() 1。获取每页数据条数?php $perPage $paginator-perPage();获取总条数注意Hyperf\Paginator\Paginator中没有total()方法需要使用Hyperf\Paginator\LengthAwarePaginator。?php $total $paginator-total();由于Paginator只接收「当前页切片数据」无法知道总数需要知道总条数时必须改用LengthAwarePaginator在构造时显式传入$total参数详见下文。构造参数与 options 深入解析从源码看Paginator构造函数Paginator.php依次完成以下工作保存$options并通过foreach ($options as $key $value) { $this-{$key} $value; }把每个键值直接赋值为实例属性——这正是文档所说「options 可以定义分页器实例的所有属性」的实现方式设置$perPage通过setCurrentPage()处理当前页若传入为空则回退到静态的resolveCurrentPage()解析结果且只有通过isValidPageNumber()要求 1且可通过FILTER_VALIDATE_INT校验的页码才会被采纳否则回退为 1对$path做规范化非/的路径会去掉末尾的/调用setItems()设置内部集合。setItems()的内部逻辑Paginator.php值得注意protected function setItems($items): void { $this-items $items instanceof Collection ? $items : Collection::make($items); $this-hasMore $this-items-count() $this-perPage; $this-items $this-items-slice(0, $this-perPage); }即无论传入数组还是集合都会被统一包装为Collection通过「传入数据条数 每页条数」来判断hasMore是否有更多页最后只保留前$perPage条数据作为当前页。这就是为什么你可以在传入完整数据集的情况下仍得到正确的hasMorePages()判断。$options中常用的键包括键类型作用默认值pathstring生成 URL 的基础路径/queryarray附加到所有 URL 的查询参数[]fragment?string附加到 URL 的锚点片段nullpageNamestring存储页码的查询参数名page这些属性定义在 AbstractPaginator.php同时还有onEachSide当前页两侧显示的链接数默认 3用于UrlWindow的滑动窗口计算。URL 生成机制与相关方法url(int $page)是 URL 生成的核心AbstractPaginator.php$parameters [$this-pageName $page]; if (count($this-query) 0) { $parameters array_merge($this-query, $parameters); } return $this-path . (Str::contains($this-path, ?) ? : ?) . Arr::query($parameters) . $this-buildFragment();要点页码参数名默认是page可通过setPageName()修改例如setPageName(p)若path本身已包含?则用拼接查询串否则用?query中的附加参数会与页码合并进查询串且通过addQuery()添加时不会覆盖与pageName同名的键fragment锚点通过fragment()方法读取/设置最终以#xxx形式追加在 URL 末尾。相关链式方法一览方法作用withPath(string $path)/setPath(string $path)设置所有 URL 的基础路径appends($key, $value)追加一组查询参数支持数组批量追加withQueryString()把当前请求的全部查询串附加到分页 URLfragment(?string $fragment)读取或设置 URL 锚点onEachSide(int $count)设置当前页两侧显示的链接数getUrlRange(int $start, int $end)生成一段连续页码的 URL 映射hasPages()判断是否足够拆分为多页不在第一页或还有更多页items()获取当前页数据的数组形式isEmpty()/isNotEmpty()判断当前页数据是否为空getCollection()/setCollection()读取 / 替换内部集合此外AbstractPaginator实现了ArrayAccess可像数组一样用$paginator[key]访问条目与__call()魔术方法未定义的方法调用会被转发到内部集合因此$paginator-each(...)、$paginator-map(...)等集合方法均可直接使用。当前页码与路径的自动解析Paginator内置了静态解析器机制用于在未显式传入当前页与路径时自动从 HTTP 请求中读取。相关静态方法定义于 AbstractPaginator.phpresolveCurrentPage(string $pageName page, int $default 1)解析当前页未设置解析器时返回默认值currentPageResolver(Closure $resolver)注册当前页解析器resolveCurrentPath(string $default /)与currentPathResolver(Closure $resolver)对应路径的解析与注册。组件通过监听器 PageResolverListener.php 在BootApplication事件触发时完成自动注册它从RequestInterface读取page参数通过input($pageName)只有通过FILTER_VALIDATE_INT且大于等于 1 的值才会被采纳否则回退为 1路径则取自RequestInterface::url()。这就是「默认通过当前 HTTP 请求携带的page参数检测当前页码」的实现原理因此控制器示例中即使不传$currentPage也能正确工作。LengthAwarePaginator带总数统计的分页器当需要知道数据总量、总页数时应使用Hyperf\Paginator\LengthAwarePaginatorLengthAwarePaginator.php。其构造函数签名为__construct(mixed $items, int $total, int $perPage, ?int $currentPage 1, array $options [])与Paginator相比多了一个$total参数切片前的总数据量。构造时会基于$total计算lastPage$this-lastPage max((int) ceil($total / $perPage), 1);即总页数 ceil(总条数 / 每页条数)且至少为 1 页。LengthAwarePaginator独有的方法方法作用total()获取总条数lastPage()获取最后一页页码hasMorePages()判断是否存在下一页currentPage() lastPage()links()/render()渲染分页链接当前版本中传入自定义视图会抛出RuntimeException(WIP.)默认以 JSON 编码返回数据示例?php $items [/* 当前页数据 */]; $total 100; // 总条数 $perPage 10; $currentPage 2; $paginator new \Hyperf\Paginator\LengthAwarePaginator($items, $total, $perPage, $currentPage); $paginator-total(); // 100 $paginator-lastPage(); // 10 $paginator-hasMorePages(); // true游标分页CursorPaginator仓库中hyperf/paginator还提供了基于游标的分页实现CursorPaginator.php、AbstractCursorPaginator.php、Cursor.php适用于大型数据集上的「上一页 / 下一页」连续翻页场景__construct(mixed $items, int $perPage, ?Cursor $cursor null, array $options [])Cursor封装了指向下一页或上一页的参数集合encode()将参数以 Base64 形式编码进 URLcursor查询参数fromEncoded()从编码字符串还原游标nextCursor()/previousCursor()基于当前页首尾条目的参数构造游标toArray()输出的 JSON 结构为data、path、per_page、next_cursor、next_page_url、prev_cursor、prev_page_url当游标指向上一页时setItems()会对切片后的数据执行reverse()-values()反转保证返回顺序正确。CursorPaginator 的完整用法通常与数据库组件的cursorPaginate()方法配合由查询构建器完成游标条件的生成。与数据库组件集成查询构建器与模型分页hyperf/database已适配分页组件查询构建器与模型均可直接调用分页方法。相关用法详见 Database - Paginator核心入口如下。查询构建器分页?php // Show all users in the app, 10 pieces of data per page return Db::table(users)-paginate(10);Query\Builder的paginate()方法定义于 BuildsQueries.php内部先通过getCountForPagination()统计总数再用forPage($page, $perPage)设置 limit 与 offset最后构造LengthAwarePaginator返回。模型分页通过静态方法直接调用?php // Show all users in the app, 10 pieces of data per page return User::paginate(10);也可以组合查询条件?php // Show all users in the app, 10 pieces of data per page return User::where(gender, 1)-paginate(10);Model\Builder中的方法签名Model/Builder.phppaginate(?int $perPage null, array $columns [*], string $pageName page, ?int $page null): LengthAwarePaginatorInterface总数感知分页未传$perPage时使用模型的默认每页条数getPerPage()未传$page时通过Paginator::resolveCurrentPage($pageName)从请求自动解析simplePaginate(...)简单分页不统计总数cursorPaginate(?int $perPage null, ...)游标分页。关联关系如BelongsToMany、HasManyThrough同样暴露了paginate()/simplePaginate()方法见 BelongsToMany.php其中BelongsToMany还会通过hydratePivotRelation()把中间表pivot数据注入分页结果方便读取关联属性。JSON 序列化与返回结构由于 Hyperf 当前不支持视图渲染分页组件暂不支持渲染视图分页结果默认以application/json格式直接输出。Paginator与LengthAwarePaginator均实现了JsonSerializable、Jsonable、Arrayable其toArray()/toJson()输出结构如下Paginator::toArray()Paginator.php{ current_page: 1, data: [], first_page_url: /?page1, from: 1, next_page_url: /?page2, path: /, per_page: 10, prev_page_url: null, to: 10 }LengthAwarePaginator::toArray()LengthAwarePaginator.php在此基础上增加了last_page、last_page_url、total三个字段是 API 分页响应中最常用的格式。由于AbstractPaginator实现了__toString()Paginator中为toJson()你可以在控制器中直接return $paginator;框架会将分页对象序列化为 JSON 响应。总结手动分页构造Hyperf\Paginator\Paginator并传入数据集、每页条数与当前页即可options可覆盖path、query、fragment、pageName等内部属性常用方法currentPage()、count()、firstItem()、lastItem()、hasMorePages()、nextPageUrl()、previousPageUrl()、url($page)、onFirstPage()、perPage()总数统计Paginator不含total()需改用Hyperf\Paginator\LengthAwarePaginator自动解析PageResolverListener会在框架启动时注册页码与路径解析器默认从 HTTP 请求的page参数读取当前页数据库集成查询构建器与模型的paginate()/simplePaginate()/cursorPaginate()是开箱即用的分页入口返回带完整分页元数据的 JSON 结构。相关源码阅读入口AbstractPaginator.php、Paginator.php、LengthAwarePaginator.php、PageResolverListener.php、CursorPaginator.php数据库集成见 BuildsQueries.php 与 Model/Builder.php测试用例可参考 LengthAwarePaginatorTest.php、CursorPaginatorTest.php 与 PageResolverListenerTest.php。赞分享后端微服务【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/gh_mirrors/hy/hyperf点击查看免费下载相关推荐rsuite Pagination 分页组件实战指南从基础用法到源码级布局原理rsuite Pagination 分页组件实战指南从基础用法到源码级布局原理 导读 本文围绕 rsuite 的 Pagination 分页组件展开以官方文前端UI组件Hyperf 查询分页实战基于 database 与 paginator 组件的 paginate 完整使用指南Hyperf 查询分页实战基于 database 与 paginator 组件的 paginate 完整使用指南 本文以 Hyperf 官方文档「Query后端Web框架微服务RPC框架异步编程Livewire 分页Pagination完整实战指南从基础用法到源码级原理Livewire 分页Pagination完整实战指南从基础用法到源码级原理 Laravel 自带的分页器Paginator诞生于静态应用场景每次翻后端前端上一篇Jekyll 站点目录结构完全指南从标准骨架到源码级过滤规则下一篇OneUptime LLM 提供者接入指南从 OpenAI 到自托管 vLLM 的完整配置与源码解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?