63. 话题列表排序
简介
在本节里,我们完成话题列表可以按『最后回复』和『最新发布』排序功能。
需求分解
我们可以通过 URI 传参 order 给控制器,控制器根据此参数来决定数据的读取逻辑。因为『分类下的话题列表』也会用到排序,并且是在不同的控制器中,所以在此处为了复用性考虑,我们将会把排序逻辑代码放置于 Topic 数据模型中。
在 Topic 数据模型里我们打算用 查询范围 实现排序功能。查询范围允许我们定义通用的约束集合以便在应用中复用。要定义这样的一个查询范围,只需简单在对应的模型方法前加上一个 scope
前缀,查询范围总是返回 查询构建器。一旦定义了查询范围,则可以在查询模型时调用该查询范围方法。需要注意的是在进行方法调用时不需要加上 scope
前缀。
此外,从 V5.1.26+ 版本开始,支持在数据模型里面可以设置 globalScope
属性,定义 全局查询范围。全局查询范围 和普通查询范围不同之处是,当给模型设置了全局查询范围后在执行查询操作时不通过 useGlobalScope
方法关闭时全局查询默认是有效的(即给查询添加上全局查询范围条件)。
数据模型
application/common/model/Topic.php
<?php
namespace app\common\model;
use think\Model;
class Topic extends Model
{
.
.
.
/**
* 范围查询-最近回回复排序
* @Author zhanghong(Laifuzi)
* @DateTime 2019-02-25
* @param [type] $query 查询构建器
* @return [type] 查询构建器
*/
public static function scopeRecentReplied($query)
{
// 按最后更新时间排序
return $query->order('update_time', 'DESC');
}
/**
* 范围查询-最新发表
* @Author zhanghong(Laifuzi)
* @DateTime 2019-02-25
* @param [type] $query 查询构建器
* @return [type] 查询构建器
*/
public static function scopeRecent($query)
{
// 按照创建时间排序
return $query->order('id', 'DESC');
}
/**
* 范围查询-排序方式
* @Author zhanghong(Laifuzi)
* @DateTime 2019-02-25
* @param [type] $query 查询构建器
* @param [type] $order_type 排序方式
* @return [type] 查询构建器
*/
public static function scopeWithOrder($query, $order_type)
{
switch ($order_type) {
case 'recent':
$query->recent();
break;
default:
// 默认按最后回复降序排列
$query->recentReplied();
break;
}
return $query->with('user,category');
}
/**
* 分页查询方法
* @Author zhanghong(Laifuzi)
* @DateTime 2019-06-20
* @param array $params 请求参数
* @param integer $page_rows 每页显示数量
* @return [type] 分页查询结果
*/
public static function minePaginate($param = [], $per_page = 20)
{
$order_type = NULL;
if(isset($param['order'])){
$order_type = $param['order'];
}
$self = self::withOrder($order_type);
foreach ($param as $name => $value) {
switch ($name) {
case 'category_id':
if($value > 0){
$self = $self->where($name, $value);
}
break;
}
}
$paginate = $self->paginate($per_page);
return $paginate;
}
}
控制器
接下来,我们在话题控制器中调用 minePaginate
时把排序参数(我们这里设置的参数名是 order
)传递进去。
- 话题列表:
application/index/controller/Topic.php
<?php
namespace app\index\controller;
use think\Request;
use app\common\model\Topic as TopicModel;
class Topic extends Base
{
public function index(Request $request)
{
$param = $request->only(['order'], 'get');
$paginate = TopicModel::minePaginate($param);
$this->assign('paginate', $paginate);
return $this->fetch('index');
}
}
- 分类话题列表:
application/index/controller/Category.php
<?php
namespace app\index\controller;
use think\Request;
use app\common\model\Topic as TopicModel;
use app\common\model\Category as CategoryModel;
class Category extends Base
{
/**
* 显示指定的资源
*
* @param int $id
* @return \think\Response
*/
public function read(Request $request, $id)
{
$category = CategoryModel::find($id);
$this->assign('category', $category);
$param = $request->only(['order'], 'get');
$param['category_id'] = $id;
$paginate = TopicModel::minePaginate($param);
$this->assign('paginate', $paginate);
return $this->fetch('topic/index');
}
}
代码解读
- 在这里我们使用
$request->only
方法只获取请求 URL 里的 order 这一个参数值并把它传递到minePaginate
方法里; - 当使用
$request->only
获取的请求参数不存在时,返回结果里不包含该参数主键,如当参数order
不存在时$param = $request->only(['order'], 'get')
的运行结果是$param = [];
。
助手方法
接下来,我们需要添加一个辅助方法为当前使用的排序方式添加上选中效果。
application/index/common.php
<?php
.
.
.
/**
* 排序方式导航是否active样式名
* @Author zhanghong(Laifuzi)
* @DateTime 2019-02-25
* @param string $name 判断参数名
* @param string $value 判断参数值
* @param boolean $is_equal 判断方式
* @return string [description]
*/
function order_active($name, $value, $is_equal = true)
{
// 获取当前请求信息里的参数值
$param_value = request()->get($name);
$is_active = false;
if($is_equal == true && $param_value == $value){
// 页面请求参数值和判断参数值相等时为选中样式
$is_active = true;
}else if($is_equal != true && $param_value != $value){
// 页面请求参数值和判断参数值不等时为选中样式
$is_active = true;
}
if($is_active){
return 'active';
}else{
return '';
}
}
视图页面
接下来,在视图页面里我们需要为按钮添加链接和选中状态。
application/index/view/topic/index.html
<div class="card-header bg-transparent">
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link <?php echo(order_active('order', 'recent', false)); ?>" href="<?php echo(request()->baseUrl()); ?>">
最后回复
</a>
</li>
<li class="nav-item">
<a class="nav-link <?php echo(order_active('order', 'recent')); ?>" href="<?php echo(request()->baseUrl()); ?>?order=recent">
最新发布
</a>
</li>
</ul>
</div>
代码解读
- 我们使用
request()->baseUrl()
获取访问页面不含请求参数的 URL 。
效果展示
Git 版本控制
下面把代码纳入到版本管理:
$ git add -A
$ git commit -m "话题排序"
推荐文章: