LoginSignup
59
55

More than 5 years have passed since last update.

LaravelのPivotモデルを使い中間テーブルから関係を取得する

Last updated at Posted at 2018-12-14

この記事について

Laravel Advent Calendar 2018 - Qiita の14日目の記事です。

本記事ではコードは要点となる部分しか記述していないので、他の箇所も見たいという方はGitHubに公開したサンプル GitHub - kkznch/laravel_pivot_example を参照してください。

はじめに

概要

多対多リレーションを操作するための中間テーブルに三つ以上の関係を持たせた際に、pivot属性から関係先にどうやってアクセスするかについて書いていきます。

環境

  • PHP 7.2.4
  • Laravel 5.7.16

やりたいこと

テーブル構成が以下のようにあるとする。

20181214_LaravelAdventCalendar_ER図.png

上記のテーブル構成において、あるユーザが複数のグループに所属しているとき、それらのグループでそのユーザに割り振られているロールを以下のように取得したい。

$user->groups()->find(1)->pivot->role

実装手順

1. マイグレーションファイルを作成する

前述したテーブル構成通り id, name カラムを持つ users, groups, roles テーブルをそれぞれ定義する。

同様に user_id, group_id, role_id を持つ中間テーブル user_group テーブルを定義する。これらのカラムは users, groups, roles テーブルを参照する外部キーとする。

2. Group, Role モデルクラスを作成する

php artisan make:model コマンドで Group, Role モデルクラスをそれぞれ作成する。
なお、Group, Role モデルクラスの中身は空のままでよい。

3. UserRole Pivotクラスを作成する

以下のように UserRole Pivotクラスを作成する。

UserRole.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class UserGroup extends Pivot
{
    protected $table = 'user_group';

    public function role()
    {
        return $this->belongsTo(Role::class);
    }
}

継承しているのはModelクラスではなく、Pivotクラスなので注意すること。

4. User モデルクラスを作成する

ここが肝になる部分。
php artisan make:model コマンドで User モデルクラスを作成し、以下のように編集する。

User.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $fillable = ['name'];

    public function groups()
    {
        return $this
            ->belongsToMany(Group::class, 'user_group')
            ->using(UserGroup::class)->withPivot(['role_id']);
    }
}

using() で先程指定した中間テーブルのカスタムモデルとなるPivotクラスを指定し、 withPivot() でpivot属性を介して中間テーブルの指定した要素へのアクセスを可能にする。

使い方

php artisan tinker を起動して以下を実行してみる。

>>> $user = User::find(1)
>>> $user->groups()->find(1)
=> App\Group {
     id: 1,
     name: "グループ1",
     created_at: "2018-12-09 01:18:03",
     updated_at: "2018-12-09 01:18:03",
     pivot: App\UserGroup {#2894
       user_id: 1,
       group_id: 1,
       role_id: 1,
     },
   }

>>> $user->groups()->find(1)->pivot->role
=> App\Role {
     id: 1,
     name: "ロール1",
     created_at: "2018-12-09 01:18:03",
     updated_at: "2018-12-09 01:18:03",
   }

$user->groups()->find(1) を実行した段階ではpivot属性には user_id, group_id, role_id が含まれていることが分かる。

この状態で $user->groups()->find(1)->pivot->role を実行すると、User モデルクラスで定義した groups() から特定のグループに関する関係を取得し、更にpivot属性を介して UserRole Pivotクラスで定義した role() からロールに関する関係を取得できる。

おわりに

以前からQiitaに登録はしていたものの投稿はしていなかったため、今回が初の投稿となりました。
いつもは人が書いた記事を遠目で見て参考にしているだけでしたが、書いてみるのも割といいものだなと思いました。

記事中の実装や考え方について、間違っている or 他に良い方法などがあれば教えていただければ幸いです。

参考文献

59
55
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
55