web-dev-qa-db-ja.com

Laravelクエリスコープ内の関連モデルのクエリ

モデルの作成者がFooモデルの結果をフィルタリングするクエリスコープメソッドがあります。複雑なのは、作者が直接関係していないことです。

FooはBarに属し、BarはUserに属しています。 Fooがユーザーに属している場合は、次のようにすることができます。

public function scopeAuthorOnly($query, User $user)
{
    return $query->whereuser_id($user->id);
}

Fooモデルにはuser_id列がなく、代わりにbar_id列があるため、これは明らかに機能しません。ただし、user_idをフィルタリングする方法でクエリを作成する方法がわかりません。

ポインタはありますか?

11
Russ Back

解決策を見つけました:

public function scopeAuthorOnly($query, User $user)
{
    $query
        ->join('bars', 'foos.bar_id', '=', 'bars.id')
        ->join('users', 'bars.user_id', '=', 'users.id')
        ->where('users.id', '=', $user->id);

    return $query;
}
5
Russ Back

スコープでwhereHas()を使用して、関係を照会できます。

このモデルにusers()関係関数があると仮定しましょう。次に、次のようになります。

public function scopeAuthorOnly($query, User $user)
{
    return $query->whereHas('users', function($q) use($user){
        $q->where('id', $user->id);
    });
}

更新:whereHasステートメントをネストすることもできます:現在のFoobarという名前の関係があり、barusersという名前の関係がある場合、次のようになります。この:

public function scopeAuthorOnly($query, User $user)
{
    return $query->whereHas('bar', function($q) use($user){
        return $q->whereHas('users', function($q2) use($user){
            $q2->where('id', $user->id);
        });
    });
}

詳細: ここ

17
Arda

リレーションを使用してこれを行うこともできます(手動結合に頼ることなく):

public function scopeAuthorOnly($query, User $user)
{
    $query->whereHas(array('Bar' => function($query) use($user){
                $query->where('user_id', '=', $user->id);
            }));
}

編集:whereHasの代わりにwithを使用するようになりました(Laravel> = 4.1のみ)。訂正アルダをありがとう。

編集:4.2では、whereHasの構文が変更されたため、リレーションシップ名はパラメーター1であり、クロージャーはパラメーター2です(配列として渡されるのではありません)。

public function scopeAuthorOnly($query, User $user)
{
    $query->whereHas('Bar', function($query) use($user){
                $query->where('user_id', '=', $user->id);
            });
}
8
casafred