Yii中,通过继承ActiveController,我们可以很快的创建cuid的接口。
比如我们可以这样获取数据列表:
GET http://localhost:8080/articles
用GET方法对上面的url发起请求,就可以获取所有的数据的列表。
那么问题来了,如果我想排序,比如,按时间排序,按热度排序等等,那么在url中,关于排序的参数应该怎么传呢。
这个问题虽然看起来很简单,但是官方文档中好像并没有相关内容。
要知道答案,只有去看源码了
首先打开yii\rest\IndexAction
最后有这么一段代码
return Yii::createObject([
'class' => ActiveDataProvider::className(),
'query' => $query,
'pagination' => [
'params' => $requestParams,
],
'sort' => [
'params' => $requestParams,
],
]);
就是用来反回结果集的。
我们发现在createObject的参数中有sort这个属生,在这里,url的参数通过$requestParams这个变量给传了过来。而 $requestParams中和排序相关的参数会在ActiveDataProvider中进行匹配,最终生成排序规则。
我们可以猜想,ActiveDataProvider中肯定有一个setSort的方法,用来传这里面的sort的值。
所以我们现在要看一看ActiveDataProvider的源码。
果然,被我们找到
public function setSort($value)
{
if (is_array($value)) {
$config = ['class' => Sort::className()];
if ($this->id !== null) {
$config['sortParam'] = $this->id . '-sort';
}
// print_r($config);
//print_r($value);
$this->_sort = Yii::createObject(array_merge($config, $value));
} elseif ($value instanceof Sort || $value === false) {
$this->_sort = $value;
} else {
throw new InvalidArgumentException('Only Sort instance, configuration array or false is allowed.');
}
}
这里面的$value,就是我们从url中获取的参数。在这个方法中,创建了一个Yii\data\Sort的对象。
然后,ActiveDataProvider会通过Yii\data\Sort对象提供的相关方法来获取排序规则
打开Yii\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])) {
//print_r($this->attributes);
// print_r($this->parseSortParam($params[$this->sortParam]));
foreach ($this->parseSortParam($params[$this->sortParam]) as $attribute) {
//echo $attribute;
$descending = false;
if (strncmp($attribute, '-', 1) === 0) {
$descending = true;
$attribute = substr($attribute, 1);
}
if (isset($this->attributes[$attribute])) {
// echo $attribute;
$this->_attributeOrders[$attribute] = $descending ? SORT_DESC : SORT_ASC;
if (!$this->enableMultiSort) {
return $this->_attributeOrders;
}
}
}
}
if (empty($this->_attributeOrders) && is_array($this->defaultOrder)) {
$this->_attributeOrders = $this->defaultOrder;
}
}
return $this->_attributeOrders;
}
这个方法干的事就是把url中获取的排序相关的参数转化程具体的排序规则返回,然后再ActiveDataProvider中通过这句代码
$query->addOrderBy($sort->getOrders());
来把排序添加到查询中。
在上面Sort代码中有这段
foreach ($this->parseSortParam($params[$this->sortParam]) as $attribute)
{
、、、、、、、、、
}
因为$this->sortParam=“sort",
parseSortParam方法是对url中的排序参数进行解析,
找到parseSortParam方法代码
/**
* Parses the value of [[sortParam]] into an array of sort attributes.
*
* The format must be the attribute name only for ascending
* or the attribute name prefixed with `-` for descending.
*
* For example the following return value will result in ascending sort by
* `category` and descending sort by `created_at`:
*
* ```php
* [
* 'category',
* '-created_at'
* ]
* ```
*
* @param string $param the value of the [[sortParam]].
* @return array the valid sort attributes.
* @since 2.0.12
* @see $separator for the attribute name separator.
* @see $sortParam
*/
protected function parseSortParam($param)
{
return is_scalar($param) ? explode($this->separator, $param) : [];
}
从注释可以看出,这个方法的返回值是一个数组,格式是这样的
[‘category’,’-created_at’]
return is_scalar($param) ? explode($this->separator, $param) : [];
这段代码实现的功能是,如果$param不是数组,将把它按逗号拆分成数组返回,否则返回空数组,
所以url中正确的参数规则应该是逗号分隔的字符串,就你这样
xxx=create_at,category
那么这个xxx应该是什么呢,是 $this->sortParam的值,也就是”sort"
所以,我们想要实现排序,应该这样
GET http://localhost:8080/users?sort=-create_at,category
字段前面什么都没就,就是正序,字段前加一个“-”,就是倒序。
然而,有一点需要注意,如果我们需要进行多个字段的排序的话,需要让Sort类中的$enableMultiSort属性为true,而默认是false。
所以我们需要在IndexAction中,传这样一个参数 ‘enableMultiSort’=>true,
return Yii::createObject([
'class' => ActiveDataProvider::className(),
'query' => $query,
'pagination' => [
'params' => $requestParams,
],
'sort' => [
'params' => $requestParams,
'enableMultiSort'=>true,
],
]);