With
Применяется для жадной загрузки. То есть вместе с самой моделью Laravel загружает и связанные данные. Это полезно, если у вас есть коллекция моделей и для каждой вы хотите загрузить связанные данные. При жадной загрузке будет выполнен только один дополнительный запрос к базе данных.
Пример User > hasMany > Post:
$users = User::with(‘posts’)->get();
foreach($users as $user){
$users->posts; // посты уже загружены, нет запроса в каждой итерации цикла
}
Has
Применяется для фильтрации по связанным данным. Это очень похоже на обычно where-условие. Если вы используете has(‘relatiion’), то получите только те модели, у которых есть хотя бы одна связанная модель.
Пример User > hasMany > Post:
$users = User::has(‘posts’)->get();
// только пользователи с хотя бы одним постом
WhereHas
Работает как и has, но с возможностью указать дополнительные фильтры для связанной модели.
Пример User > hasMany > Post:
$users = User::whereHas(‘posts’, function($q){
$q->where(‘created_at’, ‘>=’, ‘2018-01-01 00:00:00’);
})->get();
// только пользователи с хотя бы одним постом 2018 года
Важно, что with добавляет связанные данные в коллекцию, а has и whereHas — нет. Иногда может понадобиться применить with и has одновременно (или with и whereHas).
И есть еще такой вариант:
$books = Book::with([‘author’ => function($query) { $query->where(‘smth’, ‘val’); },
‘author.contacts’ => function($query) { $query->where(‘smth_else’, ‘one_more_val’); }])
->get();
Бывает и такое:
…->whereHas(‘university’, function($q) use($p) {
$q->whereHas(‘location’, function($q2) use($p) {
$q2->whereHas(‘city’,function($q3) use($p) {
$q3->where(‘region_id’, $p);
});
});
});