Reputation: 368
I have 3 models: Conference
, Session
and Speaker
. A Conference can have many Sessions and many Sessions can have many Speakers.
conferences
-----------
id
name
sessions
--------
id
conference_id
name
session_speaker
---------------
id
session_id
speaker_id
speakers
--------
id
name
I need to write a method which allows me to get all the Speakers of a particular Conference (so all the Speakers from all the Sessions of that particular Conference).
The following illustrates what I think should work, but it obviously doesn't as I can't chain these together.
class Conference extends Eloquent {
public function speakers() {
return $this->hasMany('Session')->belongsToMany('Speaker');
}
}
I have all the Model-Model relationships setup and working correctly (Conference-Sessions, Session-Speakers) however I can't create the bridge between Conference-Sessions-Speakers. Does anyone know how I can achieve this without writing a large SQL join query?
I think if there was a relationship belongsToManyThrough()
this would work however there isn't.
Thanks in advance!
Upvotes: 8
Views: 11591
Reputation: 13
The best solution is use the lib "hasManyDeep" (https://github.com/staudenmeir/eloquent-has-many-deep)
With this you can create the complete relationship, independently of be "has one", 'has many" or "many to many". You can create something like:
return $this->hasManyDeep(
Speaker::class,
['session_speaker', Session::class]
);
You can analyse the SQL creat
Upvotes: 0
Reputation: 321
I think a cleaner way will be
public function speakers()
{
return Speaker::whereHas('sessions', fn($query) => $query->where('conference_id', $this->id))->get();
}
but you should set up the belongsToMany() relationship between Session and Speaker Models
Upvotes: 1
Reputation: 3553
Unfortunately, the hasManyThrough relation does not work with many to many relationships in between.
What you can do is something like this:
public function speakers() {
$session_ids = Session::where('conference_id', $this->id);
$speaker_ids = DB::table('session_speaker')->whereIn('session_id', $session_ids)->lists('speaker_id');
return Speaker::whereIn('id', $speaker_ids)->get();
}
You probably need to set the variables to array(0)
if no results are found, otherwise the whereIn function will throw an error.
You could also use an Eloquent-only way, but that would probably result in many more database queries, while this one should be fine with only 2 queries being run.
You can then access the speakers with e.g. Conference::find(1)->speakers()
.
Note from 2021: This answer is from back in 2014 and relates to Laravel 4. Nowadays, this apparently does not work anymore. I would encourage you to check the Laravel docs, maybe this problem can now be solved in a better way.
Upvotes: 10