【第四弾】Laravel入門資料
- Windows環境構築
- Mac環境構築
- Laravelとは
- ルーティング
- ビュー
- コントローラ
- マイグレーション
- モデル
- ここまでの知識の実践
- 検索・フィルタ
- ソフトデリート
- ページネーション
- 画像アップロード
- 認証ライブラリ
- 認証実装
- ミドルウェア・ロール
- 総合実践
📚 Laravel公式ドキュメント - Database: Migrations
https://laravel.com/docs/12.x/migrations
💡 この講座では、上記の公式ドキュメントを基に解説していきます。
公式ドキュメントは初学者には内容が難しいため、エッセンスを優しく噛み砕いて解説していきます。
マイグレーション(Migration)とは
マイグレーションとは、データベースのテーブル構造をコードで管理する仕組みです。
マイグレーションなしの問題点
従来のデータベース管理では、以下のような問題がありました:
- 手動でSQLを実行してテーブルを作成
- チームメンバー間でテーブル構造が異なる
- 本番環境と開発環境で構造が違う
- 変更履歴が追えない
- ロールバック(元に戻す)ができない
マイグレーションのメリット
- ✅ バージョン管理 - Gitでテーブル構造を管理できる
- ✅ 再現性 - コマンド1つで同じ構造を作れる
- ✅ チーム開発 - 全員が同じ構造で開発できる
- ✅ ロールバック - 変更を簡単に元に戻せる
- ✅ 履歴管理 - いつ何が変更されたかわかる
💡 例え話
マイグレーションは「データベースのGit」のようなものです。
コードと同じように、データベースの変更履歴を管理し、いつでも特定の状態に戻せます。
データベース設定
マイグレーションを実行する前に、データベースの接続設定を確認します。
💡 前提条件
- ✅ MySQLがインストール済み
- ✅
.envファイルでデータベース接続設定済み - ✅ データベースGUIツール導入済み
- • Mac: Sequel Ace
- • Windows: A5M2
.envファイルの設定例
プロジェクトのルートディレクトリにある .env ファイル:
# .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=your_password
接続確認
データベースに接続できるか確認します。
php artisan migrate:status
エラーが出なければ、データベース接続成功です!
⚠️ 注意
.env ファイルを変更した場合、キャッシュをクリアする必要があります:
php artisan config:clear
マイグレーションの作成
実際にマイグレーションファイルを作成してみましょう。
基本的な作成コマンド
php artisan make:migration create_products_table
これにより、database/migrations/ ディレクトリに新しいマイグレーションファイルが作成されます。
ファイル名の規則
作成されるファイル名の例:
2025_01_22_123456_create_products_table.php
タイムスタンプ + アンダースコア + 指定した名前
💡 タイムゾーン設定
マイグレーションファイルのタイムスタンプは、デフォルトでUTC(協定世界時)で作成されます。
日本時間で作成したい場合は、以下の設定を行ってください。
1. config/app.php を編集
// 変更前
'timezone' => 'UTC',
// 変更後
'timezone' => env('APP_TIMEZONE', 'UTC'),
2. .env ファイルに追加
APP_TIMEZONE=Asia/Tokyo
3. キャッシュをクリア
php artisan config:clear
これで、マイグレーションファイルのタイムスタンプやデータベースの日時データが日本時間(JST)になります。
命名規則
| 目的 | 命名例 |
|---|---|
| テーブル作成 | create_products_table |
| カラム追加 | add_price_to_products_table |
| カラム変更 | modify_description_in_products_table |
| テーブル削除 | drop_old_products_table |
💡 命名規則のポイント
- 1. スネークケースを使う
小文字 + アンダースコア(例: create_products_table) - 2. テーブル名は複数形にする
• ❌ 単数形:create_product_table
• ✅ 複数形:create_products_table - 3. なぜ複数形?
テーブルは「データの集合」を表すため、複数形が自然です。
また、Laravelの規約として、モデル名(単数形)とテーブル名(複数形)が対応します。
例: モデルProduct→ テーブルproducts
💡 重要な注意点
マイグレーションファイルの命名によって、生成されるテンプレートが少し変わります。
- create_xxx_table パターン
- •
Schema::create()を使ったテンプレートが生成される - • 新しいテーブルを作成する時に使う
- •
- add_xxx_to_yyy_table パターン
- •
Schema::table()を使ったテンプレートが生成される - • 既存のテーブルにカラムを追加する時に使う
- •
ただし、最終的な実装は自分で書く必要があります。
命名規則に従うことで、チームメンバーが「このマイグレーションは何をするか」を名前から推測できるようになります。
テーブル構造の定義
作成されたマイグレーションファイルを開いて、テーブル構造を定義します。
マイグレーションファイルの構造
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
up() メソッド
up() メソッドは、マイグレーション実行時に呼ばれます。
ここにテーブル作成やカラム追加の処理を書きます。
down() メソッド
down() メソッドは、ロールバック時に呼ばれます。
up() で行った処理を元に戻す処理を書きます。
💡 重要な原則
up() と down() は対になる必要があります。
• up() でテーブル作成 → down() でテーブル削除
• up() でカラム追加 → down() でカラム削除
カラムの定義
商品テーブルを例に、実際のカラムを定義してみましょう。
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id(); // id (BIGINT, AUTO_INCREMENT, PRIMARY KEY)
$table->string('name'); // 商品名 (VARCHAR 255)
$table->text('description'); // 説明 (TEXT)
$table->integer('price'); // 価格 (INT)
$table->integer('stock')->default(0); // 在庫数 (INT, デフォルト0)
$table->boolean('is_published')->default(false); // 公開状態 (BOOLEAN)
$table->timestamps(); // created_at, updated_at
});
}
よく使うカラム型
実務でよく使うカラム型のみを紹介します。他にも多くの型がありますが、まずはこれらを覚えましょう。
データ型は、MySQLで実際に作成されるカラムの型です。
💡 主キー(Primary Key)とは
主キーは、テーブルの各レコード(行)を一意に識別するためのカラムです。
• 重複しない(ユニーク)
• NULL(空)にならない
• 自動的に連番(1, 2, 3...)が割り振られる
Laravelの id() メソッドは、MySQLの BIGINT型(大きな整数)で主キーを作成します。
| Laravelメソッド | MySQLデータ型 | 用途 |
|---|---|---|
id() |
BIGINT UNSIGNED | 主キー(1, 2, 3...と自動採番) |
string('name') |
VARCHAR(255) | 短いテキスト(名前、タイトル、メールアドレス) |
text('description') |
TEXT | 長いテキスト(説明、本文、コメント) |
integer('price') |
INT | 整数(価格、数量、年齢) |
boolean('is_active') |
TINYINT(1) | 真偽値(0=false, 1=true)有効/無効、公開/非公開 |
foreignId('user_id') |
BIGINT | 外部キー(他のテーブルとの関連) |
timestamps() |
TIMESTAMP | created_at, updated_at(作成日時、更新日時) |
💡 補足
この講座では基本的なカラム型のみ紹介しています。
他にも decimal()(小数点付き数値)、date()(日付)、json()(JSON)など、様々な型があります。
詳しくは公式ドキュメントを参照してください。
📝 MySQLでのboolean型について
MySQLには真のBOOLEAN型は存在しません。boolean() メソッドは、実際には TINYINT(1) 型として作成されます。
• 0 = false(偽)
• 1 = true(真)
Laravelが自動的に true/false として扱ってくれるので、通常は意識する必要はありません。
よく使うカラム修飾子
カラムに追加の設定を加えることができます。実務でよく使う修飾子のみを紹介します。
| 修飾子 | 説明 | 例 |
|---|---|---|
nullable() |
NULL許可(空でもOK) | $table->string('phone')->nullable() |
default($value) |
デフォルト値を設定 | $table->integer('stock')->default(0) |
unique() |
一意制約(重複不可) | $table->string('email')->unique() |
comment('説明') |
カラムの説明を追加 | $table->string('name')->comment('商品名') |
💡 comment() について
comment() を使うと、データベースのカラムに日本語の説明を付けられます。
GUIツール(Sequel AceやA5M2)でテーブルを見た時に、何のカラムか一目でわかるので便利です。
実践例: 商品テーブル
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('商品名');
$table->text('description')->nullable()->comment('商品説明');
$table->integer('price')->comment('価格');
$table->integer('stock')->default(0)->comment('在庫数');
$table->boolean('is_published')->default(false)->comment('公開状態');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('products');
}
✅ これで商品テーブルの構造が定義できました!
マイグレーションの実行
定義したマイグレーションを実行して、実際にテーブルを作成します。
基本的な実行コマンド
php artisan migrate
このコマンドで、まだ実行されていないマイグレーションが全て実行されます。
実行結果の例
$ php artisan migrate
INFO Running migrations.
2025_01_22_000001_create_products_table ............... 15ms DONE
マイグレーションの状態確認
php artisan migrate:status
どのマイグレーションが実行済みかを確認できます。
📊 実行結果の例:
Migration name .......................... Batch / Status
2014_10_12_000000_create_users_table ........ [1] Ran
2025_01_22_000001_create_products_table ..... [1] Ran
マイグレーションの仕組み
Laravelは、migrations というテーブルで実行履歴を管理しています。
🔍 実行の流れ
- 1. migrations テーブルを確認
- • どのマイグレーションが実行済みかチェック
- 2. 未実行のマイグレーションを実行
- • ファイル名のタイムスタンプ順に実行
- • up() メソッドを呼び出す
- 3. migrations テーブルに記録
- • 実行したマイグレーションを記録
- • 次回は実行されない
よく使うオプション
| コマンド | 説明 |
|---|---|
migrate |
未実行のマイグレーションを実行 |
migrate:status |
マイグレーションの状態を確認 |
migrate --force |
本番環境で強制実行(本番では慎重に!) |
migrate --pretend |
実行せずにSQLを表示(確認用) |
💡 本番環境での安全機構
Laravelは .env ファイルの APP_ENV=production で本番環境を判断します。
本番環境で migrate や migrate:fresh などを実行すると、以下のような確認メッセージが表示されます:
Do you really wish to run this command? (yes/no)
yes と入力すれば実行できますが、この確認は誤操作を防ぐための安全機構です。
--force オプションを付けると、この確認をスキップして直接実行できます(CI/CDでの自動デプロイ時に便利)。
✅ これでテーブルが作成されました!
ロールバックとリフレッシュ
マイグレーションは、実行した処理を元に戻すことができます。
ロールバック
最後に実行したマイグレーションを元に戻します。
php artisan migrate:rollback
これにより、down() メソッドが実行され、テーブルが削除されます。
特定のステップ数だけロールバック
# 最後の3つのバッチをロールバック
php artisan migrate:rollback --step=3
リフレッシュ(全削除して再実行)
php artisan migrate:refresh
全てのマイグレーションをロールバック(down()実行)してから、再度実行(up()実行)します。
開発中にテーブル構造を変更した時に使います。
フレッシュ(全削除して再作成)
php artisan migrate:fresh
全てのテーブルを強制的に削除(DROP)してから、マイグレーションを実行します。
down() メソッドを使わないので、refresh より高速で確実です。
💡 refresh と fresh の違い
| コマンド | 削除方法 | 速度 |
|---|---|---|
refresh |
down() メソッドでロールバック | 遅い |
fresh |
全テーブルをDROP(強制削除) | 高速 |
おすすめ: 開発中は migrate:fresh --seed を使うのが一般的です。
高速で確実にテーブルを再作成し、テストデータも投入できます。
⚠️ 警告
refresh と fresh は全データが削除されます!
本番環境では絶対に使わないでください。開発環境のみで使用してください。
コマンド比較
| コマンド | 動作 | 用途 |
|---|---|---|
migrate |
未実行のマイグレーションを実行 | 通常の実行 |
migrate:rollback |
最後のバッチをdown()で元に戻す | 直前の変更を取り消し |
migrate:refresh |
全てをdown()で削除 → 再実行 | 開発中の再構築(遅い) |
migrate:fresh |
全テーブルをDROP → 再実行 | 開発中の再構築(高速・推奨) |
実践例: 開発中の流れ
# 1. マイグレーション作成
php artisan make:migration create_products_table
# 2. ファイルを編集してテーブル構造を定義
# 3. マイグレーション実行
php artisan migrate
# 4. テーブル構造を変更したい!
# 5. 一旦削除して再実行
php artisan migrate:fresh
# 6. 再度実行
php artisan migrate
✅ ロールバックを使えば、安心してテーブル構造を変更できます!
カラムの追加・変更
既存のテーブルに対して、カラムを追加・変更する方法を学びます。
カラム追加のマイグレーション作成
既存の products テーブルに新しいカラムを追加する例です。
php artisan make:migration add_category_to_products_table
カラム追加の実装
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->string('category')->nullable()->after('name');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('category');
});
}
};
💡 重要なポイント
- •
Schema::create()ではなくSchema::table()を使う - •
after('name')で挿入位置を指定できる - •
down()ではdropColumn()でカラムを削除
カラム変更のマイグレーション
既存のカラムの型や属性を変更することができます。
💡 doctrine/dbal について(Laravel 10以前)
Laravel 10以前では、カラムを変更する際に doctrine/dbal パッケージのインストールが必要でした。
しかし、Laravel 11以降(現在はLaravel 12)では不要になりました。
Laravelがネイティブでカラム変更をサポートしています。
# Laravel 10以前では必要だった
composer require doctrine/dbal
# Laravel 11以降は不要!
カラム変更の実装
php artisan make:migration modify_description_in_products_table
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
// descriptionをnullableに変更
$table->text('description')->nullable()->change();
// nameの長さを100文字に変更
$table->string('name', 100)->change();
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->text('description')->change();
$table->string('name', 255)->change();
});
}
カラムのリネーム
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->renameColumn('old_name', 'new_name');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->renameColumn('new_name', 'old_name');
});
}
複数カラムの削除
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn(['category', 'old_price']);
});
}
外部キー制約
テーブル間のリレーション(関連)を定義するために、外部キー制約を設定します。
これは非常に重要な概念なので、しっかり理解しましょう。
外部キーとは
外部キーは、あるテーブルのカラムが、別のテーブルの主キーを参照する仕組みです。
データの整合性を保つために使われます。
💡 具体例で理解する
商品(products)とカテゴリー(categories)の関係を考えてみましょう。
| categories テーブル | ||
|---|---|---|
| id | name | |
| 1 | 家電 | |
| 2 | 食品 | |
| products テーブル | |||
|---|---|---|---|
| id | name | category_id | →参照先 |
| 1 | ノートPC | 1 | ✓ 家電 |
| 2 | コーヒー | 2 | ✓ 食品 |
| 3 | マウス | 999 | ✗ 存在しない |
外部キー制約がないと: category_id=999 のように、存在しないカテゴリーを指定できてしまう
外部キー制約があると: 存在しないカテゴリーIDは登録できない(エラーになる)
なぜ外部キー制約を使うべきなのか?
🚨 外部キーなしの問題点
- 1. データの不整合が起きる
存在しないカテゴリーIDを持つ商品が作れてしまう - 2. 孤立したデータが残る
カテゴリーを削除しても、そのカテゴリーIDを持つ商品が残る - 3. バグの原因になる
存在しないカテゴリーを参照してエラーが発生 - 4. アプリ側で整合性チェックが必要
データベースで保証されないので、PHP側で毎回チェックが必要
✅ 外部キーありのメリット
- 1. データの一元管理(正規化)
カテゴリー名を1箇所変更すれば、全商品に反映される。
categories テーブルで「家電」→「電化製品」に変更するだけでOK - 2. データベースレベルで整合性を保証
不正なデータは絶対に入らない - 3. 削除時の動作を制御できる
親削除時に子も削除、または削除を防ぐなど - 4. バグを未然に防ぐ
データの不整合が原因のバグがなくなる - 5. 開発が楽になる
整合性チェックをアプリ側で書かなくていい❌ 外部キーなしの場合 - PHP側で毎回チェックが必要
// 商品を作成する時 public function store(Request $request) { // PHP側で存在チェックが必要 $categoryExists = Category::where('id', $request->category_id)->exists(); if (!$categoryExists) { return back()->withErrors(['category_id' => '存在しないカテゴリー']); } // チェックが通ったら作成 Product::create([ 'name' => $request->name, 'category_id' => $request->category_id, ]); }✅ 外部キーありの場合 - データベースが自動チェック
// 商品を作成する時 public function store(Request $request) { // 存在チェック不要!データベースが自動的にチェック Product::create([ 'name' => $request->name, 'category_id' => $request->category_id, ]); // 存在しないcategory_idなら、データベースがエラーを返す }
⚠️ あえて外部キーにしない場合もある
実務では、意図的に外部キー制約を使わない場合もあります。
- 1. ログデータ・履歴データ
削除されたユーザーのログも残したい場合、user_id だけを保存して外部キーにしない。
ユーザーが削除されてもログは残る。 - 2. スナップショット(その時点のデータ)
注文時の商品価格や商品名を保存する場合、後で商品情報が変わっても注文データは変わらない。
外部キーではなく、カテゴリー名を直接 products テーブルに保存することもある。 - 3. パフォーマンス重視
大量のデータを扱う場合、外部キーチェックのオーバーヘッドを避けるため。
アプリ側で整合性を保証する。
判断基準: データの整合性 vs 柔軟性・パフォーマンスのトレードオフを考えて決める
💡 外部キーとリレーションの関係
マイグレーション(今ここで学習中)では、データベースに外部キー制約を設定します。
これはデータの整合性を保つためのデータベースレベルの設定です。
モデル(後で学習)では、リレーションを定義します。
これはLaravelで「カテゴリーに紐づく商品を取得」のような操作を簡単に書けるようにするアプリケーションレベルの設定です。
// モデルで定義するリレーション(後で学習)
class Category extends Model
{
public function products() {
return $this->hasMany(Product::class);
}
}
// こう書けるようになる
$category = Category::find(1);
$products = $category->products; // このカテゴリーの全商品を取得
まとめ:
• 外部キー(マイグレーション)= データベースでデータの整合性を守る
• リレーション(モデル)= Laravelで関連データを簡単に取得できるようにする
詳しくはモデルの章で学習します。
【実践】カテゴリーと商品のリレーションを作る
実際に外部キー制約を設定してみましょう。今回は、最初からcreateマイグレーションに含める方法で実装します。
💡 2つのアプローチ
外部キーを追加する方法は2つあります:
1. 最初からcreateに含める(推奨)
テーブル作成時に外部キーも一緒に定義。シンプルで分かりやすい
2. 後からaddマイグレーションで追加
既存テーブルに外部キーを追加する場合に使う
ステップ1: 既存のproductsテーブルを削除
# 既存のテーブルを削除
php artisan migrate:rollback
# または全削除
php artisan migrate:fresh
ステップ2: カテゴリーテーブル作成
php artisan make:migration create_categories_table
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('カテゴリー名');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('categories');
}
ステップ3: 商品テーブルを外部キー付きで作成
既存の create_products_table マイグレーションファイルを編集します。
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('商品名');
$table->text('description')->nullable()->comment('商品説明');
$table->integer('price')->comment('価格');
$table->integer('stock')->default(0)->comment('在庫数');
$table->boolean('is_published')->default(false)->comment('公開状態');
// 外部キー
$table->foreignId('category_id')
->constrained() // categories テーブルを参照
->onDelete('restrict'); // カテゴリーに商品がある場合は削除不可
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('products');
}
ステップ4: マイグレーション実行
# マイグレーション実行
php artisan migrate
✅ これで、categoriesテーブルが先に作成され、その後productsテーブルが外部キー付きで作成されます。
⚠️ 重要: マイグレーションの順序
外部キーを設定する際は、参照先のテーブルが先に存在している必要があります。
順序を間違えるとエラーになります。
正しい順序:
1. create_categories_table (2025_01_22_000001)
2. create_products_table (2025_01_22_000002)
❌ 間違った順序だと:
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
(table 'categories' doesn't exist)
💡 ポイント: マイグレーションファイル名のタイムスタンプで実行順序が決まります。
categories を先に作成したので、タイムスタンプが若い(古い)ファイル名になり、先に実行されます。
外部キーの書き方
シンプルな書き方(推奨)
$table->foreignId('category_id')
->constrained() // categories テーブルを自動推測
->onDelete('cascade');
• foreignId() は unsignedBigInteger() のショートカット
• constrained() は category_id から categories テーブルを推測
明示的な書き方
$table->foreignId('category_id')
->constrained('categories') // テーブル名を明示
->onDelete('cascade');
従来の書き方(Laravel 6以前)
$table->unsignedBigInteger('category_id');
$table->foreign('category_id')
->references('id')->on('categories')
->onDelete('cascade');
💡 書き方が変わった理由と歴史
Laravel 7(2020年3月)から、foreignId() と constrained() が導入されました。
変更の理由:
• 従来の書き方は冗長で書くのが大変
• テーブル名を手動で指定する必要があった
• Laravelの規約に従っていれば自動推測できるはず
→ より簡潔で書きやすい構文に改善されました
Laravelの命名規約:
constrained() は、カラム名からテーブル名を自動推測します。
• カラム名 category_id → テーブル名 categories を推測
• カラム名 user_id → テーブル名 users を推測
• パターン: {単数形}_id → {複数形} テーブル
※ この規約に従えば、テーブル名を明示しなくてもOK
onDelete() - 削除時の動作指定
親レコード(カテゴリー)を削除した時に、子レコード(商品)をどう扱うかを指定します。
これは非常に重要な設定で、ビジネスロジックによって使い分けます。
| メソッド | 動作 | 例 | 実務での用途 |
|---|---|---|---|
cascade |
親を削除すると子も削除 | カテゴリー削除→商品も削除 | 注文と注文明細など、親なしで意味がない子データ |
set null |
親を削除すると子はNULLに | カテゴリー削除→商品はcategory_id=NULL | ユーザーとコメントなど、親が消えても子を残したい場合 |
restrict |
子が存在すると親を削除できない | 商品があるカテゴリーは削除不可 | 本番で最も安全。誤削除を防ぐ(デフォルト) |
💡 実務での使い分け
1. cascade を使う場合
• 注文(orders) と 注文明細(order_items)
• ブログ投稿(posts) と コメント(comments)(投稿が消えたらコメントも不要な場合)
→ 親が消えたら子も意味がないデータ
2. set null を使う場合
• ユーザー(users) と コメント(comments)(ユーザーが退会してもコメントは残す)
• 投稿者(users) と ブログ記事(posts)(退会しても記事は残す)
→ 親が消えても子は残したいデータ
⚠️ nullable() を忘れずに!
3. restrict を使う場合(デフォルト)
• カテゴリー(categories) と 商品(products)
• 部署(departments) と 社員(employees)
→ 誤削除を防ぎたい場合。子レコードが存在する限り、親は削除できない。
→ アプリ側で「このカテゴリーには商品が登録されているため削除できません」と表示して、ユーザーに確認を促せる。
※ onDelete() を指定しない場合は自動的に restrict になります
シーダー(Seeder)
シーダーとは、データベースに初期データを投入する仕組みです。
💡 Seederの主な用途
1. マスターデータの投入(最重要)
システムが動作するために必ず必要なデータを投入します。
例: カテゴリー、都道府県、権限、ステータス、設定値など
→ これがないとシステムが動かない
2. 開発環境のテストデータ投入
開発中に動作確認用のサンプルデータを投入します。
例: サンプル商品、サンプルユーザーなど
→ チーム全員が同じデータで開発できる
3. 本番環境の初期データ投入
本番リリース時に必要なマスターデータを投入します。
→ php artisan db:seed で本番環境にも投入可能
シーダーのメリット
- ✅ マスターデータを確実に投入できる(本番環境でも使える)
- ✅ migrate:fresh しても一発で復元できる(開発効率UP)
- ✅ チーム全員が同じデータで開発できる(属人化防止)
- ✅ Git管理できる(バージョン管理可能)
【実践】シーダーを作成してマスターデータを投入
カテゴリーと商品のマスターデータを投入するシーダーを作成します。
ステップ1: シーダーを作成
# カテゴリーのシーダー
php artisan make:seeder CategorySeeder
# 商品のシーダー
php artisan make:seeder ProductSeeder
database/seeders/ ディレクトリに2つのファイルが作成されます。
ステップ2: CategorySeeder を実装
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class CategorySeeder extends Seeder
{
public function run(): void
{
DB::table('categories')->insert([
['name' => '家電', 'created_at' => now(), 'updated_at' => now()],
['name' => '食品', 'created_at' => now(), 'updated_at' => now()],
['name' => '衣類', 'created_at' => now(), 'updated_at' => now()],
['name' => '書籍', 'created_at' => now(), 'updated_at' => now()],
]);
}
}
ステップ3: ProductSeeder を実装
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class ProductSeeder extends Seeder
{
public function run(): void
{
DB::table('products')->insert([
[
'name' => 'ノートPC',
'description' => '高性能なノートパソコン',
'price' => 120000,
'stock' => 10,
'is_published' => true,
'category_id' => 1, // 家電
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'ワイヤレスマウス',
'description' => '快適な操作感',
'price' => 3000,
'stock' => 50,
'is_published' => true,
'category_id' => 1, // 家電
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'オーガニックコーヒー',
'description' => '香り高いコーヒー豆',
'price' => 1500,
'stock' => 30,
'is_published' => true,
'category_id' => 2, // 食品
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'Laravel入門書',
'description' => '初心者向けの解説書',
'price' => 2800,
'stock' => 20,
'is_published' => true,
'category_id' => 4, // 書籍
'created_at' => now(),
'updated_at' => now(),
],
]);
}
}
⚠️ 重要: シーダーの実行順序
ProductSeederは category_id で外部キーを参照しているため、
CategorySeederを先に実行する必要があります。
順序を間違えると、存在しない category_id を参照してエラーになります。
ステップ4: DatabaseSeeder で実行順序を管理
database/seeders/DatabaseSeeder.php で、実行するシーダーと順序を指定します。
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
CategorySeeder::class, // 先に実行
ProductSeeder::class, // 後に実行
]);
}
}
ステップ5: シーダーを実行
# 全てのシーダーを実行(DatabaseSeeder の call() に書いたものを順に実行)
php artisan db:seed
# 特定のシーダーのみ実行(DatabaseSeeder に書かなくても実行可能)
php artisan db:seed --class=CategorySeeder
# migrate:fresh と同時に実行(便利!)
php artisan migrate:fresh --seed
💡 シーダーの実行の仕組み
1. php artisan db:seed(オプションなし)
→ DatabaseSeeder の call() に書かれたシーダーを順番に実行します。
→ この例では CategorySeeder → ProductSeeder の順で実行される
2. php artisan db:seed --class=CategorySeeder
→ 指定したシーダーだけを実行します。
→ DatabaseSeeder の call() に書かなくても実行可能
→ 開発中に特定のマスターデータだけ投入し直したい時に便利
3. php artisan migrate:fresh --seed
→ 全テーブル削除 → マイグレーション実行 → db:seed を実行
→ つまり DatabaseSeeder の call() に書いたシーダーを順に実行
💡 開発の流れ
# テーブル構造を変更
# ↓
php artisan migrate:fresh --seed
# ↓
# テーブル再作成 + マスターデータ投入 完了!
このワンコマンドで、いつでもクリーンな状態に戻せます。
💡 補足: Factory(中級者向け)
Seederは決まったデータ(カテゴリー、都道府県など)を投入するのに適していますが、 1000件、10000件といった大量のランダムなテストデータが必要な場合は、 Factory という機能があります。
Factoryの用途:
• PHPUnitでの自動テスト用データ生成
• パフォーマンステスト用の大量データ生成
• ランダムな商品データを1000件生成、など
ただし、Factoryは主にPHPUnitでの自動テストで使う中級者向けの機能のため、
この入門講座では扱いません。
まずは Seeder を使ってマスターデータの投入ができるようになりましょう!
✅ シーダーを使えば、マスターデータの管理が楽になります!
まとめ
この講座で学んだマイグレーションの内容をまとめます。
マイグレーションの基本
| 操作 | コマンド |
|---|---|
| マイグレーション作成 | make:migration create_xxx_table |
| マイグレーション実行 | migrate |
| 状態確認 | migrate:status |
| ロールバック | migrate:rollback |
| 全削除→再実行 | migrate:fresh |
| シーダー作成 | make:seeder XxxSeeder |
| シーダー実行 | db:seed |
| 再構築+データ投入 | migrate:fresh --seed |
よく使うカラム型
| 用途 | メソッド |
|---|---|
| 主キー | id() |
| 短いテキスト | string('name') |
| 長いテキスト | text('description') |
| 整数 | integer('price') |
| 真偽値(0 or 1) | boolean('is_active') |
| 外部キー | foreignId('user_id')->constrained() |
| 作成日時・更新日時 | timestamps() |
よく使うカラム修飾子
| 修飾子 | 意味 |
|---|---|
nullable() |
NULL許可(空でもOK) |
default($value) |
デフォルト値を設定 |
unique() |
一意制約(重複不可) |
comment('説明') |
カラムの説明を追加 |
マイグレーションのベストプラクティス
- ✅ up() と down() は必ず対にする
ロールバックできるようにする - ✅ マイグレーションファイルは編集しない
一度実行したら、新しいマイグレーションで変更する - ✅ 外部キーの順序に注意
参照先テーブルを先に作成する - ✅ 開発中は migrate:fresh --seed を活用
いつでもクリーンな状態に戻せる - ⚠️ 本番環境では fresh/refresh は絶対に使わない
データが全て消えてしまう
次のステップ
マイグレーションでテーブル構造を定義できるようになりました。
次はモデル(Model)を学び、PHPからデータベースを操作する方法を学びます。
🎉 お疲れ様でした!
マイグレーションは、Laravelでアプリケーションを開発する上で最も重要な機能の1つです。
何度も練習して、しっかりマスターしましょう!