Вложенные отношения Laravel
У меня много проблем с установлением очень вложенных отношений для правильной работы в Laravel.
Разыскиваемое поведение заключается в следующем,
Я выбираю событие по идентификатору и хочу посмотреть, какие лица подписаны на него. Теперь проблема в том, что между событием и человеком есть несколько таблиц.
Это запрос, который работает!
SELECT persons.id,
persons.firstname,
persons.lastname,
event_scores.score
FROM events
JOIN cities
ON cities.id = events.city_id
JOIN companies
ON cities.id = companies.city_id
JOIN persons
ON companies.id = persons.company_id
JOIN event_scores
ON event_scores.person_id = persons.id
WHERE event_scores.event_id = 1
GROUP BY persons.id
Это мои отношения
Модель события
class Event extends Eloquent
{
protected $table = 'events';
public function city()
{
return $this->belongsTo('City');
}
}
Модель города
class City extends Eloquent
{
protected $table = 'cities';
public function companies()
{
return $this->hasMany('Company');
}
public function event()
{
return $this->hasMany('Event');
}
}
Модель компании
class Company extends Eloquent {
protected $table = 'companies';
public function persons()
{
return $this->hasMany('Person');
}
public function city()
{
return $this->belongsTo('City');
}
}
Модель человека
class Person extends Eloquent
{
protected $table = 'persons';
public function company()
{
return $this->belongsTo('Company');
}
public function eventscore()
{
return $this->belongsToMany('Event', 'event_scores', 'person_id', 'event_id')
->withPivot('score')
->withTimestamps();
}
}
Что я пробовал
return Event::with('city')->with('company')->get();
а также
return Event::with('city')
->whereHas('companies', function($query) use ($company_id){
$query->where('company_id', $company_id);
})->get();
И многие другие возможности, я действительно застрял на этом. В laravel так сложно добиться такого рода вложенных отношений?
Спасибо!
Ответы
Ответ 1
return Event::with('city.companies.persons')->get();
Если вы хотите только выбрать определенные поля из таблицы persons
, используйте это:
return Event::with(['city.companies.persons' => function ($query) {
$query->select('id', '...');
}])->get();
Ответ 2
Для конкретных городов и компаний необходимо распределить их с красноречивым.
Например:
return Event::with([
'city' => function ($query) {
$query->select('id', '...');
},
'city.companies' => function ($query) {
$query->select('id', '...');
},
'city.companies.persons' => function ($query) {
$query->select('id', '...');
}
])->get();
Ответ 3
Я создал отношение HasManyThrough
для таких случаев: Репозиторий на GitHub
После установки вы можете использовать его так:
class Event extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function persons() {
return $this->hasManyDeep(
Person::class,
[City::class, Company::class],
['id'],
['city_id']
);
}
}
Вы можете получить атрибуты из промежуточных таблиц с помощью withIntermediate()
:
public function persons() {
return $this->hasManyDeep(
Person::class,
[City::class, Company::class],
['id'],
['city_id']
)->withIntermediate(City::class, ['id', '...']);
}
Ответ 4
Чтобы расширить @rashmi-nalwaya ответ. Я получил это работает для проекта 5.8 с некоторыми изменениями.
Мой пример был немного другим, потому что я пытаюсь ссылаться на отношения hasOne, а не hasMany.
Таким образом, для справки, Домены принадлежат одному Веб-сайту, который принадлежит одному Серверу. Я только хотел вернуть определенные столбцы из всех этих таблиц. Я должен был сделать это.
Domain::with([
'website' => function($q){
$q->select('id', 'server_id');
},
'website.server' => function($q){
$q->select('id', 'hostname', 'nickname');
}
])
->select('id', 'website_id', 'domain')
->get();
Нужно было в любой момент убедиться, что я прошел первичный ключ для таблицы, на которой я работаю (таким образом, id
в моем случае), и, во-вторых, внешний ключ связанной таблицы, к которой я пытаюсь добраться. Итак, website_id
с домена и server_id
с сайта. Тогда это сработало отлично.
В моем коде у меня также есть еще пункт where в основном домене, после всего этого без присмотра.