You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel项目查询Scope问题:权限控制与截止日期排序优化

解决Laravel Project模型Scope的权限与排序问题

需求回顾

  • 拥有view-all-projects权限的管理员:返回系统所有项目
  • 普通用户:仅返回自己创建的项目,或自己被分配了任务的项目
  • 排序规则:项目按「即将到期→还有充足时间→已过期」的顺序排列

原代码问题分析

  1. 排序失效:原代码中latest()默认按created_at降序,后续的orderBy('end_date', 'desc')被覆盖,导致排序不符合预期
  2. 管理员数据异常:最初的嵌套关联查询可能引发数据过滤错误,修改后的简化查询解决了数据获取问题,但缺失了关联预加载和自定义排序逻辑

完整解决方案

1. 完善scopeForUser方法

整合权限判断、关联预加载、预算计算和自定义排序逻辑:

public function scopeForUser($query, User $user)
{
    // 统一处理关联预加载和预算统计
    $query->withBudget()
          ->with(['customer:id,company_id' => ['company:id,name']]);

    // 管理员权限判断
    if ($user->hasPermissionTo('view-all-projects')) {
        return $this->applyDueDateSort($query);
    }

    // 普通用户的项目过滤规则
    return $query->where(function ($query) use ($user) {
        $query->where('user_id', $user->id)
              ->orWhereIn('id', function ($subQuery) use ($user) {
                  $subQuery->select('project_id')
                           ->from('tasks')
                           ->where('user_id', $user->id);
              });
    })->tap(function ($query) {
        $this->applyDueDateSort($query);
    });
}

// 抽离排序逻辑,复用性更强
private function applyDueDateSort($query)
{
    return $query->orderByRaw("
        CASE
            -- 即将到期:未来7天内的项目,优先级最高
            WHEN end_date >= NOW() AND end_date <= DATE_ADD(NOW(), INTERVAL 7 DAY) THEN 1
            -- 充足时间:超过7天的项目,优先级次之
            WHEN end_date > DATE_ADD(NOW(), INTERVAL 7 DAY) THEN 2
            -- 已过期:截止日期已过的项目,优先级最低
            WHEN end_date < NOW() THEN 3
            -- 无截止日期的项目,放在最后
            ELSE 4
        END ASC,
        -- 同优先级内按截止日期升序,最早到期的排最前
        end_date ASC
    ");
}

2. 保留scopeWithBudget方法不变

public function scopeWithBudget($query)
{
    return $query->addSelect(['budget' => function ($subQuery) {
        $subQuery->selectRaw('sum(cost)')
                 ->from('tasks')
                 ->whereColumn('project_id', 'projects.id');
    }]);
}

3. Action调用逻辑保持原样

<?php

namespace App\Actions;

use App\Models\Project;
use Illuminate\View\View;

class ListProjects
{
    public function __invoke(): View
    {
        $projects = Project::forUser(auth()->user())->get();

        return view('projects.index', ['projects' => $projects, 'projectsCount' => $projects->count()]);
    }
}

核心优化说明

  • 把排序逻辑抽成独立方法,避免重复代码,后续调整规则更方便
  • 统一处理关联预加载和预算计算,减少重复的查询构建代码
  • 用orderByRaw实现自定义优先级排序,精准匹配业务需求
  • 修复了原代码中排序被覆盖的问题,同时保留了管理员和普通用户的正确数据过滤逻辑

内容的提问来源于stack exchange,提问作者Kingsley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 04:55:07