Quick Guide to handle Laravel Eloquent Many-to-Many relationship

0
608
Quick Guide to handle Laravel Eloquent Many-to-Many relationship

Dealing with database is hard, and it is harder when it comes down to manage relationships. Laravel makes it easy for developers. I will show you how to handle Laravel Eloquent Many-to-Many relationship in this post.

Many-to-Many Relationship

To illustrate, let see following example.

Many-to-Many Relationship
Many-to-Many Relationship – blog.petehouston.com

Talking about game champions’ leagues, there are many seasons and many clans.

  • One season have many clans.
  • One clan can participate in many seasons.

That’s it! The Many-to-Many relationship.

We will deal with it in Laravel, and with the help of Eloquent, dealing with relationship is easier than ever.

1. Setup the bootstrap project

Just create a new Laravel project in any way you prefer, and I recommend this.

$ composer create laravel/laravel laravel-m2m-project

Composer is a great tool for PHP developers and must-have today. Use it to quickly bootstrap a new Laravel project.

2. Generate models and migrations

We need to create 3 tables and 2 models, and they basically are:

  • Tables: seasons, clans, season_clan. The last one is the pivot table that addresses the many-to-many relationship.
  • Models: Season, Clans. No need to create table for pivot, it is a waste.

Let’s generate models along with migrations for the first two tables.

$ php artisan make:model Season -m
$ php artisan make:model Clan -m

Let’s update the migration code for seasons and clans table.

// file: XXX_create_seasons_table.php

class CreateSeasonsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('seasons', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('description');
            $table->integer('year');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('seasons');
    }
}
// file: XXX_create_clans_table.php

class CreateClansTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('clans', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('slogan');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('clans');
    }
}

In migration files, we need to define the table schema structure as you can see.

Next is to make migration for the pivot table season_clan.

$ php artisan make:migration create_season_clan_table

This is the following code for CreateSeasonClanTable migration class.

class CreateSeasonClanTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('season_clan', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('season_id')->unsigned();
            $table->foreign('season_id')->references('id')->on('seasons');

            $table->integer('clan_id')->unsigned();
            $table->foreign('clan_id')->references('id')->on('clans');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('season_clan');
    }
}

So far so good. We have models and migrations, let’s migrate into database.

$ php artisan migrate
Migrating: 2019_01_20_132011_create_seasons_table
Migrated:  2019_01_20_132011_create_seasons_table
Migrating: 2019_01_20_132119_create_clans_table
Migrated:  2019_01_20_132119_create_clans_table
Migrating: 2019_01_20_132253_create_season_clan_table
Migrated:  2019_01_20_132253_create_season_clan_table

3. Seed some data

Take your time to create a seeder class to feed some data into database, or you can do it manually.

Then move to next step.

4. Address the relationship

To address the many-to-many relationship, we need to use belongsToMany in both Season and Clan model.

class Clan extends Model
{
    public function seasons() {
        return $this->belongsToMany(\App\Season::class, 'season_clan', 'clan_id');
    }
}
class Season extends Model
{
    public function clans() {
        return $this->belongsToMany(\App\Clan::class, 'season_clan', 'season_id');
    }
}

The three parameters are:

  • The full namespace to class that current model is related to.
  • The pivot table name.
  • The column name of current model to map in the pivot table.

5. Query the many-to-many relationship

The fastest way to verify if our code is working is to use tinker.

$ php artisan tinker

This is the REPL for Laravel code, so it can evaluate code line-by-line, and we can quickly test if current code is working okay or not.

Psy Shell v0.9.9 (PHP 7.2.4 — cli) by Justin Hileman
>>> use App\Season;
>>> $s = Season::first()
=> App\Season {#2918
     id: 1,
     name: "International 2017",
     description: "The regular international season in 2017",
     year: 2017,
     created_at: "2019-01-20 13:39:15",
     updated_at: "2019-01-20 13:39:15",
   }
>>> $s->clans()->pluck('name');
=> Illuminate\Support\Collection {#2907
     all: [
       "Liquid",
       "Hacker",
       "Engineer",
     ],
   }
>>> use App\Clan;
>>> $c = Clan::first();
=> App\Clan {#2920
     id: 1,
     name: "Liquid",
     slogan: "Never lose",
     created_at: "2019-01-20 13:38:35",
     updated_at: "2019-01-20 13:38:35",
   }
>>> $c->seasons()->pluck('name')
=> Illuminate\Support\Collection {#2915
     all: [
       "International 2017",
       "International 2018",
       "International 2019",
     ],
   }
>>> _

Look, it just works out of the box!

Summary

Thanks to Laravel Eloquent, many-to-many relationship is a piece of cake to handle. We don’t have to deal with unnecessary tasks or write extra code to make it.

Also, if you’re not certain, read the official Laravel Eloquent documentation.

If you need source code for reference, it is right here, https://github.com/petehouston/laravel-many-to-many-relationship-demo