← Back to all snippets
PHP

Implementing a Has Many Through Relationship

Learn how to define a "has many through" relationship in Laravel Eloquent to conveniently access a distant relationship by traversing an intermediate model in your application.

// Scenario: A Country has many Users, and each User has many Posts.
// We want to get all Posts for a given Country directly.

// 1. Define the Country model (app/Models/Country.php)
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Country extends Model
{
    use HasFactory;

    public function users()
    {
        return $this->hasMany(User::class);
    }

    // Define the "has many through" relationship to Posts
    public function posts()
    {
        return $this->hasManyThrough(Post::class, User::class);
    }
}

// 2. Define the User model (app/Models/User.php)
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class User extends Model
{
    use HasFactory;

    public function country()
    {
        return $this->belongsTo(Country::class);
    }

    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// 3. Define the Post model (app/Models/Post.php)
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Post extends Model
{
    use HasFactory;

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

// Usage: Get all posts from a specific country
$country = App\Models\Country::find(1);
$countryPosts = $country->posts; // Collection of Post models
How it works: The `hasManyThrough` relationship provides a convenient shortcut for accessing distant relationships through an intermediate model. In the example, a `Country` model can directly access its `Post` models (which belong to `User` models) through the `User` model. The `hasManyThrough` method takes the final model name (`Post::class`) as the first argument and the intermediate model name (`User::class`) as the second. This simplifies querying and avoids needing to manually chain multiple relationships.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs