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

Laravel scopeFilter中为$search多orWhere条件添加括号包裹方案

Laravel 本地作用域多字段OR搜索逻辑优先级问题修复

问题原因

直接在查询构建器上链式调用orWhere拼接多字段模糊搜索条件时,Laravel不会自动为这组OR条件生成分组括号。由于SQL中AND的运算优先级高于OR,后续拼接的serviceDate、mealType等AND筛选条件会被划入最后一段OR的逻辑分支,导致整体查询逻辑错乱。

修复方案

通过向where方法传入闭包的方式,手动为OR搜索条件声明独立的逻辑分组,Laravel会自动为闭包内的所有条件包裹独立括号,与外层其他AND条件完全隔离。

修正后的代码

public function scopeFilter($query, array $filters)
{
    $mealType = $filters['mealType'] ?? null;
    $serviceDate = $filters['serviceDate'] ?? null;
    $search = $filters['search'] ?? null;

    $query
        ->when($search, function ($query) use ($search) { 
            // 核心:通过闭包创建独立逻辑分组,自动生成包裹括号
            $query->where(function ($subQuery) use ($search) {
                $subQuery->where('first_name', 'like', '%'.$search.'%')
                    ->orWhere('last_name', 'like', '%'.$search.'%')
                    ->orWhere('sisid', 'like', '%'.$search.'%')
                    ->orWhere('grade', 'like', '%'.$search.'%')
                    ->orWhere('hr', 'like', '%'.$search.'%');
            });
        })
        ->when($serviceDate, function ($query, $serviceDate) {
            $query->where('enter_date', '<=', $serviceDate)
                ->where('exit_date', '>=', $serviceDate);
        })
        ->when($filters['grade'] ?? null, function ($query, $grade) {
            $query->where('grade', '=', $grade);
        })
        ->when($filters['hr'] ?? null, function ($query, $hr) {
            $query->where('hr', '=', $hr);
        })
        ->when($mealType, function ($query) use ($mealType, $serviceDate) {
            $query->whereDoesntHave('student_meals', fn ($query) => 
                $query->where('meal_type_id', $mealType )
                    ->where('void', false)
                    ->where('date_served', $serviceDate));
        });        
}

实现效果

修正后生成的SQL会将所有搜索相关的OR条件整体包裹在独立括号内,结构与预期完全一致:

SELECT * FROM `students` 
WHERE `students`.`site_id` = 1 and `students`.`site_id` IS not NULL 
and (`first_name` like '%Maxi%' or `last_name` like '%Maxi%' or `sisid` like '%Maxi%' or `grade` like '%Maxi%' or `hr` like '%Maxi%')
and `enter_date` <= '2022-05-11' 
and `exit_date` >= '2022-05-11' 
and not exists (SELECT * FROM `student_meals` WHERE `students`.`id` = `student_meals`.`student_id` and `meal_type_id` = '1' and `void` = 0 and `date_served` = '2022-05-11') and `students`.`deleted_at` IS NULL ORDER BY `first_name` ASC, `last_name` ASC

注意:所有需要和外层条件保持AND关系、内部包含OR逻辑的条件组,都需要通过闭包分组的方式编写,避免出现逻辑优先级错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 18:36:51