LaravelDocs(中文)

遷移 (Migrations)

Migrations 就像是資料庫的版本控制系統

簡介 (Introduction)

Migration 就像是資料庫的版本控制系統,讓您的團隊可以定義和共享應用程式的資料庫結構定義。如果您曾經需要告訴隊友在從版本控制拉取您的變更後手動在本機資料庫結構中新增欄位,您就遇到了資料庫 migration 所解決的問題。

Laravel Schema Facade 提供了與資料庫無關的支援,可在 Laravel 支援的所有資料庫系統中建立和操作資料表。通常,migration 會使用此 Facade 來建立和修改資料庫資料表和欄位。

產生 Migration (Generating Migrations)

您可以使用 make:migration Artisan 命令來產生資料庫 migration。新的 migration 會放置在您的 database/migrations 目錄中。每個 migration 檔案名稱都包含一個時間戳記,讓 Laravel 可以決定 migration 的順序:

php artisan make:migration create_flights_table

Laravel 會使用 migration 的名稱來嘗試猜測資料表的名稱,以及 migration 是否會建立新的資料表。如果 Laravel 能夠從 migration 名稱判斷資料表名稱,Laravel 會在產生的 migration 檔案中預先填入指定的資料表。否則,您可以在 migration 檔案中手動指定資料表。

如果您想為產生的 migration 指定自訂路徑,您可以在執行 make:migration 命令時使用 --path 選項。給定的路徑應該相對於您應用程式的基礎路徑。

[!NOTE] Migration 樣板可以使用 樣板發佈 來自訂。

壓縮 Migration (Squashing Migrations)

隨著您建構應用程式,您可能會隨著時間累積越來越多的 migration。這可能會導致您的 database/migrations 目錄膨脹到可能有數百個 migration。如果您願意,您可以將 migration「壓縮」成單一 SQL 檔案。若要開始,請執行 schema:dump 命令:

php artisan schema:dump

# 傾印目前的資料庫結構並清除所有現有的 migration...
php artisan schema:dump --prune

當您執行此命令時,Laravel 會將一個「結構」檔案寫入您應用程式的 database/schema 目錄。結構檔案的名稱會對應於資料庫連線。現在,當您嘗試遷移資料庫且沒有其他 migration 已執行時,Laravel 會先執行您正在使用的資料庫連線的結構檔案中的 SQL 陳述式。執行結構檔案的 SQL 陳述式後,Laravel 會執行不屬於結構傾印的任何剩餘 migration。

如果您的應用程式的測試使用與您在本機開發期間通常使用的不同資料庫連線,您應該確保已使用該資料庫連線傾印了結構檔案,以便您的測試能夠建構您的資料庫。您可能希望在傾印您在本機開發期間通常使用的資料庫連線後執行此操作:

php artisan schema:dump
php artisan schema:dump --database=testing --prune

您應該將資料庫結構檔案提交到版本控制,以便團隊中的其他新開發人員可以快速建立應用程式的初始資料庫結構。

[!WARNING] Migration 壓縮僅適用於 MariaDB、MySQL、PostgreSQL 和 SQLite 資料庫,並使用資料庫的命令列客戶端。

Migration 結構 (Migration Structure)

一個 migration 類別包含兩個方法:updownup 方法用於向資料庫新增新的資料表、欄位或索引,而 down 方法應該反轉 up 方法執行的操作。

在這兩個方法中,您可以使用 Laravel 結構建構器來表達式地建立和修改資料表。若要了解 Schema 建構器上可用的所有方法,請查看其文件。例如,以下 migration 會建立一個 flights 資料表:

<?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('flights', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('airline');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::drop('flights');
    }
};

設定 Migration 連線 (Setting the Migration Connection)

如果您的 migration 將與應用程式預設資料庫連線以外的資料庫連線互動,您應該設定 migration 的 $connection 屬性:

/**
 * The database connection that should be used by the migration.
 *
 * @var string
 */
protected $connection = 'pgsql';

/**
 * Run the migrations.
 */
public function up(): void
{
    // ...
}

跳過 Migration (Skipping Migrations)

有時候 migration 可能是為了支援尚未啟用的功能而設計的,您不希望它現在執行。在這種情況下,您可以在 migration 上定義 shouldRun 方法。如果 shouldRun 方法回傳 false,則會跳過該 migration:

use App\Models\Flights;
use Laravel\Pennant\Feature;

/**
 * Determine if this migration should run.
 */
public function shouldRun(): bool
{
    return Feature::active(Flights::class);
}

執行 Migration (Running Migrations)

若要執行所有尚未執行的 migration,請執行 migrate Artisan 命令:

