laravel5.1のEloquentを使って、リレーション先のリレーション先の値でwhereしたい時のコーディング(多対1の先の多対1)
結構分かりづらかったので、備忘録として書いておく。
1,以下のようなテーブル(関係)があったとする
親会社テーブル(Parents)
子会社テーブル(Childs)
子会社の社員テーブル(members)
2,やりたい事
親会社に属している子会社の社員数の人数を、親会社毎に集計したい!
3, 各クラスにリレーション関係を記述する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// 子会社クラス class Child extends Model(App\Child) { // 親会社は一社だけ public function Parent() { return $this->hasOne('App\Parent'); } // 子会社に所属している社員は複数 public function Members() { return $this->hasMany('App\Member'); } } // 子会社の社員クラス(App\Member) class Member extends Model { // この社員が所属している子会社 public function Child() { return $this->belongsTo('App\Child'); } } |
4, 実際のリレーション先の値を使って、検索・集計する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 子会社の社員クラスを使って集計!親会社を指定する $query = Member::query(); $parent_name = "親会社の名前"; // 所属している子会社の所属している親会社を検索キーにして、メンバー数をカウント! // Member.Child.Parentみたいにドットでつなげる。後ろが親なのが変な感じ。 $query->wherehas("Child.Parent", function ($query) use ($parent_name) { // クロージャーの中で外の変数を使いたい場合はuseを使う。 // このnameは、Parent.name(親会社の名前) $query->where("name", $parent_name); }); // 指定された親会社に所属する子会社の従業員数。 $num = $query->get()->count(); // 他の項目が知りたいなら、通常通りに取得する。 // $users = $query->get(); |
【結論】
少々分かりづらいので、無理してeloquentを使わずに、素直にSQL単体で書いても良さ気だけど・・・使い分けの判断に迷うな。