laravel7.x¦リレーション先の条件も加味した複雑なwhere条件のデータを取得する
やりたいこと
リレーションを使って複雑なwhereをいい感じ(ざっくり)に取得していく方法のメモですφ('ᴗ'」)
当然ながらjoinなどを使ったり、他の方法でも同じようなデータは取得できると思います。
今回はその中でもリレーションを頑張って使っていく方法です。メリットとしてはリレーション先のデータへのアクセスがスマートにできる、コード数が少なくなる(ような気が)します。
今回やっていくことはこちら💡
・ A or B の時 Aはリレーション先のテーブルの条件の場合
・(A and B and C and D) or (C and D and E)の時 AとBはリレーション先のテーブルの条件の場合
環境
・laravel 7.1
・php 7.3
前提
塾とか何か習いごとのクラスをしているかのようなテーブルを想像していただければと思います💡
グループクラス(group_class_infosにデータがあるもの)は複数の先生に見てもらえるリッチな塾という感じで...
・companies - 先生の所属する塾
・teachers - 先生のテーブル
・students - 生徒のテーブル
・classes - 先生と生徒1on1のクラス
・group_class_infos
- 複数の先生と生徒1人のクラス
- 先生が対象のグループクラスに参加/不参加/回答待ちのステータスも保存
想像しやすいように図を作ってみたのですが、鳥の足記法がもし間違っていたらごめんなさい😹
グループクラス、メインの先生、サブの先生とは? テーブルの仕様について...
💡グループクラスになっている場合
group_class_infos
のclass_idカラムにclasses
のidのデータがある
💡メインの先生の見つけ方
group_class_infos
のclass_idカラムにclasses
のidのデータがある場合、classes
のteacher_idがメインの先生
💡サブの先生の見つけ方
group_class_infos
のclass_idカラムにclasses
のidのデータがある場合、group_class_infos
のteacher_idのみがサブの先生
※メインの先生のデータもgroup_class_infos
に入ってきます
Class.phpでstudentsとgroup_class_infosのリレーションを定義しておいてください💡
今回はstudentsはstudent
で group_class_infosはgroupInfos
としています( '֊' )
A or B の時 Aはリレーション先のテーブルの条件の場合
一人の先生のクラスの予定で、個人クラスもグループクラスもとにかく全部ほしいとき
$classes = Class::with('student')
->with('groupInfos')
->whereHas('groupInfos', function ($q) use ($teacherId) {
$q->where('group_class_infos.teacher_id', $teacherId);
})
->orWhere('classes.teacher_id', $teacherId)
->get();
with('student')
としているので生徒の名前も取り出すことができます💫
@foreach ($classes as $class)
{{ $class->student->isNotEmpty() ? $class->student->name : '未予約' }}
@endfoeach
リレーションを定義しているとwithで指定するだけでいい感じにデータがとれるので便利ですね!
collectionクラスで後続処理を行う場合にグループクラスの他の先生の情報は不要な場合
with('groupInfos')
としているところの条件を絞ると他の先生のデータが入ってこないのでスッキリすることがあります💡
$classes = Class::with('student')
->with(['groupInfos' => function ($q) use ($teacherId) {
$q->where('group_class_infos.teacher_id', $teacherId);
}])
->whereHas('groupInfos', function ($q) use ($teacherId) {
$q->where('group_class_infos.teacher_id', $teacherId);
})
->orWhere('classes.teacher_id', $teacherId)
->get();
🏳 🏳 🏳
(A and B and C and D) or (C and D and E)の時 AとBはリレーション先のテーブルの条件の場合
先生のクラスの予定で、生徒から予約が入っている個人クラスとグループクラス両方がほしいとき
つまり以下のようなデータを取得したい時です💡
・自分の個人クラスで、生徒から予約が入っているクラス
・生徒から予約が入っているグループクラスで、自分がメインの先生のクラス
・生徒から予約が入っているグループクラスで、サブの先生で加えられており参加予定のクラス
$classes = Class::with('student')
->whereHas('groupInfos', function ($q) use ($teacherId, $status) {
$q->where('group_class_infos.teacher_id', $teacherId)
->where('group_class_infos.status', $status);
})
->whereNotNull('student_id')
->where('date', '>=', $date)
->orWhere(function ($q) use ($teacherId, $date) {
$q->whereNotNull('student_id')
->where('date', '>=', $date)
->where('teacher_id', $teacherId);
})
->get();
🎩 🎩 🎩
おわりに...
実際に実装している時はリレーションもふんわりしかわかっていなかったこともあり
条件が複雑で迷走しまくり実装に時間がかかりましたが、こうしてまとめてみると簡単なような...あの時間は一体...
なんとか意図した動作になったので良かったです( '֊' )
Discussion