php artisan migrate

如果您想查看哪些 migration 已經執行以及哪些仍待處理,您可以使用 migrate:status Artisan 命令:

php artisan migrate:status

如果您想查看 migration 將執行的 SQL 陳述式而不實際執行它們,您可以向 migrate 命令提供 --pretend 標誌:

php artisan migrate --pretend

隔離 Migration 執行 (Isolating Migration Execution)

如果您要在多個伺服器上部署應用程式並作為部署過程的一部分執行 migration,您可能不希望兩個伺服器同時嘗試遷移資料庫。若要避免這種情況,您可以在呼叫 migrate 命令時使用 isolated 選項。

當提供 isolated 選項時,Laravel 會在嘗試執行 migration 之前使用應用程式的快取驅動程式取得原子鎖。當該鎖被持有時,所有其他嘗試執行 migrate 命令的操作都不會執行;但是,命令仍會以成功的結束狀態碼結束:

php artisan migrate --isolated

[!WARNING] 若要使用此功能,您的應用程式必須使用 memcachedredisdynamodbdatabasefilearray 快取驅動程式作為應用程式的預設快取驅動程式。此外,所有伺服器必須與同一個中央快取伺服器通訊。

在正式環境中強制執行 Migration (Forcing Migrations to Run in Production)

某些 migration 操作是具破壞性的,這表示它們可能會導致您遺失資料。為了保護您不在正式環境資料庫上執行這些命令,您將在命令執行前被提示確認。若要強制命令在沒有提示的情況下執行,請使用 --force 標誌:

php artisan migrate --force

回滾 Migration (Rolling Back Migrations)

若要回滾最新的 migration 操作,您可以使用 rollback Artisan 命令。此命令會回滾最後一「批」migration,其中可能包含多個 migration 檔案:

php artisan migrate:rollback

您可以透過向 rollback 命令提供 step 選項來回滾有限數量的 migration。例如,以下命令將回滾最後五個 migration:

php artisan migrate:rollback --step=5

您可以透過向 rollback 命令提供 batch 選項來回滾特定「批」的 migration,其中 batch 選項對應於應用程式 migrations 資料庫表中的批次值。例如,以下命令將回滾第三批的所有 migration:

php artisan migrate:rollback --batch=3

如果您想查看 migration 將執行的 SQL 陳述式而不實際執行它們,您可以向 migrate:rollback 命令提供 --pretend 標誌:

php artisan migrate:rollback --pretend

migrate:reset 命令將回滾應用程式的所有 migration:

php artisan migrate:reset

使用單一命令回滾和遷移 (Roll Back and Migrate Using a Single Command)

migrate:refresh 命令會回滾所有 migration,然後執行 migrate 命令。此命令有效地重新建立您的整個資料庫:

php artisan migrate:refresh

# 重新整理資料庫並執行所有資料庫填充...
php artisan migrate:refresh --seed

您可以透過向 refresh 命令提供 step 選項來回滾並重新遷移有限數量的 migration。例如,以下命令將回滾並重新遷移最後五個 migration:

php artisan migrate:refresh --step=5

刪除所有資料表並遷移 (Drop All Tables and Migrate)

migrate:fresh 命令會從資料庫刪除所有資料表,然後執行 migrate 命令:

php artisan migrate:fresh

php artisan migrate:fresh --seed

預設情況下,migrate:fresh 命令只會從預設資料庫連線刪除資料表。但是,您可以使用 --database 選項來指定應該遷移的資料庫連線。資料庫連線名稱應該對應於您應用程式的 database 設定檔中定義的連線:

php artisan migrate:fresh --database=admin

[!WARNING] > migrate:fresh 命令會刪除所有資料庫資料表,無論其前綴為何。在與其他應用程式共用的資料庫上開發時應謹慎使用此命令。

資料表 (Tables)

建立資料表 (Creating Tables)

若要建立新的資料庫資料表,請在 Schema Facade 上使用 create 方法。create 方法接受兩個參數:第一個是資料表的名稱,第二個是接收 Blueprint 物件的閉包,可用於定義新資料表:

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

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email');
    $table->timestamps();
});

建立資料表時,您可以使用結構建構器的任何欄位方法來定義資料表的欄位。

判斷資料表 / 欄位是否存在 (Determining Table / Column Existence)

您可以使用 hasTablehasColumnhasIndex 方法來判斷資料表、欄位或索引是否存在:

if (Schema::hasTable('users')) {
    // "users" 資料表存在...
}

if (Schema::hasColumn('users', 'email')) {
    // "users" 資料表存在且有 "email" 欄位...
}

