LaravelでSQLiteの外部キー制約を有効にする

こんにちは。この度、新加入いたしました「ふっくん」です。
よろしくお願いいたします。

さて、現在Laravelを使用して開発を行っており、ローカル環境ではDBにSQLiteを採用しました。
その際の、外部キー制約を設定する方法を備忘録として残します。

SQLiteでは、SQLite3から外部キーの設定が可能になりました

また、DBの作成はマイグレーションで行います。
マイグレーションについての説明は過去記事のLaravel 5.3 Eloquent ORM 入門 2 (マイグレーション)をご確認ください。

※以下に記載する内容は Laravel 5.5.3 を前提としております。

LaravelでSQLiteを使用するには?

SQLiteを使用するには、まずLaravelにSQLiteの設定をしてあげないといけません。
.envファイルを以下のように編集してください。

DB_CONNECTION=sqlite
DB_HOST=/*SQLiteに接続するためのホスト*/
DB_PORT=/*SQLiteに接続するためのポート番号*/
DB_USERNAME=/*SQLiteに接続するためのユーザー名*/
DB_PASSWORD=/*SQLiteに接続するためのパスワード*/

編集が完了したら、databaseディレクトリ直下にtouch database.sqliteなどで、database.sqliteというファイルを作成すればOKです!
これで、LaravelからSQLiteに接続する準備は整いました!

外部キー制約のコードはどこに書けばいいの?

さて、これから外部キー制約のコードを書いていくのですが、そのコードはどこに書けばいいのでしょう?

今回は、サンプルとしてgroups_tableusers_tableを用意します。
ディレクトリ構成はこんな感じです!

database
  └ migrations
     ├2017_11_10_000001_create_groups_table.php
     └2017_11_10_000002_create_users_table.php

groups_tableを参照先テーブル、users_tableを参照元テーブルとします。
外部キー制約のコードは参照元テーブルに記載します!!
つまりここで言うと2017_11_10_000002_create_users_table.phpに記載すればいいのです。
それでは、実際にどんなコードになるかと言うと、

public function up(){
  Schema::create('users', function (Blueprint $table) {
    $table->integer('id')->unsigned();
    $table->primary('id');
    $table->integer('group_id');
    $table->string('user_name');
    $table->timestamps();
    $table->softDeletes();

    // 外部キー制約
    $table->foreign('group_id') // このテーブルの外部キー列
    ->references('id') // 参照先テーブルの ID 列
    ->on('groups') // 参照先テーブル
    ->onDelete('restrict');
  });
}

こんな感じです!
テーブルを作る順番に気をつけてくださいね。
「参照先」を作ってから「参照元」を作らないと怒られます。
外部キーを削除するコードも忘れずに書いてくださいね。

public function down(){
  Schema::table('users', function (Blueprint $table) {
    $table->dropForeign(['group_id']);
  });

  Schema::dropIfExists('users');
}

SQLiteの外部キー制約を有効にする

しかし、どうやらこれだけではSQLiteの外部キー制約は有効にならないようです。
なぜ有効にならないのか?

SQLiteの公式サイトを見てみると、

Foreign key constraints are disabled by default (for backwards compatibility), so must be enabled separately for each database connection.
後方互換のため外部キー制約はデフォルトで無効になっていますので、データベース接続ごとに有効にする必要があります。

ふむ。
SQLiteの外部キー制約を有効にするにはPRAGMA foreign_keys = ON;のコマンドを実行しろ!とありますね。
しかし、今回はSQLiteのコマンドを叩くのではなく、Laravel上でソースコードを書いて外部キー制約を有効したい。
どうすれば。。。。

その答えは、Laravel公式サイト(ページ下部)にありました!!!

You may enable or disable foreign key constraints within your migrations by using the following methods:

Schema::enableForeignKeyConstraints();

Schema::disableForeignKeyConstraints();

ふむ。
外部キー制約を有効にするにはSchema::enableForeignKeyConstraints();メソッドを書け!とありますね。
これをマイグレーションコードに書いてあげてください。

今回はマイグレーション以外でも有効にしたいのでAppServiceProvider.phpに書きました。

app
  └ Providers
     └AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Schema; // <- 追加
use Illuminate\Support\ServiceProvider;
use DB; // <- 追加

class AppServiceProvider extends ServiceProvider {
  public function boot() {
    // SQLiteの時、外部キー制約を有効にする
    if (\DB::getDriverName() == 'sqlite') {    // <- 追加
      Schema::enableForeignKeyConstraints();
    }
  }

  public function register() {
        //
  }
}

ここまで完了したらマイグレーションを実行しましょう!!
php artisan:migrate

そして、SQLiteの中を見てみると、、、、
(私はDB Browser for SQLiteでSQLiteの中身を確認しています。)

FOREIGN KEY(`groups_id`)

きたーーーー!!!
めでたしめでたしでした。

SNSでもご購読できます。