LoginSignup
1
5

More than 5 years have passed since last update.

開発における悩ましいデータベース共有問題を解決するLaravelのマイグレーションとシーダー解説編~アジャイルでDevOpsなシステム構築実践~

Posted at

開発におけるデータベースに関する悩み

Githubからプルしたら、ある画面が動かない。
結合フェーズに入ったら、システムが動かない。
原因はテーブルのスキーマがいつの間にか変わっていた…
なんてことはありませんか?

Laravelにおいてはマイグレーションとシーダーを使えばこのような問題を解決できます!

マイグレーションのメリット

Laravel(をはじめとするPHPフレームワーク)にはマイグレーションという機能があり、プログラムでデータベースのスキーマを管理できます。
プログラムなのでバージョン管理が可能なので、テーブル設計を変更の影響を最小限にしたり、開発メンバー間での共有もテーブル変更をマイグレーションファイルに記載したら、GitHubにコミットし、メンバーにプルしてもらい、マイグレーションを実行してもらうだけで、テーブルを共通化することが可能です。

マイグレーションとモデルの密接な関係

Laravelにおいてモデルはテーブルに1対1で関連づきます。
マイグレーションファイルと同時に作るほうが便利です。

シーダー

初期データ挿入の際にはシーダーを利用します。
こちらもマイグレーションと同様にプログラム化できるので、GitHubなどでデータ共有を楽にすることが可能です。

マイグレーションファイルとモデルファイルを自動生成

モデルファイルを自動生成する際に、オプションで"-m"をつけると、マイグレーションファイルも生成されます。

マイグレーションファイルとモデルファイルを自動生成
$ php artisan make:model {モデル名} -m
例:roundというモデルを生成
$ php artisan make:model round -m
Model created successfully.
Created Migration: 2017_12_12_231913_create_rounds_table

上記コマンドを実行すると"/database/migrations"フォルダに
2017_12_12_224229_create_rounds_table.php
というファイルが生成され"/app"フォルダに
Round.php
というファイルが生成されます。

モデル名は単数形(Round)、テーブルは複数形(rounds)になります。

マイグレーション

マイグレーションファイルはテーブルのスキーマを定義します。
ほとんど空のマイグレーションファイルに、テーブルのスキーマをメソッドを使い定義します。
下記はマイグレーションファイルの例です。

シンプルなマイグレーションファイル

2017_12_12_224229_create_rounds_table.php
<?php

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

class CreateRoundsTable extends Migration
{
    /**
     * マイグレーション実行
     *
     * @return void
     */
    public function up()
    {
        Schema::create('rounds', function (Blueprint $table) {
            $table
                ->increments('id')
                ->comment('ID');

            $table
                ->string('name')
                ->comment('試験実施回名');

            $table
                ->timestamp('created_at')
                ->default(DB::raw('CURRENT_TIMESTAMP'))
                ->comment('登録日');

            $table
                ->timestamp('updated_at')
                ->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'))
                ->comment('更新日');
        });
    }

    /**
     * ロールバック時に実行
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('rounds');
    }
}

upメソッドにマイグレーション実行時に動作するプログラム、downメソッドにロールバック時に実行に動作するプログラムを書きます。
downメソッドにはテーブルを削除する記述を書きます。

テーブル定義する際のメソッドの説明はLaravel 5.5 データベース:マイグレーション
の「カラム」を参照してください。

外部参照制約をつけたマイグレーションファイル

下記のようなコードを書くと、外部参照制約を追加できます。

外部参照制約の例
$table
    ->foreign('firstcategory_id')
    ->references('id')
    ->on('firstcategories')
    ->onDelete('RESTRICT')
    ->onUpdate('RESTRICT');

外部参照制約を追加した例

2017_12_13_012322_create_questions_table.php
<?php

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

class CreateQuestionsTable extends Migration
{
    /**
     * マイグレーション実行
     *
     * @return void
     */
    public function up()
    {
        Schema::create('questions', function (Blueprint $table) {
            $table
                ->increments('id')
                ->comment('ID');

            $table
                ->integer('number')
                ->unsigned()
                ->comment('問題番号');

            $table
                ->text('body')
                ->comment('問題文');

            $table
                ->text('commentary')
                ->comment('解説');

            $table
                ->integer('firstcategory_id')
                ->unsigned()
                ->comment('小項目ID 外部参照 firstcategories.id');

            $table
                ->integer('divition_id')
                ->unsigned()
                ->comment('問題種別ID 外部参照 divitions.id');

            $table
                ->integer('round_id')
                ->unsigned()
                ->comment('試験実施回ID 外部参照 rounds.id');

            $table
                ->integer('examination_id')
                ->unsigned()
                ->comment('試験区分ID 外部参照 examinations.id');

            $table
                ->timestamp('created_at')
                ->default(DB::raw('CURRENT_TIMESTAMP'))
                ->comment('登録日');

            $table
                ->timestamp('updated_at')
                ->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'))
                ->comment('更新日');

            /*
             * 外部参照制約 小項目
             */
            $table
                ->foreign('firstcategory_id')
                ->references('id')
                ->on('firstcategories')
                ->onDelete('RESTRICT')
                ->onUpdate('RESTRICT');

            /*
             * 外部参照制約 問題種別
             */
            $table
                ->foreign('divition_id')
                ->references('id')
                ->on('divitions')
                ->onDelete('RESTRICT')
                ->onUpdate('RESTRICT');

            /*
             * 外部参照制約 試験実施回
             */
            $table
                ->foreign('round_id')
                ->references('id')
                ->on('rounds')
                ->onDelete('RESTRICT')
                ->onUpdate('RESTRICT');

            /*
             * 外部参照制約 試験区分
             */
            $table
                ->foreign('examination_id')
                ->references('id')
                ->on('examinations')
                ->onDelete('RESTRICT')
                ->onUpdate('RESTRICT');

        });
    }

    /**
     * ロールバック時に実行
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('questions');
    }
}

マイグレーション実行

次のコマンドでマイグレーションを実行すると、テーブルが生成されます。

マイグレーションを実行
$ php artisan migrate
Migrating: 2017_12_12_224229_create_rounds_table
Migrated:  2017_12_12_224229_create_rounds_table

この通りテーブルが作成されました!

rounds.PNG

モデル

Laravelの命名に規則に従えばモデルは空でも役割を果たします。

Round.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Round extends Model
{
    //
}

ORマッパーのEloquentを使い際は、モデルにhasOneやhasManyやbelongsToを記載します。
※2017年12月13日時点でEloquentを利用して動作確認をしていません。
※メソッド名が異なるとうまく動作しないので注意してください(結構シビアです)。

Question.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Question extends Model
{
    /*
     * belongsTo設定
     * 小項目を参照
     */
    public function firstcategory()
    {
        return $this->belongsTo('App\Firstcategory');
    }

    /*
     * belongsTo設定
     * 問題種別を参照
     */
    public function divition()
    {
        return $this->belongsTo('App\Divition');
    }

    /*
     * belongsTo設定
     * 試験実施回を参照
     */
    public function round()
    {
        return $this->belongsTo('App\Round');
    }

    /*
     * belongsTo設定
     * 試験区分を参照
     */
    public function examination()
    {
        return $this->belongsTo('App\Examination');
    }
}

シーダー

テンプレートを自動生成

シーダーを自動生成
$ php artisan make:seeder RoundsTableSeeder
Seeder created successfully.

コマンドを実行すると、"database/seeds"に
RoundsTableSeeder.php
が生成されます。
このテンプレートに追加するデータを作ります。
プログラムで管理できるので、単純な繰り返しはループを使えてデータ生成が楽にできます。

シーダーファイルを作成

RoundsTableSeeder.php
<?php

use Illuminate\Database\Seeder;

/*
 * Eloquentを利用するのでRoundモデルを使う
 */
use App\Round;

class RoundsTableSeeder extends Seeder
{
    /**
     * シーダーを実行
     *
     * @return void
     */
    public function run()
    {
        /*
         * 必要な情報を配列化
         */
        $round_names[] = '平成21年度春';
        $round_names[] = '平成21年度秋';
        $round_names[] = '平成22年度春';
        $round_names[] = '平成22年度秋';
        $round_names[] = '平成23年度特別';
        $round_names[] = '平成23年度秋';
        $round_names[] = '平成24年度春';
        $round_names[] = '平成24年度秋';
        $round_names[] = '平成25年度春';
        $round_names[] = '平成25年度秋';
        $round_names[] = '平成26年度春';
        $round_names[] = '平成26年度秋';
        $round_names[] = '平成27年度春';
        $round_names[] = '平成27年度秋';
        $round_names[] = '平成28年度春';
        $round_names[] = '平成28年度秋';
        $round_names[] = '平成29年度春';
        $round_names[] = '平成29年度秋';

        /*
         * ループしてデータを作成
         */
        foreach($round_names as $round_name)
        {
            Round::create([
                'name' => $round_name,
            ]);
        }
    }
}

シーダーを実行

シーダーを実行するとデータが入ります。

シーダー実行
$ php artisan db:seed --class=ExaminationsTableSeeder
(特に成功メッセージなし)

この通りデータが入りました!

rounds_data.PNG

マイグレーションとしーだを使えばデータベース管理が楽にできます!

1
5
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
1
5