if (Schema::hasIndex('users', ['email'], 'unique')) {
    // "users" 資料表存在且 "email" 欄位有唯一索引...
}

資料庫連線和資料表選項 (Database Connection and Table Options)

如果您想在非應用程式預設連線的資料庫連線上執行結構操作,請使用 connection 方法:

Schema::connection('sqlite')->create('users', function (Blueprint $table) {
    $table->id();
});

此外,還有一些其他屬性和方法可用於定義資料表建立的其他方面。使用 MariaDB 或 MySQL 時,engine 屬性可用於指定資料表的儲存引擎:

Schema::create('users', function (Blueprint $table) {
    $table->engine('InnoDB');

    // ...
});

使用 MariaDB 或 MySQL 時,charsetcollation 屬性可用於指定所建立資料表的字元集和排序規則:

Schema::create('users', function (Blueprint $table) {
    $table->charset('utf8mb4');
    $table->collation('utf8mb4_unicode_ci');

    // ...
});

temporary 方法可用於指示資料表應該是「暫時性」的。暫時性資料表僅對目前連線的資料庫 Session 可見,並在連線關閉時自動刪除:

Schema::create('calculations', function (Blueprint $table) {
    $table->temporary();

    // ...
});

如果您想為資料庫資料表新增「註解」,您可以在資料表實例上呼叫 comment 方法。資料表註解目前僅由 MariaDB、MySQL 和 PostgreSQL 支援:

Schema::create('calculations', function (Blueprint $table) {
    $table->comment('Business calculations');

    // ...
});

更新資料表 (Updating Tables)

Schema Facade 上的 table 方法可用於更新現有資料表。與 create 方法一樣,table 方法接受兩個參數:資料表的名稱和一個接收 Blueprint 實例的閉包,您可以使用它來為資料表新增欄位或索引:

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

Schema::table('users', function (Blueprint $table) {
    $table->integer('votes');
});

重新命名 / 刪除資料表 (Renaming / Dropping Tables)

若要重新命名現有的資料庫資料表,請使用 rename 方法:

use Illuminate\Support\Facades\Schema;

Schema::rename($from, $to);

若要刪除現有的資料表,您可以使用 dropdropIfExists 方法:

Schema::drop('users');

Schema::dropIfExists('users');

重新命名有外鍵的資料表 (Renaming Tables With Foreign Keys)

在重新命名資料表之前,您應該驗證資料表上的任何外鍵約束在 migration 檔案中都有明確的名稱,而不是讓 Laravel 指派基於慣例的名稱。否則,外鍵約束名稱將參照舊的資料表名稱。

欄位 (Columns)

建立欄位 (Creating Columns)

Schema Facade 上的 table 方法可用於更新現有資料表。與 create 方法一樣,table 方法接受兩個參數:資料表的名稱和一個接收 Illuminate\Database\Schema\Blueprint 實例的閉包,您可以使用它來為資料表新增欄位:

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

Schema::table('users', function (Blueprint $table) {
    $table->integer('votes');
});

可用的欄位類型 (Available Column Types)

結構建構器藍圖提供了多種方法,對應於您可以新增到資料庫資料表的不同欄位類型。每個可用的方法都列在下表中:

布林類型 (Boolean Types)

字串和文字類型 (String & Text Types)

數值類型 (Numeric Types)

日期和時間類型 (Date & Time Types)

二進位類型 (Binary Types)

物件與 JSON 類型 (Object & Json Types)

UUID 與 ULID 類型 (UUID & ULID Types)

空間類型 (Spatial Types)

關聯類型 (Relationship Types)

特殊類型 (Specialty Types)

bigIncrements()

bigIncrements 方法建立一個自動遞增的 UNSIGNED BIGINT(主鍵)等效欄位:

$table->bigIncrements('id');

bigInteger()

bigInteger 方法建立一個 BIGINT 等效欄位:

$table->bigInteger('votes');

binary()

binary 方法建立一個 BLOB 等效欄位:

$table->binary('photo');

使用 MySQL、MariaDB 或 SQL Server 時,你可以傳遞 lengthfixed 引數來建立 VARBINARYBINARY 等效欄位:

$table->binary('data', length: 16); // VARBINARY(16)

$table->binary('data', length: 16, fixed: true); // BINARY(16)

boolean()

boolean 方法建立一個 BOOLEAN 等效欄位:

$table->boolean('confirmed');

char()

char 方法建立一個給定長度的 CHAR 等效欄位:

$table->char('name', length: 100);

dateTimeTz()

dateTimeTz 方法建立一個帶有可選小數秒精度的 DATETIME(帶時區)等效欄位:

