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

Valorin's avatar

Opposite of hasManyThrough

hasManyThrough (http://laravel.com/docs/eloquent#has-many-through) is a great way to define complex nested relationships for models, however, is there a reverse of it?

Using the example provided in the docs:

countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string

You can easily bounce through the users table and return all posts for a country:

$posts = Country::posts();

However, how can you go the other way, and retrieve a country for a given post? Currently it looks like you need to do:

$country = $post->user->country;

Is there a nicer way?

0 likes
14 replies
foxted's avatar
foxted
Best Answer
Level 8

I think you could use this logic in a method on your Post model:

class Post extends Eloquent{

    ...

    public function country(){
        return $this->user->country;
    }
}
5 likes
Valorin's avatar

Good idea :-)

I was hoping for a magical all-in-one method, but I guess it's not really needed given that is so simple.

1 like
foxted's avatar

@Valorin If it helped, do not hesitate to give an award for the answer :p

1 like
impbob36's avatar

Is there a magic method for this in Laravel 5?

livecontrol's avatar

Instead of creating a method that has to be called I prefer using the "magic" get{Name}Attribute() method for this (http://laravel.com/docs/5.0/eloquent all the way in the bottom).

For example you can do the following:

class Post extends Eloquent {
    protected $appends = ['country']; // only available in Laravel 5
    ...
    public function getCountryAttribute() {
        return $this->user->country;
    }
}

That way you can use $post->country and it also automatically gets added if you use toArray() or toJson() on the Post model.

4 likes
pdraznik's avatar

Has anyone tried eager loading with this method? When I do I get the error below Call to undefined method Illuminate\Database\Query\Builder::addEagerConstraints()

Manthan's avatar

@pdraznik Hey, I was facing the same issue. I followed what @livecontrol showed above and it works fine. You don't have to eager load it, the attribute will always be there.

gilbitron's avatar

An alternative is to use whereHas:

$country = Country::whereHas('posts', function ($query) use ($post) {
    $query->where('posts.id', $post->id);
})->first();
2 likes
victorsfleite's avatar

@livecontrol, your answer should be chosen the best one. This approach is called 'Accessors', and using this requires no need of work-arounds. Creating a method to return $post->user->country works fine, but I think using an accessor is a lot better, since it actually acts as an attribute of the given object.

Please or to participate in this conversation.