web-dev-qa-db-ja.com

Laravel 5の「with」と「whereHas」をマージします

私はこのコードをLaravel 5にあります。Eloquentを使用して、完全に機能しています。

$filterTask = function($query) use ($id) {
    $query->where('taskid', $id);
};

User::whereHas('submissions', $filterTask)->with(['submissions' => $filterTask])->get();

基本的には、フィルターされた提出物を持つユーザーのみを取得することを目的としています。ただし、同じコールバック関数でwhereHaswithの両方のメソッドを実行するのは無駄です。それを簡素化する方法はありますか?

ありがとう。

17
KristofMorva

パフォーマンスの点では、ここでは何も最適化できません(雄弁な関係から結合に移動する場合を除く)。 whereHasの有無にかかわらず、2つのクエリが実行されます。 1つはすべてのユーザーを選択し、もう1つは関連モデルをロードします。 whereHas条件を追加すると、サブクエリが追加されますが、それでも2つのクエリです。

ただし、構文的に query scope をモデル(またはこれをより頻繁に使用する場合はベースモデル)に追加することで、これを少し最適化できます。

public function scopeWithAndWhereHas($query, $relation, $constraint){
    return $query->whereHas($relation, $constraint)
                 ->with([$relation => $constraint]);
}

使用法:

User::withAndWhereHas('submissions', function($query) use ($id){
    $query->where('taskid', $id);
})->get();
42
lukasgeiter

'マクロ可能'方法(Laravel 5.4 +

これをサービスプロバイダーのboot()メソッド内に追加します。

\Illuminate\Database\Eloquent\Builder\Eloquent::macro('withAndWhereHas', function($relation, $constraint){
    return $this->whereHas($relation, $constraint)->with([$relation => $constraint]);
});
1
Ijas Ameenudeen

静的関数を使用して@lukasgeiterからの回答を拡張したいと思います。

public static function withAndWhereHas($relation, $constraint){
    return (new static)->whereHas($relation, $constraint)
        ->with([$relation => $constraint]);
}

使い方は同じ

User::withAndWhereHas('submissions', function($query) use ($id){
    $query->where('taskid', $id);
})->get();
0
Emsal