$table->dateTimeTz('created_at', precision: 0);

dateTime()

dateTime 方法建立一個帶有可選小數秒精度的 DATETIME 等效欄位:

$table->dateTime('created_at', precision: 0);

date()

date 方法建立一個 DATE 等效欄位:

$table->date('created_at');

decimal()

decimal 方法建立一個具有給定精度(總位數)和小數位數的 DECIMAL 等效欄位:

$table->decimal('amount', total: 8, places: 2);

double()

double 方法建立一個 DOUBLE 等效欄位:

$table->double('amount');

enum()

enum 方法建立一個具有給定有效值的 ENUM 等效欄位:

$table->enum('difficulty', ['easy', 'hard']);

當然,你也可以使用 Enum::cases() 方法來代替手動定義允許值的陣列:

use App\Enums\Difficulty;

$table->enum('difficulty', Difficulty::cases());

float()

float 方法建立一個具有給定精度的 FLOAT 等效欄位:

$table->float('amount', precision: 53);

foreignId()

foreignId 方法建立一個 UNSIGNED BIGINT 等效欄位:

$table->foreignId('user_id');

foreignIdFor()

foreignIdFor 方法為給定的模型類別新增一個 {column}_id 等效欄位。欄位類型將根據模型鍵類型為 UNSIGNED BIGINTCHAR(36)CHAR(26)

$table->foreignIdFor(User::class);

foreignUlid()

foreignUlid 方法建立一個 ULID 等效欄位:

$table->foreignUlid('user_id');

foreignUuid()

foreignUuid 方法建立一個 UUID 等效欄位:

$table->foreignUuid('user_id');

geography()

geography 方法建立一個具有給定空間類型和 SRID(空間參考系統識別碼)的 GEOGRAPHY 等效欄位:

$table->geography('coordinates', subtype: 'point', srid: 4326);

[!NOTE] 空間類型的支援取決於你的資料庫驅動程式。請參閱你的資料庫文件。如果你的應用程式使用 PostgreSQL 資料庫,必須先安裝 PostGIS 擴充套件才能使用 geography 方法。

geometry()

geometry 方法建立一個具有給定空間類型和 SRID(空間參考系統識別碼)的 GEOMETRY 等效欄位:

$table->geometry('positions', subtype: 'point', srid: 0);

[!NOTE] 空間類型的支援取決於你的資料庫驅動程式。請參閱你的資料庫文件。如果你的應用程式使用 PostgreSQL 資料庫,必須先安裝 PostGIS 擴充套件才能使用 geometry 方法。

id()

id 方法是 bigIncrements 方法的別名。預設情況下,該方法將建立一個 id 欄位;但是,如果你想為欄位指定不同的名稱,可以傳遞欄位名稱:

$table->id();

increments()

increments 方法建立一個自動遞增的 UNSIGNED INTEGER 等效欄位作為主鍵:

$table->increments('id');

integer()

integer 方法建立一個 INTEGER 等效欄位:

$table->integer('votes');

ipAddress()

ipAddress 方法建立一個 VARCHAR 等效欄位:

$table->ipAddress('visitor');

使用 PostgreSQL 時,將建立一個 INET 欄位。

json()

json 方法建立一個 JSON 等效欄位:

$table->json('options');

使用 SQLite 時,將建立一個 TEXT 欄位。

jsonb()

jsonb 方法建立一個 JSONB 等效欄位:

$table->jsonb('options');

使用 SQLite 時,將建立一個 TEXT 欄位。

longText()

longText 方法建立一個 LONGTEXT 等效欄位:

$table->longText('description');

使用 MySQL 或 MariaDB 時,你可以對欄位套用 binary 字元集來建立 LONGBLOB 等效欄位:

$table->longText('data')->charset('binary'); // LONGBLOB

macAddress()

macAddress 方法建立一個用於存放 MAC 位址的欄位。某些資料庫系統(如 PostgreSQL)有專門的欄位類型來存放此類資料。其他資料庫系統將使用字串等效欄位:

$table->macAddress('device');

mediumIncrements()

mediumIncrements 方法建立一個自動遞增的 UNSIGNED MEDIUMINT 等效欄位作為主鍵:

$table->mediumIncrements('id');

mediumInteger()

mediumInteger 方法建立一個 MEDIUMINT 等效欄位:

$table->mediumInteger('votes');

mediumText()

mediumText 方法建立一個 MEDIUMTEXT 等效欄位:

$table->mediumText('description');

使用 MySQL 或 MariaDB 時,你可以對欄位套用 binary 字元集來建立 MEDIUMBLOB 等效欄位:

