Yii 2 数据排序实战指南:深入解析 yii\data\Sort 的配置、原理与数据提供者集成

发布时间:2026/9/24 16:22:19
Yii 2 数据排序实战指南:深入解析 yii\data\Sort 的配置、原理与数据提供者集成 后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载当页面需要展示多行数据且允许终端用户按照某一列或某几列进行排序时Yii 2 提供了专门的[[yii\data\Sort]]对象来承载整套排序模式信息。本文以 output-sorting.md 为骨架结合框架源码与测试用例完整讲解yii\data\Sort的声明方式、配置参数、请求参数解析、排序链接生成以及与 ActiveDataProvider、ArrayDataProvider、SqlDataProvider 等数据提供者的集成原理帮助你写出真正可落地、可复用的 Yii 2 排序功能。一、Sort 对象的三个核心维度yii\data\Sort位于 framework/data/Sort.php继承自yii\base\BaseObject通过三个属性完整描述一套排序模式$attributes声明数据允许按哪些“属性”排序。一个属性可以简单对应模型的一个属性详见 模型属性也可以是由多个模型属性或数据库列组合而成的复合属性。$attributeOrders返回当前请求中各属性对应的排序方向SORT_ASC升序 /SORT_DESC降序以属性名为键。$orders返回底层列级别的排序方向映射键是真实的列名或排序表达式值是对应的方向常量。该数组可以直接喂给数据库查询构造ORDER BY子句。二、声明可排序属性简单属性与复合属性要使用yii\data\Sort第一步是声明允许排序的属性然后从attributeOrders或orders中取出当前请求的排序信息用它定制数据查询。以下是文档中的完整示例use yii\data\Sort; $sort new Sort([ attributes [ age, name [ asc [first_name SORT_ASC, last_name SORT_ASC], desc [first_name SORT_DESC, last_name SORT_DESC], default SORT_DESC, label Name, ], ], ]); $articles Article::find() -where([status 1]) -orderBy($sort-orders) -all();上面声明了两个可排序属性age和name。2.1 简单属性ageage对应ArticleActive Record 类的age属性它是一个简单属性等价于下面的完整声明age [ asc [age SORT_ASC], desc [age SORT_DESC], default SORT_ASC, label Inflector::camel2words(age), ]也就是说当你只写属性名字符串形式时Yii 会自动生成与其同名的列、默认升序方向并用Inflector::camel2words()生成标签。这一归一化逻辑可以在Sort::init()中看到framework/data/Sort.phppublic function init() { $attributes []; foreach ($this-attributes as $name $attribute) { if (!is_array($attribute)) { $attributes[$attribute] [ asc [$attribute SORT_ASC], desc [$attribute SORT_DESC], ]; } elseif (!isset($attribute[asc], $attribute[desc])) { $attributes[$name] array_merge([ asc [$name SORT_ASC], desc [$name SORT_DESC], ], $attribute); } else { $attributes[$name] $attribute; } } $this-attributes $attributes; }注意如果 Sort 对象已经创建完成再对其属性进行配置就必须使用完整格式每个属性都必须包含asc和desc元素。2.2 复合属性namename由Article的first_name和last_name两列组合而成采用数组结构声明asc/desc分别指定按该属性升序、降序排序时的实际列与方向。值可以是一个列简单排序也可以是多个列复合排序。default指定该属性首次被请求排序时采用的默认方向缺省为升序SORT_ASC。label调用Sort::link()生成排序链接时使用的标签文本若不设置Yii 会用Inflector::camel2words()从属性名自动生成。注意该标签不会被 HTML 编码如需转义请自行处理。2.3 直接排序表达式2.0.12自 2.0.12 起asc/desc还可以直接写成一个排序表达式字符串便于使用数据库专属特性。例如 PostgreSQL 的空值排序控制name [ asc [[last_name]] ASC NULLS FIRST, // PostgreSQL 专属特性 desc [[last_name]] DESC NULLS LAST, ]此时getOrders()会把该字符串原样放入orders数组由查询构造器Query Builder解析处理测试用例 SortTest::testGetExpressionOrders 验证了这一点。三、将排序信息应用到数据查询拿到orders后直接传给查询的orderBy()即可$articles Article::find() -where([status 1]) -orderBy($sort-orders) -all();Info可以直接把$sort-orders的值喂给数据库查询构造ORDER BY子句。不要使用$sort-attributeOrders因为有些属性是复合属性数据库查询无法直接识别例如上面name对应的真实列是first_name与last_name。从源码看getOrders()framework/data/Sort.php会遍历attributeOrders把每个属性的asc/desc定义展开成真实列映射若定义是数组/可遍历对象则展开为列 方向若是字符串表达式则直接追加到$orders数组中public function getOrders($recalculate false) { $attributeOrders $this-getAttributeOrders($recalculate); $orders []; foreach ($attributeOrders as $attribute $direction) { $definition $this-attributes[$attribute]; $columns $definition[$direction SORT_ASC ? asc : desc]; if (is_array($columns) || $columns instanceof \Traversable) { foreach ($columns as $name $dir) { $orders[$name] $dir; } } else { $orders[] $columns; } } return $orders; }四、生成排序链接link() 与 createUrl()调用Sort::link()可以生成一个终端用户点击即可请求按指定属性排序的超链接Sort::createUrl()则只生成可排序的 URL。文档示例// 指定生成 URL 所用的路由若不指定则使用当前请求的路由 $sort-route article/index; // 依次展示按 name 和 age 排序的链接 echo $sort-link(name) . | . $sort-link(age); // 输出/index.php?rarticle%2Findexsortage echo $sort-createUrl(age);4.1 link() 的细节行为结合源码framework/data/Sort.phplink()会依次完成若当前该属性已在排序中则根据方向为a附加 CSS 类asc或desc若$options[class]已有值则追加否则新建通过createUrl()生成目标 URL在链接标签上写入data-sort属性值为createSortParam()生成的排序参数供前端 JavaScript 增强交互使用确定标签文本优先取$options[label]其次取$attributes[$attribute][label]再其次通过modelClass实例的getAttributeLabel()获取2.0.49最后退回Inflector::camel2words($attribute)。createUrl()framework/data/Sort.php会把新的排序参数写入$params[$this-sortParam]以$this-route缺省为当前控制器路由Yii::$app-controller-getRoute()作为路由交给urlManager缺省为应用组件urlManager生成 URL传入$absolute true可生成绝对 URL。4.2 链接方向的智能切换createSortParam()framework/data/Sort.php体现了“点击切换方向”的逻辑若当前该属性未在排序中使用定义里的default缺省SORT_ASC作为方向若已在排序中单属性模式下升序变降序、降序变升序多属性模式下升序变降序降序则从排序中移除最终把方向编码为属性名升序或-属性名降序多个属性用separator默认,连接。测试 SortTest::testCreateSortParam 覆盖了各种状态切换例如当sort参数为-age时再请求age排序生成的参数是空字符串即取消排序。五、请求参数解析sort 参数、defaultOrder 与 sortParamyii\data\Sort通过sort查询参数判断用户请求了哪些属性、以什么方向排序。参数格式为升序直接写属性名降序在属性名前加-前缀多属性用分隔符连接例如sortage,-name表示按age升序、name降序。defaultOrder当请求中没有sort参数时使用该属性指定的默认排序格式为[属性名 SORT_ASC|SORT_DESC, ...]。sortParam自定义查询参数名默认是sort。解析过程在getAttributeOrders()framework/data/Sort.php中public function getAttributeOrders($recalculate false) { if ($this-_attributeOrders null || $recalculate) { $this-_attributeOrders []; if (($params $this-params) null) { $request Yii::$app-getRequest(); $params $request instanceof Request ? $request-getQueryParams() : []; } if (isset($params[$this-sortParam])) { foreach ($this-parseSortParam($params[$this-sortParam]) as $attribute) { $descending false; if (strncmp($attribute, -, 1) 0) { $descending true; $attribute substr($attribute, 1); } if (isset($this-attributes[$attribute])) { $this-_attributeOrders[$attribute] $descending ? SORT_DESC : SORT_ASC; if (!$this-enableMultiSort) { return $this-_attributeOrders; } } } return $this-_attributeOrders; } if (empty($this-_attributeOrders) is_array($this-defaultOrder)) { $this-_attributeOrders $this-defaultOrder; } } return $this-_attributeOrders; }要点请求参数来源默认是Yii::$app-request-getQueryParams()即$_GET也可通过$params属性显式指定例如为所有链接统一追加锚点array_merge($_GET, [# my-hash])见 framework/data/Sort.php。解析出的属性如果不在attributes声明中会被忽略防止注入未知列。parseSortParam()是受保护方法默认按separator拆分字符串子类可重写它以支持自定义参数格式例如把sort参数解析为结构化数组——测试中的 CustomSort 就是这样一个示例。六、多属性同时排序enableMultiSort默认情况下enableMultiSort false即同一时刻数据只能按一个属性排序getAttributeOrders()遇到第一个有效属性即返回createSortParam()也只保留单一属性。将其设为true后sort参数可以携带多个属性如age,-name排序同时生效。测试 SortTest::testGetOrders 验证了两种模式下的差异启用多排序时getOrders()返回 3 个列映射age、first_name、last_name关闭后只剩 1 个。七、与数据提供者Data Provider的集成yii\data\Sort最常用的场景是搭配各类数据提供者使用。BaseDataProvider::setSort()framework/data/BaseDataProvider.php接受三种值配置数组class缺省为yii\data\Sort若提供者设置了id还会自动把sortParam命名为{id}-sort避免多个数据提供者共用同一sort参数Sort或其子类的实例false表示禁用排序。7.1 ActiveDataProvider在 framework/data/ActiveDataProvider.php 中排序结果通过addOrderBy()附加到克隆的查询上if (($sort $this-getSort()) ! false) { $query-addOrderBy($sort-getOrders()); }setSort()被重写framework/data/ActiveDataProvider.php传入排序配置后会校验查询是否实现了ActiveQueryInterface。典型用法$provider new ActiveDataProvider([ query Article::find()-where([status 1]), sort [ attributes [age, name], defaultOrder [age SORT_DESC], ], ]);7.2 ArrayDataProvider对于内存数组数据排序在 framework/data/ArrayDataProvider.php 中通过ArrayHelper::multisort()完成并受$sort-sortFlags默认SORT_REGULAR自 2.0.33 起可配置影响protected function sortModels($models, $sort) { $orders $sort-getOrders(); if (!empty($orders)) { ArrayHelper::multisort($models, array_keys($orders), array_values($orders), $sort-sortFlags); } return $models; }7.3 SqlDataProvider对于原生 SQL 查询framework/data/SqlDataProvider.php 会先用正则把 SQL 中已有的ORDER BY段提取为Expression前置再调用buildOrderByAndLimit()拼装排序与分页保证自定义 SQL 与 Sort 排序共存。7.4 视图层输出无论哪种数据提供者视图层输出排序链接的方式一致与 framework/data/Sort.php 的文档示例相同// 展示分别指向按 name 和 age 排序的链接 echo $sort-link(name) . | . $sort-link(age); foreach ($models as $model) { // 渲染 $model }结合 GridView 时只需在数据提供者中配置sortGridView 的列头即可自动生成带data-sort属性与asc/desc样式类的排序链接。八、测试验证Sort 的契约行为仓库测试 tests/framework/data/SortTest.php 是对上述行为的权威背书关键用例包括testGetOrders/testGetAttributeOrders验证多属性排序下orders展开为列映射、attributeOrders保留属性级方向以及单属性模式下只保留第一个属性。testGetAttributeOrder验证单属性方向查询未知属性返回null。testSetAttributeOrders验证手动注入排序方向时的校验行为——enableMultiSort false时只保留第一个校验开启时未知属性会被剔除$validate false则原样保留。testCreateUrl/testLinkWithParams/testLinkWithoutParams验证生成 URL 的编码结果、asc/descCSS 类、data-sort属性以及defaultOrder对链接状态的影响。testGetExpressionOrders验证直接排序表达式如 PostgreSQL 的NULLS FIRST原样进入orders。这些用例同时也是理解Sort行为边界的速查手册。九、小结yii\data\Sort是 Yii 2 输出层排序功能的基石通过attributes声明排序白名单orders驱动查询、link()/createUrl()驱动交互sortParam/defaultOrder/enableMultiSort控制请求解析与默认行为并且天然与 ActiveDataProvider、ArrayDataProvider、SqlDataProvider 以及 GridView 协同工作。掌握本文内容你就能在任意 Yii 2 项目中快速实现安全、可扩展、体验良好的多列排序功能。赞分享后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载相关推荐Yii 2 数据排序实战深入解析 yii\data\Sort 的属性声明、排序链接与 DataProvider 集成Yii 2 数据排序实战深入解析 yii\data\Sort 的属性声明、排序链接与 DataProvider 集成 Yii 2 在 yii\data\Sor后端Web框架Yii 2 数据排序实战yii\data\Sort 对象从入门到源码级解析Yii 2 数据排序实战yii\data\Sort 对象从入门到源码级解析 本篇技术指南以官方文档《排序》 docs/guide zh CN/output后端Web框架Yii 2 排序实战基于 yii\data\Sort 实现用户可控的数据排序Yii 2 排序实战基于 yii\data\Sort 实现用户可控的数据排序 本文以 Yii 2 框架的官方指南 docs/guide ru/output s后端Web框架上一篇secGear本地证明与远程证明对比分析构建多层安全验证体系下一篇QEMU串口和控制台配置如何通过串口访问虚拟机控制台创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考