Объединить 'с' и 'whereHas' в Laravel 5

У меня есть этот код в Laravel 5, используя Eloquent, который отлично работает:

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

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

В основном цель состоит в том, чтобы получить только тех пользователей, у которых есть свои отфильтрованные материалы, в которых есть какие-либо из них. Тем не менее, кажется, что тратить время на запуск как whereHas, так и с помощью с той же функцией обратного вызова. Есть ли способ упростить его?

Спасибо.

Ответ 1

В плане производительности вы ничего не можете оптимизировать здесь (за исключением случаев, когда вам нужно перейти от красноречивых отношений к объединениям). С помощью или без whereHas будут выполняться два запроса. Один, чтобы выбрать всех пользователей другой, чтобы загрузить связанные модели. Когда вы добавляете условие whereHas, добавляется подзапрос, но все еще два запроса.

Однако синтаксически вы можете немного оптимизировать это, добавив область запроса к своей модели (или даже базовую модель, если вы хотите использовать это чаще):

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

Ответ 2

" Макробный " способ (Laravel 5. 4+)

Добавьте это в метод boot() поставщика услуг.

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

Ответ 3

Я хочу расширить ответ от @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();