Search code examples
laravellaravel-4

Laravel get belongsToMany through hasMany


I have 3 models: Conference, Session and Speaker. A Conference can have many Sessions and many Sessions can have many Speakers.

Database structure

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.

app/models/Conference.php

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!


Solution

  • 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.