> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 資料庫遷移（Migrations）

> 說明如何運用 Laravel 的 migration 功能為資料庫綱要進行版本控管。

## 什麼是 Migration

Migration 就像資料庫的版本控管。
它讓團隊能夠共享、管理應用程式的資料庫綱要定義。

你或許曾遇過拉取原始碼後，還得請團隊成員手動在本機資料庫加欄位的情境。
Migration 就是解決這問題的辦法。

Migration 檔案存放在 `database/migrations` 目錄。
每個檔名都包含時間戳，Laravel 會依此決定執行順序。

## 建立 Migration 檔

以 `make:migration` Artisan 指令建立新的 migration 檔。

```shell theme={null}
php artisan make:migration create_posts_table
```

Laravel 會根據 migration 名稱推測資料表名稱並產生對應範本。
若名稱為 `create_posts_table`，範本會事先產生用於建立 `posts` 資料表的程式碼。

## Migration 結構

Migration 類別具有 `up` 與 `down` 兩個方法。

* `up`：對資料庫新增資料表、欄位、索引。
* `down`：將 `up` 的操作反轉，回滾時執行。

```php theme={null}
<?php

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

return new class extends Migration
{
    /**
     * 執行 migration
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->boolean('published')->default(false);
            $table->timestamps();
        });
    }

    /**
     * 回滾 migration
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
```

## 主要欄位定義方法

`Blueprint` 類別提供大量欄位類型。

| 方法                                  | 說明                                |
| ----------------------------------- | --------------------------------- |
| `$table->id()`                      | 自動遞增主鍵（`bigIncrements('id')` 的別名） |
| `$table->string('name')`            | 相當於 VARCHAR（預設 255 字元）            |
| `$table->text('body')`              | TEXT 欄位                           |
| `$table->integer('count')`          | INTEGER 欄位                        |
| `$table->boolean('active')`         | 以 TINYINT 儲存布林                    |
| `$table->timestamp('published_at')` | TIMESTAMP 欄位                      |
| `$table->timestamps()`              | 一次加入 `created_at` 與 `updated_at`  |
| `$table->softDeletes()`             | 加入用於軟刪除的 `deleted_at` 欄位          |
| `$table->foreignId('user_id')`      | 外鍵用的 `BIGINT UNSIGNED` 欄位         |

### 欄位修飾子

可用方法鏈附加欄位修飾子。

```php theme={null}
$table->string('email')->unique();
$table->string('name')->nullable();
$table->integer('votes')->default(0);
$table->string('title')->after('id'); // 放在指定欄位之後
```

## 執行 Migration

用 `migrate` 執行所有未執行的 migration。

```shell theme={null}
php artisan migrate
```

要查看已 / 未執行的 migration，可用 `migrate:status`。

```shell theme={null}
php artisan migrate:status
```

<Warning>
  正式環境執行 migration 會出現確認提示。
  想跳過確認可用 `--force`，但因可能影響資料，請務必謹慎。
</Warning>

## 回滾

用 `migrate:rollback` 可回滾最近一批 migration。

```shell theme={null}
php artisan migrate:rollback
```

要回滾指定步數，可用 `--step`。

```shell theme={null}
# 回滾最近 5 個 migration
php artisan migrate:rollback --step=5
```

若要先回滾全部再重新執行，可用 `migrate:refresh`。

```shell theme={null}
php artisan migrate:refresh
```

<Info>
  `migrate:refresh` 會重建所有資料表，既有資料會遺失。
  適合開發期重置資料庫。
</Info>

## 實戰範例：建立 posts 資料表

以管理部落格文章的 `posts` 資料表為例，走過一次完整流程。

### 1. 產生 migration 檔

```shell theme={null}
php artisan make:migration create_posts_table
```

### 2. 編輯 migration

打開 `database/migrations/xxxx_xx_xx_xxxxxx_create_posts_table.php` 編輯。

```php theme={null}
<?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::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->text('body');
            $table->boolean('published')->default(false);
            $table->timestamp('published_at')->nullable();
            $table->timestamps();
        });
    }

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

### 3. 執行 migration

```shell theme={null}
php artisan migrate
```

執行後資料庫中會建立 `posts` 資料表。

### 4. 之後新增欄位

若在資料表建立後要新增欄位，別直接修改既有 migration，改為建立新的 migration。

```shell theme={null}
php artisan make:migration add_excerpt_to_posts_table
```

```php theme={null}
public function up(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->string('excerpt')->nullable()->after('title');
    });
}

public function down(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->dropColumn('excerpt');
    });
}
```

<Tip>
  請避免直接修改既有的 migration 檔。
  這會破壞與其他成員或正式環境的一致性。
  變更請一律以新的 migration 加入。
</Tip>

## Migration 事件

每一次 migration 操作都會發送[事件](/zh-TW/events)。所有事件皆繼承 `Illuminate\Database\Events\MigrationEvent`。

| 類別                                               | 說明                      |
| ------------------------------------------------ | ----------------------- |
| `Illuminate\Database\Events\DatabaseRefreshed`   | `migrate:refresh` 指令完成後 |
| `Illuminate\Database\Events\MigrationsStarted`   | 一批 migration 執行前        |
| `Illuminate\Database\Events\MigrationsEnded`     | 一批 migration 完成後        |
| `Illuminate\Database\Events\MigrationStarted`    | 單一 migration 執行前        |
| `Illuminate\Database\Events\MigrationEnded`      | 單一 migration 完成後        |
| `Illuminate\Database\Events\NoPendingMigrations` | 判斷已無未執行 migration 時     |
| `Illuminate\Database\Events\SchemaDumped`        | 資料庫 schema dump 完成後     |
| `Illuminate\Database\Events\SchemaLoaded`        | 現有 schema dump 載入後      |

例如可監聽 `MigrationsEnded`，在 migration 結束後清除快取。

```php theme={null}
use Illuminate\Database\Events\MigrationsEnded;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;

Event::listen(MigrationsEnded::class, function () {
    Cache::flush();
});
```

## 下一步

<Card title="資料庫 Seeding" icon="seedling" href="/zh-TW/seeding">
  學習如何為 migration 建好的資料表匯入範例資料。
</Card>

<Card title="Eloquent 入門" icon="database" href="/zh-TW/eloquent">
  學習如何以 Eloquent ORM 操作 migration 建好的資料表。
</Card>


## Related topics

- [從 laravel/ui 遷移到 Fortify 的指南](/zh-TW/blog/ui-to-fortify.md)
- [資料庫 Seeding](/zh-TW/seeding.md)
- [資料庫測試](/zh-TW/database-testing.md)
- [資料庫設定](/zh-TW/database.md)
- [安裝](/zh-TW/installation.md)
