5

as stated in the docs the current hasManyThrough can be used when u have something like country > users > posts

which result in something like Country::whereName('xx')->posts; which is great but what if i have more than that like

country > cities > users > posts or even

country > cities > towns > users > posts

how would you then implement something like that so you can write the same as above

Country::whereName('xx')->posts; or Town::whereName('xx')->posts;

ctf0
  • 6,991
  • 5
  • 37
  • 46

3 Answers3

10

I created a HasManyThrough relationship with unlimited levels: Repository on GitHub

After the installation, you can use it like this:

class Country extends Model {
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;

    public function posts() {
        return $this->hasManyDeep(Post::class, [City::class, Town::class, User::class]);
    }
}
Jonas Staudenmeir
  • 24,815
  • 6
  • 63
  • 109
3

Here's what I've done. I did some modification to @ctfo's answer, so it will return as collection.

public function posts()
{
    $posts = collect();

    foreach ($this->towns->get() as $town) {
        $post = $town->posts();
        if ( $post->count() ) $posts = $posts->merge( $post );
    }

    return $posts;
}

I hope this can help anyone who came through.

LrdArc
  • 66
  • 6
0

sadly there is no one easy solution, so heres what i found

1- add the other table foreign id into the post table and stick to the hasMany & belongsTo, ex.

posts
    id - integer
    country_id - foreign
    // etc...
    title - string

2- go with the hasManyThrough on each table except user & post as there is no need unless you want to go deeper, ex.

countries
    id - integer
    name - string

cities
    id - integer
    country_id - foreign
    name - string

towns
    id - integer
    city_id - foreign
    name - string

users
    id - integer
    town_id - foreign
    name - string

posts
    id - integer
    user_id - foreign
    title - string

- so lets try with the 2nd option

1- set up your hasMany & belongsTo relations as usual

2- setup the hasManyThrough on the models.

3- to achieve the above example of Country::whereName('xx')->posts we add another method to the country model

// because Country::find($id)->towns, return an array
// so to get all the posts we have to loop over that
// and return a new array with all the country posts
public function posts()
{
    $posts = [];

    foreach ($this->towns as $town) {
        $posts[] = $town->posts;
    }

    return $posts;
}

4- as the whole thing is working through the foreign_id so we search by the id instead of the name like Country::find($id)->posts()

ctf0
  • 6,991
  • 5
  • 37
  • 46