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 "话题排序"
                    
                    
                    
                
          
Web 开发实战教程
        
            
            
                关于 LearnKu
              
                    
                    
                    
 
推荐文章: