Laravel 通过属性获得雄辩的查询构建器关系

Posted

技术标签:

【中文标题】Laravel 通过属性获得雄辩的查询构建器关系【英文标题】:Laravel get eloquent query builder relations by property 【发布时间】:2021-12-02 22:49:42 【问题描述】:

我正在使用 eloquent 查询构建器根据用户搜索查询提供的参数有条件地构建搜索查询。

这似乎适用于直接属于我正在搜索的模型的属性。但是,在尝试返回与模型相关但不直接属于模型的其他结果时,我遇到了问题。

我到底想做什么:

我正在尝试允许用户按教师姓名搜索学校,其中姓名/关键字通过中间表出现在学校的关系中。

这是我的模型和关系:

学校:

class School extends Authenticatable

    protected $fillable = [
        'school_name', 'head_teacher', 'address'
    ];

    public function teachers()
    
        return $this->belongsToMany(Teacher::class, 'teacher_links', 'school_id', 'teacher_id');
    

老师:

class Teacher extends Authenticatable

    use Notifiable;

    protected $table = 'teacher';

    protected $fillable = [
        'name'
    ];

TeacherLink:

class TeacherLink extends Authenticatable

    protected $table = 'teacher_links';
    protected $fillable = [
        'teacher_id', 'school_id'
    ];

我可以使用$school->teachers 成功地通过控制器中的学校查询教师,所以我知道这种关系运作良好。

这是我的控制器代码,其中用户搜索参数是有条件地建立的:

public function index(Request $request)

    $schools = School::query();

    // User Search Term
    $search = $request->get('search');
    $headTeacher = $request->get('head_teacher');

    $questions
        ->when($search, function ($q) use ($search) 
            $q->where('school_name', 'like', '%' . $search . '%')
                ->orWhere('head_teacher', 'like', '%' . $search . '%')
                
                // This is the query i'm having an issue with
                ->whereHas('teachers', function($q) use ($search) 
                    $q->where('teacher_name', 'like', '%' . $search . '%');
                );

        )

当通过学校名称或 head_teacher 搜索时,两个初始 where 子句返回正确的结果,因为这两个属性直接属于学校。但是,我想通过关系返回包含教师姓名的其他学校。

所以一所学校可以通过中间的teacher_link表属于许多老师,反之亦然,但我不知道如何使用雄辩的查询构建器准确过滤这个。

最初我尝试使用联合函数和连接,它有效但破坏了后续的 where 子句,因为它似乎不允许在联合查询之后跟随 where 子句。

如果有人能告诉我我做错了什么以及如何修复相关查询,那就太好了:

            // This is the query i'm having an issue with
            ->whereHas('teachers', function($q) use ($search) 
                $q->where('teacher_name', 'like', '%' . $search . '%');
            );

编辑

我尝试了以下似乎可行但速度很慢的方法:

$schools
        ->when($search, function ($q) use ($search) 
            $q->join("teacher_links", function ($join) 
                    $join->on("teacher_links.school_id", "=", "schools.id");
                )
                ->join("teachers", function ($join) 
                    $join->on("teachers.id", "=", "teacher_links.teacher_id");
                )
                ->select("schools.*")
                ->where("teachers.teacher_name", 'like', '%' . $search . '%')
                ->orWhere('school_name', 'like', '%' . $search . '%')
                ->orWhere('school_address', 'like', '%' . $search . '%')
                ->orWhere('school_focus', 'like', '%' . $search . '%');
        );

【问题讨论】:

whereHas 编译为AND WHERE EXISTS。也许你正在寻找orWhereHas (OR WHERE EXISTS) 【参考方案1】:

尝试在该查询中使用orWhereHas

->when($search, function ($q) use ($search) 
    $q->where('school_name', 'like', '%' . $search . '%')
        ->orWhere('head_teacher', 'like', '%' . $search . '%')
        ->orWhereHas('teachers', function ($sub) use ($search) 
            $sub->where('teacher_name', 'like', '%' . $search . '%');
        );
    );

【讨论】:

【参考方案2】:

尝试使用雄辩的关系

School::where('school_name', 'like', '%' . $search . '%')
  ->orWhere('head_teacher', 'like', '%' . $search . '%')
  ->orWhereHas(['teachers'=>function($query) use ($search) 
      return $query->where('teacher_name', 'like', '%' . $search . '%');
    ]
  )->get();

【讨论】:

以上是关于Laravel 通过属性获得雄辩的查询构建器关系的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 雄辩与查询构建器的优缺点

雄辩的查询构建器laravel 5.6中的未知列

laravel 雄辩的查询构建器更新自定义时间戳字段而没有任何逻辑

嘲笑 Laravel 雄辩的水合关系

groupBy 在 laravel 中具有雄辩的关系

查询生成器的行为就像雄辩