In this tutorial, we will explore how to use the Has-Many-Through relationship in Laravel Eloquent. Through a practical example involving the related entities: “Country,” “Team,” and “Athlete,” I’ll guide you through setting up these relationships and demonstrate how to access and work with them in your Laravel application.
The Has-Many-Through relationship in Laravel connects two models through an intermediate model. To implement it, define a function in the model named after the related table, returning $this->hasManyThrough(Related::class, Intermediate::class)
.
Take a look at the diagram below, which shows an example of entities related through a Has-Many-Through relationship. In this example, a country has multiple athletes through the intermediate teams entity.
In the following step-by-step guide, we will walk through how to implement the Has-Many-Through relationship in Laravel and create related data that can be accessed through this relationship. Let’s start and learn how to establish and work with a Has-Many-Through relationship in Laravel.
Step 1: Create and Run the Migrations
To begin, let’s create the necessary migrations for the “countries,” “teams,” and “athletes” tables. Open your terminal and run the following Artisan commands:
php artisan make:migration create_countries_table --create=countries
php artisan make:migration create_teams_table --create=teams
php artisan make:migration create_athletes_table --create=athletes
This will generate three migration files: one for the “countries” table, one for the “teams” table, and one for the “athletes” table. Open each migration file and modify the up()
and down()
methods as shown below.
For the countries
table, use:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('countries', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('countries');
}
};
For the teams
table, use:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('teams', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Country::class)->constrained();
$table->string('name');
$table->string('sport');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('teams');
}
};
For the athletes
table, use:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('athletes', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Team::class)->constrained();
$table->string('first_name');
$table->string('last_name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('athletes');
}
};
After saving the modified migration files, run the following command to create the tables:
php artisan migrate
Step 2: Create the Eloquent Models
Next, let’s create the Eloquent models for the “Country,” “Team,” and “Athlete” entities. Run the following commands in your terminal:
php artisan make:model Country
php artisan make:model Team
php artisan make:model Athlete
This will generate three model files in the “app/Models” directory. Open each model file and add the necessary relationships as shown below.
For the Country
Model, use:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Country extends Model
{
public function teams()
{
return $this->hasMany(Team::class);
}
public function athletes()
{
return $this->hasManyThrough(Athlete::class, Team::class);
}
}
For the Team
Model, use:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
public function country()
{
return $this->belongsTo(Country::class);
}
public function athletes()
{
return $this->hasMany(Athlete::class);
}
}
For the Athlete
Model, use:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Athlete extends Model
{
public function team()
{
return $this->belongsTo(Team::class);
}
}
Step 3: Performing Has-Many-Through Queries
Now that we have set up the migrations and models, we can perform queries using the Has-Many-Through relationship. Here are 2 examples of how you can use the relationship:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/testhasmanythrough', function () {
// Example 1: Retrieve all athletes for a country
$country = \App\Models\Country::find(1);
$athletes = $country->athletes;
foreach ($athletes as $athlete) {
dump($athlete->attributesToArray());
}
// Example 2: Retrieve all athletes for a country
// Retrieve the country for an athlete
$athlete = \App\Models\Athlete::find(13);
$country = $athlete->team->country;
dump($country->attributesToArray());
});
Further Has-Many-Through Examples
In addition to the “Country”, “Team”, and “Athlete” examples we have used in this tutorial, there are various other scenarios where the Has-Many-Through relationship can be applied. Here are a few more examples:
Parent Model | Intermediate Model | Child Model |
Country | State | City |
Author | Book | Chapter |
User | Account | Transaction |
Company | Department | Employee |
School | Grade | Student |
Category | Subcategory | Product |
Country | User | Post |
By understanding the concepts and implementation of Has-Many-Through relationships in Laravel, you can effectively manage complex relationships and retrieve data from related models with ease.
Conclusion
In this tutorial, we explored how to use the Has-Many-Through relationship in Laravel to establish complex relationships between entities. By implementing the relationship in the “Country,” “Team,” and “Athlete” models, we were able to create a connection between these entities through an intermediate model.
In this tutorial, we covered essential steps like creating migrations, defining model relationships, and performing queries with the Has-Many-Through relationship. Understanding and implementing this relationship enables you to build robust and interconnected data structures in your Laravel applications.
Finally, as an inspiration, we’ve included a number of example entities to which you might apply a Has-Many-Through Relationship. Happy coding!
References:
This entry is part 5 of 9 in the series Laravel Eloquent Relationships
- How to Use a One-to-One Relationship in Laravel
- How to Use a One-to-Many Relationship in Laravel
- How to Use a Many-to-Many Relationship in Laravel
- Using Extra Fields in Pivot Table With Laravel belongsToMany
- How to Use Has-Many-Through Relationships in Laravel
- How to use One-to-Many Polymorphic Relationship in Laravel
- How to use Many-to-Many Polymorphic Relationship in Laravel
- How to Paginate a Model with Relationship in Laravel
- How to Use `with()` to Eager Load Relationship in Laravel
Hi Johan,
Thanks for the tutorial.
It looks like you’ve missed country_id in the teams migration and the team_id in the Athletes migration.
Hey Danny, thank you for pointing out the missing foreign id columns in the sample code. It appears I didn’t paste the most recent version since my current code has them. I’ve updated the example by adding them to the migrations. I apologize for the oversight. Your feedback is much appreciated!