Unity(C#)初心者・入門者向けチュートリアル ひよこのたまご

AndroidやiOS向けアプリを簡単に作れるゲーム開発環境Unity(ユニティ)の使い方を、チュートリアル方式で一緒に学びましょう!

【Laravel】Eloquentのリレーション④ belongsToManyによる多対多の関係

PHPバージョン:7.1.14
Laravelバージョン:5.7.9

今回はLaravelのEloquentリレーション、
多対多についてです!
belongsToManyというメソッドを使います!


Roleモデルを作成

まずはRoleモデルを作成します!
admin(管理者)・編集者(editor)・閲覧者(visitor)
の権限を管理するモデルです。
Author対Roleが多対多となるように作成していきます。

$ php artisan make:model Models/Role

app>Modelsディレクトリに、
Role.phpモデルが作成されました。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    protected $guarded = array('id');

    public function authors() {
        return $this->belongsToMany('App\Models\Author', 'author_role', 'role_id', 'author_id')->withTimeStamps();
    }
}

app>Models>Role.php

authorsメソッドを作成し、
belongsToManyメソッドでAuthorと多対多の関係構築します。

belongsToManyの引数は以下のように設定します。
第1引数:参照先テーブルのモデルのパス
第2引数:中間テーブル(SQL)のテーブル名
(省略時アルファベット順テーブル名を並べる。例:author_role)
第3引数:中間テーブルの参照元外部キー
(今回でいうrole_id。省略時"参照元モデル名_id")。
第4引数:中間テーブルの参照先外部キー
(今回でいうauthor_id。省略時"参照先モデル名_id"。)

最後にwithTimeStamp()をチェーンすることで、
更新時にupdated_atカラムが更新されます。

roleテーブルのMigration

続いてroleテーブルのMigrationを実行していきます。

$ php artisan make:migration create_roles_table

作成されたMigrationファイルを編集します。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateRolesTable extends Migration
{
    public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('roles');
    }
}

database>migrations>xxxx_xx_xx_xxxxxx_create_roles_table.php

デフォルトからstring型のnameカラムを追加しました。
またユニークキー制約を付けました。(重複対策)

ついでにSeedingにより、rolesテーブルにデータを登録していきましょう。

$ php artisan make:seeder RolesSeeder

Seedingファイルを作成し、

<?php

use Illuminate\Database\Seeder;

class RolesSeeder extends Seeder
{
    public function run()
    {
        $param = [
            'name' => 'admin',
        ];
        DB::table('roles')->insert($param);

        $param = [
            'name' => 'editor',
        ];
        DB::table('roles')->insert($param);

        $param = [
            'name' => 'visitor',
        ];
        DB::table('roles')->insert($param);
    }
}

database>seeds>RolesSeeder.php

Seedingファイルにデータを書き込み、

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call(ArticlesSeeder::class);
        $this->call(AuthorsSeeder::class);
        $this->call(RolesSeeder::class);
    }
}

database>seeds>DatabaseSeeder.php

DatabaseSeederへRolesSeederを登録し、

$ php artisan db:seed

database>seeds>RolesSeeder.php

Seedingを実行します。

Authorモデル編集

続いて既に作成されているAuthorモデルを編集していきます!

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Author extends Model
{
    public function roles() {
        return $this->belongsToMany('App\Models\Role', 'author_role', 'author_id', 'role_id')->withTimeStamps();
    }
}

app>Models>Author.php

参照先外部キーが入れ替わったのみで、
Roleモデルとほぼ同じ形です。

ちなみに今回のbelongsToManyの第2第3第4引数に関しては、
Laravelの規約に沿っているのでRoleモデルAuthorモデル共に省略可能です。

中間テーブルをMigrationで作成

多対多の関係を作るためにはauthorsテーブルとrolesテーブルの他に、
中間テーブルを作成する必要があります。
名前の通り、authorsとrolesの間のテーブルです。
author_roleという中間テーブルを作成します。

$ php artisan make:migration create_author_role_table

作成されたMigrationファイルを編集します。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateAuthorRoleTable extends Migration
{
    public function up()
    {
        Schema::create('author_role', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('author_id');
            $table->integer('role_id');
            $table->timestamps();

            $table->unique(['author_id', 'role_id']);
            $table->foreign('author_id')
                ->references('id')
                ->on('authors')
                ->onDelete('cascade');
            $table->foreign('role_id')
                ->references('id')
                ->on('roles')
                ->onDelete('cascade');
        });
    }

    public function down()
    {
        Schema::dropIfExists('author_role');
    }
}

database>migrations>xxxx_xx_xx_xxxxxx_create_author_role_table.php

author_idとrole_idを作成します。
各idは、ユニークな外部キーとして設定します。
参照先はauthod_idがauthorsテーブルのid、
role_idがrolesテーブルのidです。

onDelete('cascade')をチェーンしておくことで、
参照先テーブル(authorsもしくはroles)のデータが削除された時、
関連する中間テーブル(author_role)のデータも削除されます。

中間テーブルにデータを登録

それでは中間テーブルにデータを登録していきます。
今回はLaravelのコンソールデバッグ機能のtinkerを使用します。

$ php artisan tinker

こちらのコマンドでtinkerは実行されます。
コンソール上で対話式にデバッグを行うことができます。

$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.1.14 — cli) by Justin Hileman
>>> 

php artisan tinker とコマンドを打つことでデバッグが開始されます。

まずはauthorsテーブルのid=1一郎くんに、admin,editor,visitorと全ての権限を与えましょう。

>>> App\Models\Author::find(1)->roles()->attach([1,2,3]);
=> null
>>> 

"App\Models\Author::find(1)"にて一郎くんを取得し、
Authorモデルで先ほど作成した"->roles()"メソッドから、
更にチェーンして"->attach()"メソッドを実行します。
引数に登録したいrolesテーブルのidを指定します。
結果はnullとそっけないですが、
MySQLでauthor_roleテーブルを確認するとちゃんと登録されています。

mysql> select * from author_role;
+----+-----------+---------+---------------------+---------------------+
| id | author_id | role_id | created_at          | updated_at          |
+----+-----------+---------+---------------------+---------------------+
|  1 |         1 |       1 | 2018-11-12 07:56:39 | 2018-11-12 07:56:39 |
|  2 |         1 |       2 | 2018-11-12 07:56:39 | 2018-11-12 07:56:39 |
|  3 |         1 |       3 | 2018-11-12 07:56:39 | 2018-11-12 07:56:39 |
+----+-----------+---------+---------------------+---------------------+
3 rows in set (0.00 sec)

author_id=1に、role_id=1,2,3と全ての権限が登録されています。

ちなみに確認する時はプロパティの形でアクセスします。

>>> App\Models\Author::find(1)->roles->toArray();
=> [
     [
       "id" => 1,
       "name" => "admin",
       "created_at" => null,
       "updated_at" => null,
       "pivot" => [
         "author_id" => 1,
         "role_id" => 1,
         "created_at" => "2018-11-12 07:56:39",
         "updated_at" => "2018-11-12 07:56:39",
       ],
     ],
     [
       "id" => 2,
       "name" => "editor",
       "created_at" => null,
       "updated_at" => null,
       "pivot" => [
         "author_id" => 1,
         "role_id" => 2,
         "created_at" => "2018-11-12 07:56:39",
         "updated_at" => "2018-11-12 07:56:39",
       ],
     ],
     [
       "id" => 3,
       "name" => "visitor",
       "created_at" => null,
       "updated_at" => null,
       "pivot" => [
         "author_id" => 1,
         "role_id" => 3,
         "created_at" => "2018-11-12 07:56:39",
         "updated_at" => "2018-11-12 07:56:39",
       ],
     ],
   ]
>>> 

同じ要領で、
authorsテーブルのid=2二郎くんにはid=2のeditorとid=3のvisitor権限を、
id=3三郎くんにはid=3のvisitor権限のみを付与します。

>>> App\Models\Author::find(2)->roles()->attach([2,3]);
=> null
>>> App\Models\Author::find(3)->roles()->attach([3]);
=> null
>>> 

MySQLで確認します。

mysql> select * from author_role;
+----+-----------+---------+---------------------+---------------------+
| id | author_id | role_id | created_at          | updated_at          |
+----+-----------+---------+---------------------+---------------------+
|  1 |         1 |       1 | 2018-11-12 07:56:39 | 2018-11-12 07:56:39 |
|  2 |         1 |       2 | 2018-11-12 07:56:39 | 2018-11-12 07:56:39 |
|  3 |         1 |       3 | 2018-11-12 07:56:39 | 2018-11-12 07:56:39 |
|  4 |         2 |       2 | 2018-11-12 08:03:16 | 2018-11-12 08:03:16 |
|  5 |         2 |       3 | 2018-11-12 08:03:16 | 2018-11-12 08:03:16 |
|  6 |         3 |       3 | 2018-11-12 08:03:26 | 2018-11-12 08:03:26 |
+----+-----------+---------+---------------------+---------------------+
6 rows in set (0.01 sec)

無事登録されました。

RoleモデルからAuthorを確認する。

先ほどはAuthorモデルからRoleモデルを確認しました。
もちろん逆パターンも可能です。
既に中間テーブルも登録されているので、さっそく確認します。

>>> App\Models\Role::find(2)->authors->toArray();
=> [
     [
       "id" => 1,
       "name" => "一郎",
       "created_at" => null,
       "updated_at" => null,
       "pivot" => [
         "role_id" => 2,
         "author_id" => 1,
         "created_at" => "2018-11-12 07:56:39",
         "updated_at" => "2018-11-12 07:56:39",
       ],
     ],
     [
       "id" => 2,
       "name" => "二郎",
       "created_at" => null,
       "updated_at" => null,
       "pivot" => [
         "role_id" => 2,
         "author_id" => 2,
         "created_at" => "2018-11-12 08:03:16",
         "updated_at" => "2018-11-12 08:03:16",
       ],
     ],
   ]
>>> 

role_id=2のeditor権限を取得している、
id=1一郎とid=2の二郎のデータを取得できました。

今回はここまでです、ありがとうございました〜!