未経験者がLaravel共同開発での詰まりポイントの「メモ」をまとめてみた【データベース（migration/seeding）編】

#はじめに
タイトルの通り、共同開発講座を受講中に起きたトラブルや詰まりポイントをまとめたメモ（約50記事）をジャンル別に全て公開します。
ジャンルは以下の通りなので、気になるものがあればぜひご覧ください。
###【ジャンル一覧】
・[GitHub関連](https://qiita.com/kei_Q/items/1e421eef9b3bdbcdd9e9)
・[Laravel関連](https://qiita.com/kei_Q/items/79ef7679b28bb3c9738e)
・[データベース（migration/seeding）関連](https://qiita.com/kei_Q/items/cf13f486628bb5662089)
・[環境関連](https://qiita.com/kei_Q/items/412a9695f26aad25a99c)
・[総まとめ集](https://qiita.com/kei_Q/items/e197268fc29fdd664b64)

下記の点を、ご了承ください。
・ジャンルで統一しているため、内容に関しては統一性はありません。
・メモの難易度もバラバラです。
・初学者向けの内容となっております。
・自分用のメモを転用しておりますので、表現が稚拙な部分があるかと思います。
**・あくまで僕のメモです！！**


#・Laravelのカラム作成で使えるデータ型

- increments('id') ... 「符号なしINT」を使用した自動増分ID（主キー）
- binary('カラム名') ... バイナリデータカラム
- boolean('カラム名') ... 真偽値カラム
- char('カラム名', 長さ) ... 長さを指定する文字列カラム
- date('カラム名') ... 日付カラム
- time('カラム名') ... 時間カラム
- dateTime(カラム名) ... 日時カラム
- double('カラム名', 桁数, 小数点以下桁数) ... ○桁で小数点以下×桁の小数カラム
- enum('カラム名', ['定数', '定数']) ... ENUMカラム
- integer('カラム名') ... 数値データカラム
- json('カラム名') ... JSONフィールドカラム
- timestamp('カラム名') ... TIMESTAMPカラム
- timestamps() ... created_atとupdate_atカラム
- nullableTimestamps() ... NULL値を許す以外、timestamps()と同じ
- string('カラム名') ... VARCHARカラム
- string('カラム名', 長さ) ... 長さ指定のVARCHARカラム
- text('カラム名') ... TEXTカラム


#・migration時の外部キー制約エラー

外部キー制約をつけてマイグレーションをするとエラーが起きてしまう件について

まず外部キー制約について
####外部キー制約の一例

```php

$table->foreign('sale_status_id')->references('sale_status_id')->on('m_sales_statuses')->onDelete('cascade');
```

####解説
子テーブルのカラムとして定義したsale_status_idを外部キーと指定し、それはm_sales_statusesというテーブルのsale_status_idというカラムと紐付くこととする

onDelete(‘cascade’)・・・親テーブルの行を削除したときに、子テーブルないの一致する行を自動的に削除されるようにするオプションのこと。例えばユーザーが消えるとそのユーザが持っている動画が消える等。

エラー内容を見ていきます

####エラー内容

```
 Illuminate\Database\QueryException  : SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `m_products` add constraint `m_products_sale_status_id_foreign` foreign key (`sale_status_id`) references `m_sales_statuses` (`sale_status_id`))
```

####原因
**①データの型が合っていない**
Integer やstring、unsignedなど　　
上記のカラム作成で使えるデータ型を確認する（これが割と間違ってることが多い）

**②マイグレーションする順番が違う(作成順序が違う)**
親テーブルと子テーブルがあるが、先に参照される側の親テーブルを先にマイグレーションしてテーブルを作成しておかないといけない。
親テーブルが存在して初めて、外部キー制約を記述したものをマイグレーションできる


#・seeding時のエラー

migrationはできたけどデータの流し込み（seedingがうまくいかない）
seedingを行うとエラーが発生する

####エラー内容

```
 Illuminate\Database\QueryException  : SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`laravel`.`m_products`, CONSTRAINT `m_products_sale_status_id_foreign` FOREIGN KEY (`sale_status_id`) REFERENCES `m_sales_statuses` (`sale_status_id`) ON DELETE CASCADE) (SQL: insert into `m_products` (`product_id`, `product_name`, `category_id`, `price`, `description`, `sale_status_id`, `product_status_id`, `resist_date`, `user_id`, `delete_flag`) values (1, 黒毛和牛サーロイン, 1, 8000, なめらかでとろける食感と、甘くコクがある上品な香りが特徴です, 1, 1, 2020-11-22 12:16:43, 1, ))
```

####原因と解説
子テーブルに外部キー制約が存在する場合、seedingの順番にも気をつける必要がある。
親テーブルより先に子テーブルをmigrationした場合にエラーが出たのと同様の理由でエラーが出る。
seeding時も親テーブルにデータが入っていない状態で、外部キーがある子テーブルにデータを流し込むとエラーが発生する。
**seedingに関しても親→子の順番でseedingを行わなければならない**


#・SQL 1364 エラー

ブラウザ上でフォームを飛ばした時に起こるエラーです

####エラー内容

```
SQLSTATE[HY000]: General error: 1364 Field 'user_classification_id' doesn't have a default value
```

####エラーの意味
**「user_classification_idのデフォルト値がない」**

つまり…
「データベースにデータを登録する際に、user_classification_idの値がないとダメですよ」
っていう意味。
**デフォルト値**をつけろと言われている。

####解決策
今回はフォームにuser_classification_idの要素を入力する欄がなかったため、データを登録時に送ることができなかった。
でも、データベースのusersテーブルにはuser_classification_idが存在するため、どうにかしてデータを入れないといけない。
そこで、migrationの段階で手を打っておく必要がある。
具体的には、migrationでusersテーブルのカラム定義の際に、修飾子をつけること。
修飾子は　->nullable() 　もしくは　->default(○○)
つまり存在しなくても良しとするか、デフォルト値を予め設定しておく。というような修飾子をつけて、マイグレーションすることでこのエラーは解決する。
ただ、可能な限り　->default(○○)　を使ったほうがいい。

**例）m_users.php(マイグレーションファイル)**

```php
public function up()
    {
        Schema::create('m_users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('password', 64);
            $table->string('last_name', 16);
            $table->string('first_name', 16);
            $table->integer('zipcode');
            $table->string('prefecture', 16);
            $table->string('municipality', 16);
            $table->string('address', 32);
            $table->string('apartments', 32);
            $table->string('email', 128);
            $table->string('phone_number', 16);
            $table->integer('user_classification_id')->unsigned()->default(1);//←ここ！！　
            //外部キー制約
            $table->foreign('user_classification_id')->references('id')->on('m_users_classifications')->onDelete('cascade');
            
            $table->string('company_name', 128)->nullable();//←ここ！！　
            $table->char('delete_flag', 1)->nullable();//←ここ！！　
            $table->rememberToken();
            $table->timestamps();
        });
    }
```

#・マイグレーション実行コマンド

**カラムの追加をしたいときのマイグレーションファイルの作成コマンド**

```
$ php artisan make:migration add_title_to_users_tables  - -table=users
```

**マイグレーション実行コマンド**

```
php artisan migrate:reset

```

全てのテーブルにおいて今まで実行したマイグレーションを初期化。
再度migrationは実行されない。

```
php artisan migrate:refresh
```

全てのテーブルにおいて今まで実行したマイグレーションを初期化
再度migrationを実行する。

```
php artisan migrate:fresh
```

全てのテーブルを削除。
再度migrationを実行する。

```
php artisan migrate:rollback
```

最後に実行したマイグレーションを元に戻す。
Step オプションをつけると元に戻す回数を指定できる。


#・migration と seeding の総まとめ


####マイグレーションとは
ザックリ言うとテーブルを作成するための作業
マイグレーションファイルをコマンドで作成し、作りたいテーブルのカラムを記載していく。
記載したファイルをコマンドでマイグレーションすると、データベースにテーブルが作成される。
また、マイグレーションファイルにはカラムに対してデータ型や修飾子、FKを記載しておくとマイグレーション実行時に反映される。
ただ、FKの関係でマイグレーションする順番が重要になってくるので、マイグレーションファイルを作成する順番に気を付ける。（FKで指定されているテーブルがないと、エラーが起こるので、先に親テーブルからマイグレーションされるように作成順番を考える。→子テーブルを後に作成する）
今回はphpmyadminを使用しているので、ブラウザ上で視覚的に確認することができる。
Phpmyadmin上で、使用するデータベースを作成しておかないと、テーブルをその中に作ることができないので注意


####マイグレーションファイルの作成（カラム、FK、その他修飾子の作成）
　php artisan make:migration ファイル名
でファイル作成。

ファイルの中身はこんな感じ

```php
　public function up()
    {
        Schema::create('m_products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('product_name', 64);
            $table->integer('category_id')->unsigned();
            $table->integer('price')->unsigned();
            $table->string('description', 256);
            $table->integer('sale_status_id')->unsigned();
            $table->integer('product_status_id')->unsigned(); 
            $table->timestamp('resist_date');
            $table->integer('user_id')->unsigned();
            $table->char('delete_flag', 1);

            $table->foreign('sale_status_id')->references('id')->on('m_sales_statuses')->onDelete('cascade');
            $table->foreign('product_status_id')->references('id')->on('m_products_statuses')->onDelete('cascade');
        });
    }
```


####データ型について
上記のファイル内の記載のうち、string integer timestamp などがデータ型にあたる。
そのデータはどういう形式のデータなのか？文字なのか？数字なのか？その時の時間なのか？
を指定することができる。詳しくはGoogle先生に。


####php artisan migrate の実行
このコマンドを実行すると、作成したマイグレーションファイルがテーブルとして作成される。
エラーになる場合は、他のエラーに関するメモを参照(上記記載)。


####migrationエラーについて
多かったエラーは
①データ型があっていない場合
②migrationする順番が違い、外部キー制約がつかないために起こるエラー


####シーディングとは
ザックリい言うと、テストデータを一気に作成することができる機能で、ファイルを作成してシーディングを行うことテーブル内にデータが挿入される。


####テストデータの決定
シーディングを行うテーブルに適したデータを考える。
例えば、商品（肉とか魚）のテストデータを考える時は、それぞれのカラムに適応した具体的なデータ（商品名や値段）を考える。
何個でも一気に登録できるが、まぁ、テストなので5~10個程度あれば十分。


####シーディングファイルの作成
　php artisan make:seeder ファイル名
上記コマンドでシーディングファイルが作成される。

中身には前項で決定したテストデータを記載していく。

実際の内容としてはこんな感じ

```php
public function run()
    {
        DB::table('m_products')->insert([
           'id' => 1,
           'product_name' => '黒毛和牛サーロイン',
           'category_id' => 1,
           'price' => 8000,
           'description' => 'なめらかでとろける食感と、甘くコクがある上品な香りが特徴です' ,
           'sale_status_id' => 1,
           'product_status_id' => 1,
           'resist_date' => date('Y-m-d H:i:s'),
           'user_id' => 1,
           'delete_flag' => ''
        ]);
        DB::table('m_products')->insert([
            'id' => 2,
            'product_name' => 'A5ランク松坂牛',
            'category_id' => 1,
            'price' => 12000,
            'description' => '松坂牛は濃厚で上品な甘みが絶品！' ,
            'sale_status_id' => 1,
            'product_status_id' => 1,
            'resist_date' => date('Y-m-d H:i:s'),
            'user_id' => 1,
            'delete_flag' => ''
         ]);
```

例として２つだけここに書いたが、実際は何個でも良い。


####php artisan db seed  の実行
このコマンドを実行することで、作成したシーディングファイル（テストデータ込み）がシーディングされて、当該テーブルにデータが挿入される。
このコマンドの実行時にエラーとしてよく起こるのは
①子テーブルと親テーブルの関係
②外部キー関連
が多いが、詳しくは別のメモにまとめてあるものを参照(上記記載)。