Laravel 入門:認識 Migration


Posted by SimonAllen on 2020-09-24

什麼是 Migration?

Migration 是用來定義、紀錄資料庫「架構」的「檔案」,它並不是「資料庫」本身,本質上仍是我們撰寫的後端程式碼,所以我們在 /migrations/ 資料夾下看到的仍是 .php 檔案。

多人協作的情境

前後端程式碼同步

前、後端的專案程式碼基本會用 Git push 上雲端備份,當今天多人協作時,A 改完 push 上去, B 可以接著把 code pull 下來同步,這個過程還可能會產生衝突,所以解衝突會是 RD 多人協作常見的情境。

資料庫同步

但資料庫呢?資料庫是獨立於後端語言框架的存在,要如何做到彼此 table 的遷移和同步?如果今天有人改了欄位名稱、新增 table、刪除某個欄位,該如何同步大家的 database 架構?

以往是輸出 .sql 的檔案,在交給其他人匯入,多人協作要一直輸出、匯入,要是遇到衝突會非常麻煩,若使用 Migration 檔案來定義、描述彼此的的 database 架構,再將 Migration 加入 git 版控,那麼大家只要彼此同步、更新 Migration 檔案即可,由 Migration 來描述、定義現在資料庫的結構,就能確保每個人的資料庫結構都一樣。

建立 Migration 檔案

要建立 Migration 檔案,我們可以在 Terminal 終端機下

php artisan make:migration ${檔名}

${} 符號表示依個人自訂輸入名稱,不需要真的輸入 ${}

例如我們在 Terminal 輸入

php artisan make:migration create_foods_table

database/migrations/

可以看見新建立的

2020_05_12_031245_create_foods_table

開頭多了一串數字 2020_05_12_031245,因為 Laravel Migration 檔案名稱的組成是

${時間戳記}_${檔名}.php

按照每個人建立時間不同,開頭時間也會不同。

且建立檔名在 Laravel Migration 也有些慣例,我們建立檔案時下 create_foods_tablecreate_ 開頭、_table 結尾,所以 Laravel 就會認為我們是要建立中間這個 foods 的 table 而自動幫我們帶入,打開 2020_05_12_031245_create_foods_table
可以看見 up()down() 已經幫我們帶入 foods 在 Schema::create 內了

Schema::create('foods', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
});

那如果後面不加上 _table 會發生什麼事情?
接著改成在 Terminal 輸入

php artisan make:migration create_foods_info

database/migrations/

可以看見新建立的

2020_05_12_032915_create_foods_info

up()可見以下內內容

Schema::create('foods_info', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
});

變成帶入 foods_info,但一樣是 table。

若將 create_ 開頭改成隨便自訂的名稱,例如在 Terminal 輸入

php artisan make:migration cooking_fried_chicken

database/migrations/

可以看見新建立的

2020_05_12_033803_cooking_fried_chicken

也就是說檔名仍可以照自己偏好去打,不強制一定要特定詞開頭,打開 2020_05_12_033803_cooking_fried_chicken,可以看見:

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

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    //
}

可以看到並沒有幫我們自動產生 Schema::createSchema::dropIfExists ,也沒自動帶入 cooking_fried_chicken 的名稱,這邊就要我們自己去輸入修改 up()down() 內容。
如果我們想要新建 Migration 檔案時不照 Laravel 慣例,又想要 Laravel 自動幫我們產生帶入 Schema::createSchema::dropIfExists code 和 table ,我們可用 --create 確定 table 的名稱或是否在 Migration 檔案創建新的 table。
例如在 Terminal 輸入

php artisan make:migration cooking_fried_chicken2 --create=fried_chicken

這邊一樣亂取名做例子,到

database/migrations/

可以看到

2020_05_12_034933_cooking_fried_chicken2

這次新建的檔案 up()down() 自動幫我們增加帶入 Schema::createSchema::dropIfExists 和 table 名稱 fried_chicken 了!

Schema::create('fried_chicken', function (Blueprint $table) {
 //..下略
});

語法

