Метод hasManyThrough
Метод hasManyThrough определяет отношение "через" (has-many-through) в Eloquent. Он позволяет получить доступ к записям из дальней таблицы через промежуточную модель. Первым параметром передаётся имя конечной модели, вторым - имя промежуточной модели, третьим - внешний ключ на промежуточной таблице, четвёртым - внешний ключ на конечной таблице, пятым - локальный ключ промежуточной модели, шестым - локальный ключ конечной модели. Если ключи не указаны, Laravel использует стандартные соглашения.
Синтаксис
<?php
Model::hasManyThrough(
$related,
$through,
$firstKey = null,
$secondKey = null,
$localKey = null,
$secondLocalKey = null
);
?>
Пример
Рассмотрим структуру таблиц для блога. У нас есть таблицы 'countries', 'users' и 'posts'. Через страну мы хотим получить все посты пользователей этой страны:
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use AppModelsUser;
use AppModelsPost;
class Country extends Model
{
protected $table = 'countries';
public function posts()
{
return $this->hasManyThrough(
Post::class,
User::class,
'country_id',
'user_id',
'id',
'id'
);
}
}
?>
Теперь мы можем получить все посты пользователей из определённой страны:
<?php
namespace AppHttpControllers;
use AppModelsCountry;
use AppModelsPost;
class PostController extends Controller
{
public function index()
{
$country = Country::find(1);
$posts = $country->posts;
foreach ($posts as $post) {
echo $post->title;
}
}
}
?>
Результат выполнения кода:
["Post 1", "Post 2", "Post 3"]
Пример
Если структура таблиц соответствует стандартным соглашениям Laravel, можно сократить определение отношения. Например, для таблиц 'countries', 'users' и 'posts' с типовыми ключами:
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use AppModelsUser;
use AppModelsPost;
class Country extends Model
{
protected $table = 'countries';
public function posts()
{
return $this->hasManyThrough(
Post::class,
User::class
);
}
}
?>
Laravel автоматически определит, что промежуточная таблица 'users' содержит внешний ключ 'country_id', а таблица 'posts' содержит внешний ключ 'user_id'. Получим посты:
<?php
namespace AppHttpControllers;
use AppModelsCountry;
class PostController extends Controller
{
public function index()
{
$country = Country::find(2);
$posts = $country->posts()->where('status', 'published')->get();
foreach ($posts as $post) {
echo $post->title . ' - ' . $post->status;
}
}
}
?>
Результат выполнения кода:
["Post 1 - published", "Post 3 - published"]
Пример
Используем метод hasManyThrough для подсчёта количества постов пользователей каждой страны с помощью отношения:
<?php
namespace AppHttpControllers;
use AppModelsCountry;
class CountryController extends Controller
{
public function index()
{
$countries = Country::withCount('posts')->get();
foreach ($countries as $country) {
echo $country->name . ': ' . $country->posts_count;
}
}
}
?>
Результат выполнения кода:
["USA: 5", "UK: 3", "Germany: 7"]
Пример
Получим посты пользователей из страны с идентификатором 1, отсортированные по дате создания в порядке убывания:
<?php
namespace AppHttpControllers;
use AppModelsCountry;
class PostController extends Controller
{
public function getPosts()
{
$country = Country::find(1);
$posts = $country->posts()
->orderBy('created_at', 'desc')
->limit(5)
->get();
foreach ($posts as $post) {
echo $post->title . ' - ' . $post->created_at;
}
}
}
?>
Результат выполнения кода:
["Post 10 - 2025-01-15", "Post 9 - 2025-01-14", "Post 8 - 2025-01-13", "Post 7 - 2025-01-12", "Post 6 - 2025-01-11"]
Смотрите также
-
метод
hasMany,
который определяет отношение "один ко многим" -
метод
hasOneThrough,
который определяет отношение "один через" -
метод
belongsToMany,
который определяет отношение "многие ко многим" -
метод
with,
который выполняет жадную загрузку отношений