$table->mediumText('data')->charset('binary'); // MEDIUMBLOB

morphs()

morphs 方法是一個便利方法,可新增一個 {column}_id 等效欄位和一個 {column}_type VARCHAR 等效欄位。{column}_id 的欄位類型將根據模型鍵類型為 UNSIGNED BIGINTCHAR(36)CHAR(26)

此方法用於定義多型 Eloquent 關聯所需的欄位。在以下範例中,將建立 taggable_idtaggable_type 欄位:

$table->morphs('taggable');

nullableMorphs()

此方法與 morphs 方法類似;但是,所建立的欄位將是「可為空」的:

$table->nullableMorphs('taggable');

nullableUlidMorphs()

此方法與 ulidMorphs 方法類似;但是,所建立的欄位將是「可為空」的:

$table->nullableUlidMorphs('taggable');

nullableUuidMorphs()

此方法與 uuidMorphs 方法類似;但是,所建立的欄位將是「可為空」的:

$table->nullableUuidMorphs('taggable');

rememberToken()

rememberToken 方法建立一個可為空的 VARCHAR(100) 等效欄位,用於存放當前的「記住我」認證權杖

$table->rememberToken();

set()

set 方法建立一個具有給定有效值列表的 SET 等效欄位:

$table->set('flavors', ['strawberry', 'vanilla']);

smallIncrements()

smallIncrements 方法建立一個自動遞增的 UNSIGNED SMALLINT 等效欄位作為主鍵:

$table->smallIncrements('id');

smallInteger()

smallInteger 方法建立一個 SMALLINT 等效欄位:

$table->smallInteger('votes');

softDeletesTz()

softDeletesTz 方法新增一個可為空的 deleted_at TIMESTAMP(帶時區)等效欄位,具有可選的小數秒精度。此欄位用於存放 Eloquent「軟刪除」功能所需的 deleted_at 時間戳記:

$table->softDeletesTz('deleted_at', precision: 0);

softDeletes()

softDeletes 方法新增一個可為空的 deleted_at TIMESTAMP 等效欄位,具有可選的小數秒精度。此欄位用於存放 Eloquent「軟刪除」功能所需的 deleted_at 時間戳記:

$table->softDeletes('deleted_at', precision: 0);

string()

string 方法建立一個給定長度的 VARCHAR 等效欄位:

$table->string('name', length: 100);

text()

text 方法建立一個 TEXT 等效欄位:

$table->text('description');

使用 MySQL 或 MariaDB 時,你可以對欄位套用 binary 字元集來建立 BLOB 等效欄位:

$table->text('data')->charset('binary'); // BLOB

timeTz()

timeTz 方法建立一個帶有可選小數秒精度的 TIME(帶時區)等效欄位:

$table->timeTz('sunrise', precision: 0);

time()

time 方法建立一個帶有可選小數秒精度的 TIME 等效欄位:

$table->time('sunrise', precision: 0);

timestampTz()

timestampTz 方法建立一個帶有可選小數秒精度的 TIMESTAMP(帶時區)等效欄位:

$table->timestampTz('added_at', precision: 0);

timestamp()

timestamp 方法建立一個帶有可選小數秒精度的 TIMESTAMP 等效欄位:

$table->timestamp('added_at', precision: 0);

timestampsTz()

timestampsTz 方法建立帶有可選小數秒精度的 created_atupdated_at TIMESTAMP(帶時區)等效欄位:

$table->timestampsTz(precision: 0);

timestamps()

timestamps 方法建立帶有可選小數秒精度的 created_atupdated_at TIMESTAMP 等效欄位:

$table->timestamps(precision: 0);

tinyIncrements()

tinyIncrements 方法建立一個自動遞增的 UNSIGNED TINYINT 等效欄位作為主鍵:

$table->tinyIncrements('id');

tinyInteger()

tinyInteger 方法建立一個 TINYINT 等效欄位:

$table->tinyInteger('votes');

tinyText()

tinyText 方法建立一個 TINYTEXT 等效欄位:

$table->tinyText('notes');

使用 MySQL 或 MariaDB 時,你可以對欄位套用 binary 字元集來建立 TINYBLOB 等效欄位:

$table->tinyText('data')->charset('binary'); // TINYBLOB

unsignedBigInteger()

unsignedBigInteger 方法建立一個 UNSIGNED BIGINT 等效欄位:

$table->unsignedBigInteger('votes');

unsignedInteger()

unsignedInteger 方法建立一個 UNSIGNED INTEGER 等效欄位:

$table->unsignedInteger('votes');

unsignedMediumInteger()

unsignedMediumInteger 方法建立一個 UNSIGNED MEDIUMINT 等效欄位:

$table->unsignedMediumInteger('votes');

unsignedSmallInteger()

unsignedSmallInteger 方法建立一個 UNSIGNED SMALLINT 等效欄位:

$table->unsignedSmallInteger('votes');

unsignedTinyInteger()

unsignedTinyInteger 方法建立一個 UNSIGNED TINYINT 等效欄位:

$table->unsignedTinyInteger('votes');

ulidMorphs()

ulidMorphs 方法是一個便利方法,可新增一個 {column}_id CHAR(26) 等效欄位和一個 {column}_type VARCHAR 等效欄位。

此方法用於定義使用 ULID 識別碼的多型 Eloquent 關聯所需的欄位。在以下範例中,將建立 taggable_idtaggable_type 欄位:

$table->ulidMorphs('taggable');

uuidMorphs()

uuidMorphs 方法是一個便利方法,可新增一個 {column}_id CHAR(36) 等效欄位和一個 {column}_type VARCHAR 等效欄位。

此方法用於定義使用 UUID 識別碼的多型 Eloquent 關聯所需的欄位。在以下範例中,將建立 taggable_idtaggable_type 欄位:

$table->uuidMorphs('taggable');

ulid()

ulid 方法建立一個 ULID 等效欄位:

$table->ulid('id');

uuid()

uuid 方法建立一個 UUID 等效欄位:

$table->uuid('id');

vector()

vector 方法建立一個 vector 等效欄位:

$table->vector('embedding', dimensions: 100);

year()

year 方法建立一個 YEAR 等效欄位:

$table->year('birth_year');

欄位修飾詞 (Column Modifiers)

除了上面列出的欄位類型外,在向資料庫資料表新增欄位時,還有幾個欄位「修飾詞」可以使用。例如,若要使欄位「可為空」,你可以使用 nullable 方法:

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

Schema::table('users', function (Blueprint $table) {
    $table->string('email')->nullable();
});

下表包含所有可用的欄位修飾詞。此列表不包括索引修飾詞

修飾詞說明
->after('column')將欄位放在另一個欄位「之後」(MariaDB / MySQL)。
->autoIncrement()INTEGER 欄位設為自動遞增(主鍵)。
->charset('utf8mb4')為欄位指定字元集 (MariaDB / MySQL)。
->collation('utf8mb4_unicode_ci')為欄位指定排序規則。
->comment('my comment')為欄位新增註解 (MariaDB / MySQL / PostgreSQL)。
->default($value)為欄位指定「預設」值。
->first()將欄位放在資料表的「第一個」位置 (MariaDB / MySQL)。
->from($integer)設定自動遞增欄位的起始值 (MariaDB / MySQL / PostgreSQL)。
->invisible()使欄位對 SELECT * 查詢「不可見」(MariaDB / MySQL)。
->nullable($value = true)允許將 NULL 值插入欄位。
->storedAs($expression)建立一個儲存的產生欄位 (MariaDB / MySQL / PostgreSQL / SQLite)。
->unsigned()INTEGER 欄位設為 UNSIGNED (MariaDB / MySQL)。
->useCurrent()TIMESTAMP 欄位設為使用 CURRENT_TIMESTAMP 作為預設值。
->useCurrentOnUpdate()在記錄更新時將 TIMESTAMP 欄位設為使用 CURRENT_TIMESTAMP (MariaDB / MySQL)。
->virtualAs($expression)建立一個虛擬產生欄位 (MariaDB / MySQL / SQLite)。
->generatedAs($expression)使用指定的序列選項建立識別欄位 (PostgreSQL)。
->always()定義序列值優先於識別欄位的輸入 (PostgreSQL)。

預設運算式 (Default Expressions)

default 修飾詞接受一個值或 Illuminate\Database\Query\Expression 實例。使用 Expression 實例將防止 Laravel 用引號包裝值,並允許你使用資料庫特定的函式。一種特別有用的情況是當你需要為 JSON 欄位指定預設值時:

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->id();
            $table->json('movies')->default(new Expression('(JSON_ARRAY())'));
            $table->timestamps();
        });
    }
};

[!WARNING] 預設運算式的支援取決於你的資料庫驅動程式、資料庫版本和欄位類型。請參閱你的資料庫文件。

欄位順序 (Column Order)

使用 MariaDB 或 MySQL 資料庫時,可以使用 after 方法在 Schema 中的現有欄位之後新增欄位:

$table->after('password', function (Blueprint $table) {
    $table->string('address_line1');
    $table->string('address_line2');
    $table->string('city');
});

修改欄位 (Modifying Columns)