接著來看看 Migration 檔案,打開剛剛新建 cooking_fried_chicken2 可以看到

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

class CookingFriedChicken2 extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('fried_chicken', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('fried_chicken');
    }
}

我們新建的 class extends 繼承了上方 use 進來的 Migration,其中包含了兩個 public function ,那麼這兩個 up()down() 是用來做什麼的呢?

up()

up() 放的就是我們這次操作的程式邏輯,例如 create table、對欄位的新增移除或修改命名...等事情。

down()

down() 相對於up() ,彼此放的操作是相反的,也就是說在每個 migration 裡面,down() 應該要做能復原撤回 up() 所做的操作,up() :新增 table 那 down() 就移除 table 、up() 新增欄位 那 down() 就移除欄位,彼此就是字面上一步下一步的關係。

schena::

schena:: 對應我們要對 table 做的事情,後面可以接對應的 Methods 來完成我們的操作

建立 table

使用 create Methods 建立 table,第一個參數就是要建立 table 的名稱,第二個參數是個 function,且參數需帶入 Blueprint 物件,用來定義新的資料表。

Schema::create(${名稱}, function (Blueprint $table) {
    // ..下略
});

在後方 function 帶入 Blueprint $table 後,我們可以在 function 內對該要建立新 table Columns 做一些操作,

Columns Type

這裡隨便列出幾個,更詳盡的當然還是參閱官方文件

指令 描述
integer 整數格式,型態為 INTEGER
boolean 真假值格式,型態為 BOOLEAN
string 字串格式,型態為 BOOLEAN
text 長字串格式,型態為 TEXT
json json 格式,型態為 JSON
date 紀錄日期格式,型態為 DATE
dateTime 紀錄時間與日期格式,型態為 DATETIME
time 紀錄時間格式,型態為 TIME
increments 相當於 id,但是會自動增加不重複(例如文章 ID),型態相當於 UNSIGNED INTEGER
timestamp 這個指令會建立 created_at、updated_at 兩個時間欄位,用來記錄初次建立資料時間與後續修改時間
softDeletes 軟性刪除,例如刪除文章時用,當我們刪除文章時就會更新以此建立的 deleted_at 時間

所以例如我們要新建立 table test 並建立欄位 count ,型態為整數 integer,可以這樣寫:

Schema::create(test, function (Blueprint $table) {
   $table->integer('count');
});

Columns Modifier

除了上述指令外,還可以用 Columns Modifier 接續在後面,進行更細部操作,這裡也簡單列出幾個:

指令 描述
nullable 接續在目標 Columns Type 指令後方,表示此欄位在寫入更新時不一定要有值,可以為空
after 接續在目標 Columns Type 指令後方,表示建立的該欄位位置排序在某欄位下方
default 接續在目標 Columns Type 指令後方,寫入時若為空就給定此時指定預設值
useCurrent 如同上方的 default 給定預設值,只是是適用在時間型態,並給定當下時間做預設值

更改 table 名稱

使用 rename Methods 更改 table 名稱

Schema::rename(${當前名稱}, ${欲修改名稱});

刪除 table

要刪除已建立 table,可以使用 dropdropIfExists 這兩個 Methods

Schema::drop(${欲刪除 table 名})

Schema::dropIfExists(${欲刪除 table 名})

修改某 table 內容

Schema 後方也可以接 table,這個 Methods 可以對這個 table update 修改或建立已存在欄位或其他資訊,參數和 create 類似,第一個參數就是要修改內容的 table 名稱,第二個參數是個 function,帶入 Blueprint 物件,用來更新或操作這個 table。

Schema::table(${欲修改 table 名}, function (Blueprint $table) {
      // ..下略
});

#Laravel #筆記









Related Posts

React-[useEffect篇]- useEffect中的第二個參數dependency array以及搜索功能

React-[useEffect篇]- useEffect中的第二個參數dependency array以及搜索功能

[ Note ]更新到最新狀態,與 Huli 的 master 同步

[ Note ]更新到最新狀態,與 Huli 的 master 同步

[JS] 浮點數精度問題

[JS] 浮點數精度問題


Comments