Laravel has many through Eloquent relationship tutorial

Laravel provides eloquent relationship which provides powerful query builders. In Laravel, eloquent relationships are defined in model classes. Laravel eloquent provides easy ways to create common relationships:

In this article, we will discuss on Laravel's Has many through eloquent relationship. This is little complicated relationship than has one through relationship. In this relationship, one model has many associated model through intermediate model.

For example, a School model may be associated with many Standard model and Standard model may be associated with many Student model. In this relationship, a School model doesn't have direct relationship with Student model but through Standard model.

Example:

Now, in this example, we will build relationship between School and Student through Standard model so we can access All students of School.

We assume that you have created fresh Laravel application. We also assume that you have confiured database connection.

Database tables

In this relationship, we have three database tables: schools, standards and students.

Migration

we need to create three migration table. Run the following three commands into Terminal to create migration classes at database/migrations directory.

php artisan make:migration create_schools_table
php artisan make:migration create_standards_table
php artisan make:migration create_students_table

Below are the migration table fields for these table:

schools migration

In the schools migration, we have defined the following fields:

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('schools', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->timestamps();
    });
}

standards migration

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('standards', function (Blueprint $table) {
        $table->id();
        $table->integer('school_id');
        $table->string('name');
        $table->timestamps();
    });
}

students migration

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('students', function (Blueprint $table) {
        $table->id();
        $table->integer('standard_id');
        $table->string('name');
        $table->timestamps();
    });
}

Now run the migrate command to create tables into database.

php artisan migrate

Model

Laravel model located at app/Models directory. Create model classes for these tables using following Artisan commands one by one into Terminal.

php artisan make:model School
php artisan make:model Standard
php artisan make:model Student

Now, let's look at the migration fields. We have school_id field in the standards table and standard_id in the students field. There is no direct relationship between schools and students table. To define relationship between schools and students table, create a method into School model.

<?php

namespace App\Models;

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

class School extends Model
{
    use HasFactory;

    /**
     * Get all the students for the school.
     */
    public function students()
    {
        return $this->hasManyThrough(Student::class, Standard::class);
    }
}

In the hasManyThrough method, first argument is the model that we want to access, the second argument is the intermediate model. Of course, you may define custom table fields instead of id of model name field.

/**
 * Get the Student of Standard.
 */
public function student()
{
    return $this->hasManyThrough(
        Student::class,
        Standard::class,
        'school_id', // Foreign key on the standards table
        'standard_id', // Foreign key on the students table
        'id', // Local key on the schools table
        'id' // Local key on the standards table
    );
}

Route

In routes/web.php file, we have added new route for relationship testing.

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\StudentController;

Route::get('/student', [StudentController::class, 'index']);

Controller

As we have added route, also create StudentController with following command.

php artisan make:controller StudentController

Open the controller at app/Http/Controllers/StudentController and create index method. To retrieve all the students record for a School, access students attribute of School model which we have created method.

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $students = School::find(1)->students;

    dd($students);
}

This will return all students record with the associated school_id of 1. If the relationship not found, the eloquent will return null record.

I hope this will help you to understand has many through eloquent relationship.

Tags: