【Laravel】リレーション後に外部キー設定を行う

# リレーションと外部キー

以前、リレーションの作業を行なった。
[【Laravel入門】リレーションとユーザーの一覧表示](https://qiita.com/33yuki/items/b7186f05d1c266076a35)

そして、動作確認のためユーザーの削除を行ってみたが、予想と違う結果となった。自分の予想ではこうなるはずだったのに・・・

「ユーザーが削除されると、自動的にそのユーザーの投稿記事が削除される。」

しかし、削除されたユーザーに紐づく投稿記事が消えない。これは``外部キー``の設定を忘れていたためだった。ちなみに、自分の持つ外部キー関連の概念はこんなところだ。

- ユーザーが保管されている``usersテーブル``と投稿記事が保管されている``articlesテーブル``は、``１対多``の関係にある。
- articlesテーブルは``user_id``を元にusersテーブルから記事の作成者情報を得ている。この状態は、articlesテーブルが``従テーブル``、usersテーブルが``主テーブル``だと言える。
- 従テーブルで主テーブルを参照するために使われるキーを``外部キー``と呼ぶ。

今回はその設定を行うことにした。

# 外部キー用のマイグレーションファイルを作成

上記の設定を行うためには、``user_id``を外部キーに設定しなければならない。

既存の``create_articles_table``にその設定を書き加えて行く方法もあるらしいが、``user_id``は他のカラムと役割が違う。（それに記述が上手く出来ず、何回か失敗した；）

そのため、``user_id``の設定は独立したマイグレーションファイル``add_user_id_articles_table``に記述することにした。

## create_articles_tableの編集

``user_id``を専用ファイルで作成するため、``create_articles_table``から``$table->integer('user_id');``を削除した。

```yyyy_mm_dd_hhmmss_create_articles_table.php
<?php

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

class CreateArticlesTable extends Migration
{
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            // $table->integer('user_id');を削除
            $table->string('title');
            $table->string('content');
            $table->timestamps();
        });
    }

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

## add_user_id_articles_tableの作成

``add_user_id_articles_table``を新たに作成し、編集する。

```
$ php artisan make:migration add_user_id_articles_table
```

```yyyy_mm_dd_hhmmss_add_user_id_articles_table.php
<?php

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

class AddUserIdArticlesTable extends Migration
{
    public function up()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')
            ->references('id')->on('users')
            ->onDelete('cascade');
        });
    }

    public function down()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->dropForeign('articles_user_id_foreign');
        });
    }
}
```

内容を説明する。

### up関数

- ``Schemaファサード``の``tableメソッド``を使用する。
- tableメソッドは第１引数に``テーブル名``、第２引数に``Blueprintインスタンスの$table``を指定する。
- ``$table``の``integerメソッド``で``user_id``を作成し、``カラム修飾子unsignedメソッド``を実行する。 
- ``unsignedメソッド``はMySQLで整数カラムを符号なしに設定する。``これを実行しないとエラーが発生するので注意すること。``
- ``foreignメソッド``で``user_id``を外部キーに設定する。
- ``referencesメソッド``で、従テーブルの``user_id``と紐付いている主テーブルの``id``を指定する。
- ``onメソッド``で主テーブル``users``を指定する。
- ``onDeleteメソッド``で``user``が削除・更新された場合の処理を記述する。今回、引数は``cascade``を指定する。

``onDeleteメソッド``には、以下４種類の引数がある。

- cascade
- set null
- no action
- restrict


詳細はこちらのサイト様から。
[Laravel 5.3 Eloquent ORM 入門 2 (マイグレーション)](https://mseeeen.msen.jp/laravel-53-eloquent-orm-2/#i-8)


### down関数

- 外部キーを削除するためには``dropForeignメソッド``を使用する。
- dropForeignメソッドの引数は、命名規則により``テーブル名_外部キー名_foreign``となる。

# 動作確認

``tableメソッド``を``createメソッド``と間違えたり、``unsigned()``を記述し忘れたり、途中でエラーの連続だった。

```
$ php artisan migrate:refresh
Rolling back: 2018_05_03_141933_create_articles_table
Rolled back:  2018_05_03_141933_create_articles_table
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table

In Connection.php line 664:

  SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'user_id' (SQL: alter table `a
  rticles` add `user_id` int not null)


In Connection.php line 458:

  SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'user_id'
```

何とかマイグレーションファイルを正しく編集し、migrationを実行できた。以下のコマンドでは、テーブルが存在しないのに``refresh``しているため、最初に``Migration table not found.``と怒られている；

```
$ php artisan migrate:refresh
Migration table not found.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
Migrating: 2018_05_03_141933_create_articles_table
Migrated:  2018_05_03_141933_create_articles_table
Migrating: 2018_05_16_185519_add_user_id_articles_table
Migrated:  2018_05_16_185519_add_user_id_articles_table
```

これで、ユーザーを削除すると、そのユーザーに紐づく投稿記事も削除されるようになった。

今回はここまで。