change 方法允許你修改現有欄位的類型和屬性。例如,你可能希望增加 string 欄位的大小。若要查看 change 方法的實際運作,讓我們將 name 欄位的大小從 25 增加到 50。為此,我們只需定義欄位的新狀態,然後呼叫 change 方法:

Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change();
});

修改欄位時,你必須明確包含所有你想保留在欄位定義上的修飾詞——任何缺少的屬性都將被刪除。例如,若要保留 unsigneddefaultcomment 屬性,你必須在更改欄位時明確呼叫每個修飾詞:

Schema::table('users', function (Blueprint $table) {
    $table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});

change 方法不會更改欄位的索引。因此,你可以使用索引修飾詞在修改欄位時明確新增或刪除索引:

// 新增索引...
$table->bigIncrements('id')->primary()->change();

// 刪除索引...
$table->char('postal_code', 10)->unique(false)->change();

重新命名欄位 (Renaming Columns)

若要重新命名欄位,你可以使用 Schema Builder 提供的 renameColumn 方法:

Schema::table('users', function (Blueprint $table) {
    $table->renameColumn('from', 'to');
});

刪除欄位 (Dropping Columns)

若要刪除欄位,你可以使用 Schema Builder 上的 dropColumn 方法:

Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('votes');
});

你可以透過將欄位名稱陣列傳遞給 dropColumn 方法來從資料表中刪除多個欄位:

Schema::table('users', function (Blueprint $table) {
    $table->dropColumn(['votes', 'avatar', 'location']);
});

可用的指令別名 (Available Command Aliases)

Laravel 提供了幾個方便的方法來刪除常見類型的欄位。下表描述了這些方法:

指令說明
$table->dropMorphs('morphable');刪除 morphable_idmorphable_type 欄位。
$table->dropRememberToken();刪除 remember_token 欄位。
$table->dropSoftDeletes();刪除 deleted_at 欄位。
$table->dropSoftDeletesTz();dropSoftDeletes() 方法的別名。
$table->dropTimestamps();刪除 created_atupdated_at 欄位。
$table->dropTimestampsTz();dropTimestamps() 方法的別名。

索引 (Indexes)

建立索引 (Creating Indexes)

Laravel Schema Builder 支援多種類型的索引。以下範例建立一個新的 email 欄位並指定其值應該是唯一的。若要建立索引,我們可以將 unique 方法鏈接到欄位定義上:

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

Schema::table('users', function (Blueprint $table) {
    $table->string('email')->unique();
});

或者,你也可以在定義欄位後建立索引。為此,你應該在 Schema Builder Blueprint 上呼叫 unique 方法。此方法接受應該建立唯一索引的欄位名稱:

$table->unique('email');

你甚至可以將欄位陣列傳遞給索引方法來建立複合(或組合)索引:

$table->index(['account_id', 'created_at']);

建立索引時,Laravel 會根據資料表、欄位名稱和索引類型自動產生索引名稱,但你可以將第二個引數傳遞給方法來自行指定索引名稱:

$table->unique('email', 'unique_email');

可用的索引類型 (Available Index Types)

Laravel 的 Schema Builder Blueprint 類別提供了建立 Laravel 支援的每種索引類型的方法。每個索引方法都接受一個可選的第二個引數來指定索引的名稱。如果省略,名稱將根據資料表和欄位名稱以及索引類型衍生。下表描述了每個可用的索引方法:

| 指令 | 說明 | | ------------------------------------------------ | --------------------------------------------- | | $table->primary('id'); | 新增主鍵。 | | $table->primary(['id', 'parent_id']); | 新增複合主鍵。 | | $table->unique('email'); | 新增唯一索引。 | | $table->index('state'); | 新增索引。 | | $table->fullText('body'); | 新增全文索引 (MariaDB / MySQL / PostgreSQL)。 | | $table->fullText('body')->language('english'); | 新增指定語言的全文索引 (PostgreSQL)。 | | $table->spatialIndex('location'); | 新增空間索引(除 SQLite 外)。 |

重新命名索引 (Renaming Indexes)

若要重新命名索引,你可以使用 Schema Builder Blueprint 提供的 renameIndex 方法。此方法接受當前索引名稱作為第一個引數,以及所需的名稱作為第二個引數:

$table->renameIndex('from', 'to')

刪除索引 (Dropping Indexes)

若要刪除索引,你必須指定索引的名稱。預設情況下,Laravel 會根據資料表名稱、索引欄位的名稱和索引類型自動分配索引名稱。以下是一些範例:

