Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 485
Mike F Avatar asked Jun 12 '14 10:06

Mike F


People also ask

What is the difference between belongsTo and hasOne?

The only difference between hasOne and belongsTo is where the foreign key column is located. Let's say you have two entities: User and an Account. In short hasOne and belongsTo are inverses of one another - if one record belongTo the other, the other hasOne of the first.

What is with () in Laravel?

with() function is used to eager load in Laravel. Unless of using 2 or more separate queries to fetch data from the database , we can use it with() method after the first command. It provides a better user experience as we do not have to wait for a longer period of time in fetching data from the database.

What is polymorphic relationship in Laravel?

A one-to-one polymorphic relationship is a situation where one model can belong to more than one type of model but on only one association. A typical example of this is featured images on a post and an avatar for a user. The only thing that changes however is how we get the associated model by using morphOne instead.


1 Answers

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.

like image 79
Matthias S Avatar answered Nov 29 '22 10:11

Matthias S