Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jptlightx005's avatar

How do I retrieve the related models of related models of a model?

If the question is not clear enough, please consider reading this stackoverflow topic:

https://stackoverflow.com/questions/48962062/how-do-i-retrieve-the-related-models-of-related-models-in-many-to-many-relations?noredirect=1#comment84930793_48962062

This time, though, I'll use different models. I'm making a basic Crime-tracking system. So, I have these tables:

Location Table -id -location_name

Crime Table -id -crime_name -location_id

Crime-Suspect Table -id -crime_id -suspect_id

Suspect Table -id -suspect_name

Basically, Crime belongs to many suspects and Suspect belongs to many crimes. Now, these three have their respective models: Location, Crime and Suspect.

Now, in the Location model, what I want to achieve is, I want to retrieve ALL of the suspects of all the crimes that is committed in that location. If you read the stackoverflow topic, I have the Group->Students->Subjects model there, and this is the SQL:

SELECT DISTINCT subject.id, subject.subject_name FROM tbl_student_subject studsubj LEFT JOIN tbl_student student ON student.id = studsubj.student_id RIGHT JOIN tbl_subject subject ON subject.id = studsubj.subject_id WHERE student.group_id = 1

Now, I want to apply this SQL in Eloquent as a relationship. If I can't, at least I just want to be able to retrieve the results as a collection of Suspect model.

The hasManyThrough doesn't work. It's made for a one-to-many model only, I think.

How do I do this in Eloquent? I hope you can help me. Thank you!

0 likes
14 replies
rumm.an's avatar

Have you established Eloquent reationships or you need help with both query and relationships?

jptlightx005's avatar

Actually, I don't know how to make this into a relationship. I already have the query, I just need to know how to use it in the model.

rumm.an's avatar

In Location:

public function crimes()
{
    return $this->hasMany('App\Crime');
}

public function suspects()
{
    return $this->crimes->flatMap(function ($crime) {
        return $crime->suspects;
    });
}

In Crime:

public function location()
{
    return $this->belongsTo('App\Location');
}

public function suspects()
{
    return $this->belongsToMany('App\Suspect');
}

In Suspect:

public function crimes()
{
    return $this->belongsToMany('App\Crimes');
}

Query (Simple Enough if I got you right):

$crimes_in_that_location = $location->suspects();

Should do the job. ;)

rumm.an's avatar

please do use proper code blocks when posting codes.

jptlightx005's avatar

Call to undefined relationship [suspects] on model [App\Location].

If that was as easy as this, I wouldn't have posted a lot of questions in the internet.

jptlightx005's avatar

I mean, I need to retrieve the suspects directly as a colleciton of model for Location. Not the Crimes in that location, but the Suspects in that location.

jptlightx005's avatar

In the location model:

protected $appends = ['suspects'];

public function allSuspects(){
    return DB::table('crime_suspect')
                ->leftJoin('crime', 'crime_suspect.crime_id', '=', 'crime.id')
                ->rightJoin('suspects', 'crime_suspect.suspect_id', '=', 'suspects.id')
                ->select(['suspects.*'])
                ->distinct()
                ->where('crime.location_id', '=', $this->id)
                ->get();
}

public function getSuspectsAttribute()
{
    return $this->allSuspects();
}
rumm.an's avatar

I mean, I need to retrieve the suspects directly as a colleciton of model for Location. Not the Crimes in that location, but the Suspects in that location.

I have updated my reply to reflect that

jptlightx005's avatar

^ Yes it worked now, it retrieves the suspects from each of the crimes for that location. The problem is, it's not distinct. It returns duplicate suspect.

Thanks for your response by the way! If I'm able to get the suspects' list in a distinct way (like in my own solution), I could use your solution as an alternative. :D

rumm.an's avatar
rumm.an
Best Answer
Level 17

Change the method as:

public function suspects()
{
    return $this->crimes->flatMap(function ($crime) {
        return $crime->suspects;
    })->unique('id');
}
jptlightx005's avatar

^ close enough. the suspects model now returns the pivot field:

pivot: {
    crime_committed_id: "3",
    suspect_id: "2"
}

Thus, making it un-unique

jptlightx005's avatar

Wait, nevermind the pivot, solved it by hiding it:

protected $hidden = ['pivot'];

in suspect class. But still it's not becoming unique, it still returns duplicate

jptlightx005's avatar

All right! Solved it using

    return $this->crimes->flatMap(function ($crime) {
        return $crime->suspects;
    })->unique('id');

I prefer this because it returns the Eloquent model I've made. Thank so much for your help @rumm.an

rumm.an's avatar

Ow yeah! forgot that unique accepts attributes too. updated

1 like

Please or to participate in this conversation.