Запрос связанной модели в пределах области запроса Laravel

У меня есть метод области запроса, который фильтрует результаты по модели Foo автором модели. Усложнение состоит в том, что автор не имеет прямого отношения.

Foo принадлежит к Bar and Bar принадлежит Пользователю. Если Foo принадлежал Пользователю, я мог бы просто сделать это:

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

Это, очевидно, не будет работать, поскольку модель Foo не имеет столбца user_id и вместо этого имеет столбец bar_id. Однако я не уверен, как я могу построить запрос таким образом, чтобы фильтр user_id.

Любые указатели?

Ответ 1

Найдено решение:

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;
}

Ответ 2

Вы можете использовать whereHas() в области видимости для запроса отношений.

Предположим, что в этой модели есть функция отношения users(). Тогда это будет примерно так:

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

Обновление: Вы также можете вставлять операторы whereHas: если текущий Foo имеет отношение с именем bar, а bar имеет отношение, называемое users, оно быть следующим:

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);
        });
    });
}

Дополнительная информация: здесь

Ответ 3

Вы также можете сделать это с помощью отношений (не прибегая к ручным объединениям):

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);
            });
}