指令說明
$table->dropPrimary('users_id_primary');從「users」資料表刪除主鍵。
$table->dropUnique('users_email_unique');從「users」資料表刪除唯一索引。
$table->dropIndex('geo_state_index');從「geo」資料表刪除基本索引。
$table->dropFullText('posts_body_fulltext');從「posts」資料表刪除全文索引。
$table->dropSpatialIndex('geo_location_spatialindex');從「geo」資料表刪除空間索引(除 SQLite 外)。

如果你將欄位陣列傳遞給刪除索引的方法,將會根據資料表名稱、欄位和索引類型產生慣例索引名稱:

Schema::table('geo', function (Blueprint $table) {
    $table->dropIndex(['state']); // 刪除索引 'geo_state_index'
});

外鍵約束 (Foreign Key Constraints)

Laravel 還提供了建立外鍵約束的支援,這用於在資料庫層級強制參照完整性。例如,讓我們在 posts 資料表上定義一個 user_id 欄位,該欄位參照 users 資料表上的 id 欄位:

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

Schema::table('posts', function (Blueprint $table) {
    $table->unsignedBigInteger('user_id');

    $table->foreign('user_id')->references('id')->on('users');
});

由於這種語法相當冗長,Laravel 提供了額外的、更簡潔的方法,使用慣例來提供更好的開發者體驗。使用 foreignId 方法建立欄位時,上面的範例可以改寫成這樣:

Schema::table('posts', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained();
});

foreignId 方法建立一個 UNSIGNED BIGINT 等效欄位,而 constrained 方法將使用慣例來判斷所參照的資料表和欄位。如果你的資料表名稱不符合 Laravel 的慣例,你可以手動將其提供給 constrained 方法。此外,也可以指定應分配給產生索引的名稱:

Schema::table('posts', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained(
        table: 'users', indexName: 'posts_user_id'
    );
});

你還可以指定約束的「on delete」和「on update」屬性所需的動作:

$table->foreignId('user_id')
    ->constrained()
    ->onUpdate('cascade')
    ->onDelete('cascade');

也為這些動作提供了另一種更具表達性的語法:

方法說明
$table->cascadeOnUpdate();更新應該級聯。
$table->restrictOnUpdate();更新應該受限。
$table->nullOnUpdate();更新應該將外鍵值設為 null。
$table->noActionOnUpdate();更新時不採取動作。
$table->cascadeOnDelete();刪除應該級聯。
$table->restrictOnDelete();刪除應該受限。
$table->nullOnDelete();刪除應該將外鍵值設為 null。
$table->noActionOnDelete();如果存在子記錄則防止刪除。

任何額外的欄位修飾詞必須在 constrained 方法之前呼叫:

$table->foreignId('user_id')
    ->nullable()
    ->constrained();

刪除外鍵 (Dropping Foreign Keys)

若要刪除外鍵,你可以使用 dropForeign 方法,將要刪除的外鍵約束名稱作為引數傳遞。外鍵約束使用與索引相同的命名慣例。換句話說,外鍵約束名稱是基於資料表名稱和約束中的欄位,後面加上「_foreign」後綴:

$table->dropForeign('posts_user_id_foreign');

或者,你可以將包含外鍵欄位名稱的陣列傳遞給 dropForeign 方法。該陣列將使用 Laravel 的約束命名慣例轉換為外鍵約束名稱:

$table->dropForeign(['user_id']);

切換外鍵約束 (Toggling Foreign Key Constraints)

你可以使用以下方法在 Migration 中啟用或停用外鍵約束:

Schema::enableForeignKeyConstraints();

Schema::disableForeignKeyConstraints();

Schema::withoutForeignKeyConstraints(function () {
    // 在此閉包內約束已停用...
});

[!WARNING] SQLite 預設停用外鍵約束。使用 SQLite 時,請確保在嘗試在 Migration 中建立外鍵之前,在資料庫設定中啟用外鍵支援

Event (Events)

為了方便起見,每個 Migration 操作都會分發一個 Event。以下所有 Event 都繼承自基礎 Illuminate\Database\Events\MigrationEvent 類別:

類別說明
Illuminate\Database\Events\MigrationsStarted一批 Migration 即將執行。
Illuminate\Database\Events\MigrationsEnded一批 Migration 已完成執行。
Illuminate\Database\Events\MigrationStarted單一 Migration 即將執行。
Illuminate\Database\Events\MigrationEnded單一 Migration 已完成執行。
Illuminate\Database\Events\NoPendingMigrationsMigration 指令沒有發現待處理的 Migration。
Illuminate\Database\Events\SchemaDumped資料庫 Schema 傾印已完成。
Illuminate\Database\Events\SchemaLoaded已載入現有的資料庫 Schema 傾印。