初めてのLaravel ⑦。多対多のリレーション

初めてのLaravel ⑦。多対多のリレーション
この記事はこんな悩みを解決します
  • Laravelの多対多のリレーションができるようになりたい
  • Laravelについて勉強したい

1対多のリレーションは以前の記事で紹介しましたが、多対多のリレーションを設定したい時もあると思います。例えば、ブログの記事にタグをつけたり、商品にレビューを書いたりするときなどに使います。

この記事を読むことで多対多のリレーションの設定の仕方が分かります。

初めてのLaravel ⑦。多対多のリレーション

userとroleのテーブルを多対多の関係で紐付けていきたいと思います。

そのために必要なテーブルを用意しましょう。

今回必要なテーブル
  • users
  • roles
  • role_user

role_userはusersとrolesを紐づけるためのテーブルです。ここで注意なのですがuser_roleとしないようにしましょう。アルファベット順でないとテーブルが見つからない、とエラーが出ます。まぁ、後で編集することもできますが。

テーブルの作成

usersテーブルはデフォルトであるものを使用するのでrolesテーブルとrole_userテーブルを作っていきます。

mbp:training user$ php artisan make:model role -m //-mはマイグレイションファイルも同時に作ると言うことを意味します。
Model created successfully.
Created Migration: 2020_07_04_074408_create_roles_table

モデルファイルとマイグレイションファイルができたのでマイグレイションファイルから編集していきます。このファイルでrolesとrole_userテーブルを同時に作って行きます。

public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->id('id');
            $table->string('name');
            $table->timestamps();
        });

        Schema::create('role_user', function (Blueprint $table) {
            $table->id('id');
            $table->unsignedBigInteger('user_id');
            $table->unsignedBigInteger('role_id');
            $table->timestamps();

            $table->unique(['user_id', 'role_id']); //各idが被ってはいけない、と言う意味です。
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
       //外部キー制約をかけています。
        });
    }

rolesテーブルを作る時にuser_idカラムを作りたくなりますが、その役割はrole_userテーブルに任せます。

では、マイグレイションします。

mbp:training user$ php artisan migrate
Migrating: 2020_07_04_074408_create_roles_table
Migrated:  2020_07_04_074408_create_roles_table (0.15 seconds)

うまく行きました。

モデルの編集

次にモデルを編集します。

 public function role(){
        return $this->belongsToMany(role::class);
        return $this->belongsToMany(role::class, 'role_user', 'user_id', 'role_id');
        //丁寧に書く場合は下を使う。role_userではなく、user_roleにするとアルファベット順ではないので定義しなければならなくなる。
     //ちなみに、第三引数にはリレーションを定義しているモデルの外部キー、第四引数には結合するモデルの外部キーを書きます。
     //第三引数と第四引数を逆にすると軸が逆になります。第三引数が軸になるので気をつけましょう。
    }

Userが複数のroleに紐づいてますと言う意味です。
色々と注意書きを書いているので興味のある人は読んでください。

逆の設定もしていきます。

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

roleが複数のUserに紐づいてますと言う意味です。

データの入力

最後にテーブルにデータを入れて行きます。
今回は下記のような感じにしてます。

usersテーブル

rolesテーブル

role_userテーブル

user_idが1に対してrole_idが3つ、role_idが2つに対してuser_idが2つあることに注意してください。これらを抽出して見ます。

リレーションの確認

では、準備が整ったのでTerminalで確認して見ましょう。

mbp:training user$ php artisan tinker
Psy Shell v0.10.4 (PHP 7.3.19 — cli) by Justin Hileman
>>> $user = App\User::find(1);
=> App\User {#3056
     id: 1,
     name: "Quinn Boyer",
     email: "kiara05@example.net",
     email_verified_at: "2020-07-04 08:14:13",
     created_at: "2020-07-04 08:14:13",
     updated_at: "2020-07-04 08:14:13",
   }

$userにidが1のユーザーを入れました。ここからroleで紐づけられたroleを引っ張ってきます。

>>> $user->role;
=> Illuminate\Database\Eloquent\Collection {#3059
     all: [
       App\role {#3064
         id: 1,
         name: "teacher",
         created_at: null,
         updated_at: null,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3069
           user_id: 1,
           role_id: 1,
         },
       },
       App\role {#3073
         id: 2,
         name: "driver",
         created_at: null,
         updated_at: null,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3062
           user_id: 1,
           role_id: 2,
         },
       },
       App\role {#3049
         id: 3,
         name: "office worker",
         created_at: null,
         updated_at: null,
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3057
           user_id: 1,
           role_id: 3,
         },
       },
     ],
   }

3つのroleがうまく取れてますね。

逆のリレーションの確認

逆にroleからuserを取ってきましょう。

>>> $role = App\role::find(1);
=> App\role {#3052
     id: 1,
     name: "teacher",
     created_at: null,
     updated_at: null,
   }
>>> $role->user;
=> Illuminate\Database\Eloquent\Collection {#3083
     all: [
       App\User {#3076
         id: 1,
         name: "Quinn Boyer",
         email: "kiara05@example.net",
         email_verified_at: "2020-07-04 08:14:13",
         created_at: "2020-07-04 08:14:13",
         updated_at: "2020-07-04 08:14:13",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3072
           role_id: 1,
           user_id: 1,
         },
       },
       App\User {#3081
         id: 2,
         name: "Jayne Champlin",
         email: "tristian.herman@example.org",
         email_verified_at: "2020-07-04 08:14:13",
         created_at: "2020-07-04 08:14:13",
         updated_at: "2020-07-04 08:14:13",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3080
           role_id: 1,
           user_id: 2,
         },
       },
     ],
   }

うまく2つ取れてきています。

まとめ

今回は多対多のリレーションの仕方を紹介しました。

1対多の次に使うことが多いと思うので使えるようになっておきましょう。ブログのタグをつけたり、ユーザーが商品を評価する時などに使います。

関連記事