Skip to main content
要持續維護使用資料庫的套件,除了首次安裝之外,還需要一套能將變更交付給已存在資料表之使用者的流程。請將 Migration 的公開、執行與執行紀錄視為不同的處理來設計。 本頁以套件開發的基礎為前提,解讀 Laravel 13 的 ServiceProvider、VendorPublishCommand 與 Migrator。框架的實作參照 v13.34.0。

複製後交付,還是從套件直接載入

publishesMigrations() 只是將複製來源與複製目的地註冊為公開對象。即使啟動服務提供者,也不會複製檔案或執行 SQL。 另一方面,loadMigrationsFrom() 會將搜尋路徑註冊至 Migrator。一般的 migrate 也會將該路徑下的檔案列為對象,但僅啟動服務提供者並不會執行它們。 若設計上讓使用者在執行前調整資料表名稱或欄位,公開方式是可考慮的選項。若由套件管理結構描述,且不預期使用者編輯檔案,也可以考慮直接載入方式。以下兩個服務提供者範例是彼此替代的方案。
請避免同時公開又直接載入同一個 Migration 的設計。若公開時時間戳記被變更,複製來源與複製目的地會被視為不同的執行紀錄,同一個建立資料表的處理可能會被執行兩次。

實作公開方式

加上套件專屬的標籤,讓使用者能將其與其他資源區分並公開。
首次安裝時,指定目標服務提供者與標籤進行複製,確認內容後再執行。同時指定兩者時,Laravel 會選出屬於該服務提供者、且帶有該標籤的公開對象。

時間戳記的變更與設定有關

官方文件說明了公開時會將 Migration 的時間戳記更新為目前日期時間的行為。不過,在 ServiceProvider::publishesMigrations() 的實作中,只有在 database.migrations.update_date_on_publish 啟用時,才會將複製來源加入時間戳記更新的對象。取得此設定時的預設值為 false。 Laravel 13 標準應用程式的 config/database.php 中有以下設定。沿用舊結構的應用程式,也請確認此設定是否存在。
此外,VendorPublishCommand 會在與已註冊之複製來源的實際路徑一致,且複製目的地的名稱帶有 YYYY_MM_DD_HHMMSS_ 格式時改寫日期時間。以指令開始的時刻為基準,每個對象檔案依序加 1 秒。若名稱中沒有此格式,該處理不會補上日期時間。
上述公開後的日期時間僅為說明用。實際的檔案名稱會依公開的時刻而異。
時間戳記更新同時取決於套件的註冊與使用端應用程式的設定。請勿從套件的服務提供者一律變更此設定,而應在安裝步驟中記載此前提。若使用設定快取,變更設定後也需要重新建置。

重新公開並不是「只新增尚未執行的項目」

vendor:publish 不會檢查資料庫的執行紀錄。此外,在 v13.34.0 的複製處理中,既有檔案的檢查是針對時間戳記變更前的複製目的地進行。即使是目錄公開,也會先確認複製目的地是否存在與複製來源相同的相對路徑,之後才改寫日期時間。 因此,若首次公開時日期時間已被變更,且應用程式端沒有與複製來源同名的檔案,再次公開同一個標籤時,可能會新增一個不同日期時間的檔案。請不要認為只要不加 --force 就一定能防止重複。

是否已執行是依檔案名稱判斷

Migrator::getMigrationName() 會回傳從檔案基本名稱去除 .php 後的字串。判斷是否尚未執行時,會將此名稱與執行紀錄比對。並不是依 PHP 內容或資料表名稱是否相同來判斷。
這兩者是不同的 Migration 名稱。即使前者已執行,僅憑該紀錄,後者也不會被視為已執行。
請勿在每次更新套件時無條件重新執行首次安裝用的公開指令,也不要將 --force 作為標準步驟。這不僅會覆寫對已公開檔案的編輯,還可能因日期時間變更而新增重複的處理。

實作直接載入方式

若希望直接將套件內的 Migration 作為執行對象,請註冊搜尋路徑。此方式不會額外加入公開同一檔案的處理。
loadMigrationsFrom() 會在 Migrator 被解析時呼叫 path()。Migrator::path() 會去除重複的搜尋路徑,getMigrationFiles() 則以 Migration 名稱作為鍵值整理找到的檔案,並依名稱排序。 使用者更新套件後,新檔案會成為下一次 migrate 的對象。請勿變更既有檔案的名稱,新的結構描述變更請新增檔案。為避免與其他套件衝突,請像 create_courier_deliveries_table 一樣在名稱中包含功能名稱。同名的檔案會成為相同的鍵值,並不會各自獨立執行。
從公開方式改為直接載入方式,並不只是改寫服務提供者而已。若使用者的執行紀錄是以公開時的名稱記錄,就會與套件端的原始名稱不一致。需要一套涵蓋既有使用者的執行紀錄、已公開檔案與回滾的遷移步驟。

將結構描述變更交付給既有使用者

例如要在配送資料表加入追蹤編號時,不要編輯已公開的 create_courier_deliveries_table,而是新增一個用於變更的新檔案。即使編輯既有的建立用 Migration,已執行過的使用者也不會套用該變更。
database/migrations/2026_10_02_000000_add_tracking_code_to_courier_deliveries_table.php
由於這是對已有資料列的資料表新增欄位的範例,此處設為 nullable。若需要改為必填或回填資料,請另外設計相應的步驟與執行順序。 在公開方式中,請準備一套與使用者已公開的檔案比對、只交付本次新增檔案的更新步驟。也可以為新檔案設立專用的公開標籤,但若日期時間更新已啟用,重複執行該標籤時也需要同樣的注意。不要讓更新步驟只是重新執行首次安裝用的標籤。 在直接載入方式中,更新後的程式碼能偵測到新檔案。無論採用哪種方式,僅有檔案存在並不會變更資料庫,因此請在發行說明中明確記載需要執行 Migration。

發行前的確認事項

除了套件的資料庫測試之外,也請在使用端應用程式中確認公開與更新的步驟。在測試中僅直接載入 Migration,並不等於驗證了檔案名稱會改變的公開方式。
  • 能在空的資料庫上進行首次安裝,並建立所需的資料表。
  • 從舊版本的資料庫與執行紀錄進行更新,只會套用新的變更。
  • 確認重複執行同一個公開指令時的檔案清單,更新步驟不會產生重複。
  • 步驟已考量日期時間更新的啟用與停用,以及對已公開檔案的編輯。
  • 確認新 Migration 的回滾,以及與應用程式其他 Migration 之間的執行順序。

相關頁面

Migration

確認結構描述定義、執行紀錄與回滾的基本概念。

套件的測試

測試套件的服務提供者與資料庫。

套件設定的合併與快取

確認考量使用者設定與設定快取的更新步驟。

版本相容性管理

將更新步驟與相容性變更連結至發行方針。

參考的一手資料

最後修改於 2026年10月2日