[譯] 在 Laravel 應用程序之間共享數據庫

介紹

若是您碰巧在 Twitter 上關注了我,您可能已經看到我發表了一些我正在作的平常工做。咱們有一個面向客戶的會員區和一個內部 CRM,它們工做在同一個主數據庫上。php

CRM 是在我爲如今的老闆打工以前創建起來的,而會員區是我在 2017 年初做爲外包商創建的。會員區自己是一個新的 Laravel 應用程序,而 CRM 則是一個徹底自定義編寫的軟件。前端

304/5000 做爲外包商,我有一個數據庫的不完整副本,而且我設法從數據庫模式中反向工程 Eloquent 模型,建立工廠,以便可以爲會員應用編寫測試。mysql

在 2017 年年末,咱們開始將咱們的 CRM 遷移到 Laravel,以便對代碼庫進行一些現代化改造,爲其提供一個標準結構,而且能夠輕鬆地對其進行更改。如今咱們有兩個 Laravel 應用程序,咱們開始研究如何在它們之間共享數據。android

Eloquent 模型

數據庫模型是最容易處理的部分。爲此,咱們使用 Composer 爲每一個共享數據庫表建立模型建立一個包,並將它們做爲 vcs 存儲庫。這使咱們可以無需經過Packagist發佈就能夠共享這些模型。ios

這個包中的模型每一個都從它們本身的基礎模型擴展而來,它爲每一個數據庫設置鏈接,幷包含能夠將它們鏈接在一塊兒的最少許的邏輯。laravel

咱們試着讓包模型僅僅包含互相之間的關係,和一些通用的方法和行爲。思路就是是,每一個使用它們的應用程序都會根據須要擴展它們並實現它們本身的特定邏輯。git

遷移

遷移是事情開始變得有點棘手的地方。雖然咱們有一個技術上由 CRM 應用程序擁有的數據庫,但遷移應該可用於任何將訪問其中的數據的應用程序。那麼問題就變成了:「哪一個程序負責管理數據庫模式?」github

Laravel 在config/database.php文件中附帶多個數據庫鏈接,向您顯示各類驅動的可用性。咱們簡單的定義幾個都使用mysql` 驅動程序的鏈接。sql

咱們對管理數據庫模式有一些要求:docker

  1. 使用數據庫的任何一個應用程序不該負責管理遷移
  2. 遷移應該可以用於測試
  3. 若是可能,咱們但願使用 Laravel 的遷移功能

前兩個要求至關簡單,假設咱們能夠經過某種方式解決第三個要求。

獨立的實用程序

我花了很長時間把相似 Artisan 的工具集中在一塊兒,這個工具只關注遷移和數據庫填充功能 —— Nomad。爲了管理許多應用程序的數據庫遷移,Nomad 能夠被引入獨立的 Composer 項目 - 例如 Vagabond

Vagabond項目隨後被做爲一個包,您能夠將其做爲 VCS 存儲庫使用,並使用服務提供者,指導 Laravel 加載遷移,以及使用它的應用程序中可能存在的全部遷移。

// 在你的 Vagabond 項目的服務提供者中
public function boot()
{
    $this->loadMigrationsFrom(dirname(__FILE__).'/../database/migrations');
}
複製代碼

Nomad 實戰

咱們在 Nomad 路徑中遇到的第一個問題是,若是您沒有在遷移文件中指定遷移應該運行的鏈接,它們將所有在您的默認鏈接上運行。

// 在您的遷移文件中
public function up()
{
    Schema::connection('the_connection')->create('table', function (Blueprint $table)
    {
        //
    }
}
複製代碼

第二個問題是,雖然 Laravel 應用程序會在正確的鏈接上運行遷移,但它會跟蹤默認鏈接上的全部遷移,即若是您爲三個不一樣的鏈接運行遷移,則遷移歷史記錄將所有在應用程序默認鏈接的 migrations 表。

爲何這是個問題?若是您的數據庫用戶具備足夠的權限,它將嘗試並在已存在這些表的數據庫上反覆運行相同的遷移。

若是您有許多不一樣的應用程序都使用集中式遷移文件,而且每次都嘗試運行相同的遷移,則會出現此問題。

爲了解決這個問題,咱們在遷移項目的 database/migrations 文件夾中爲每一個鏈接的遷移建立了文件夾。

database/migrations/
                   /crm
                   /gis
                   /coverage
複製代碼

這樣作,咱們如今能夠爲各類遷移命令使用 pathdatabase 參數,使咱們可以顯式運行每一個鏈接的遷移: php nomad migrate --database=gis --path=database/migrations/gis。這確保只運行 gis 遷移,而且在 gis 數據庫的 migrations 表中追蹤運行遷移的歷史記錄。

這如今解決了要求1和3; 咱們如今在一個的獨立的數據庫上使用 Laravel 式遷移,而且咱們還擁有可以運行遷移的獨立應用程序。這意味着咱們能夠在代碼的任何地方運行運行鍼對特定數據庫鏈接的遷移 a) 能夠訪問到數據庫服務器,而且 b) 擁有具備足夠權限的用戶。

在測試中使用共享的遷移和模型

咱們遇到的另外一個問題是運行測試。

在咱們的測試環境中,咱們使用 Laravel 的 RefreshDatabase 特徵,它能夠智能地爲每一個測試創建並刪除整個數據庫。然而,在撰寫本文時,雖然它正確運行全部遷移,但它只會刪除默認數據庫鏈接上的表

這意味着若是咱們對使用本身的數據庫以及共享數據庫的應用程序進行測試,則每次測試都將失敗,由於 Laravel 會嘗試運行未丟棄鏈接的遷移。對此,Sepehr Lajevardi 有一個解決方案Keith Damiani 爲我指出明路。

Sepehr 的建議中說起的的特性使用一個從待刪表的鏈接數組中查找屬性的方法覆蓋 Laravel 的默認 refreshTestDatabase 方法。

數據庫配置

如今你已經將本身的模型和遷移都打包到了本身的倉庫中,這是最後一件你不想作的事情。從項目手動複製到另外一個項目,就是配置自己。

Laravel 實際上很容易將第三方軟件包的配置合併到主配置中。在咱們的生產應用程序中,咱們的數據庫配置中沒有配置任何鏈接。

相反,這個功能位於每一個數據庫鏈接的服務提供者內部。咱們有一個頂級提供程序,每一個提供程序均可以擴展,默認狀況下,每一個提供程序只需定義一個受保護的屬性:$connectionName

你能夠在這裏看到這個功能的獨立樣例。

您須要在應用程序中執行的操做是將服務提供程序添加到您的 config/app.php 文件的提供程序數組中,併爲每一個鏈接定義必要的環境變量。

持續集成

這個拼圖給咱們留下的最後一塊是讓測試在 CI 管道中運行。對咱們來講,是 BitBucket

因爲咱們現有的數據庫包含不少 ENUM 字段(我不建議使用它們,尤爲是由於它們不受這個庫的支持 —— doctrine/dbal —— Laravel 用於遷移功能),咱們必須在咱們的測試環境中使用 MySQL。

在CI管道中使用容器能夠輕鬆啓動 MySQL 服務,可是,如何配置多個數據庫卻並非顯而易見的。因爲咱們使用的 MariaDB 映像不容許指定綁定的端口,所以多個數據庫服務都嘗試偵聽同一個端口(3306),隨後沒法啓動,從而致使測試套件失敗。

解決方案很是簡單,只是我以前沒發現:在測試套件運行以前使用 MySQL 客戶端建立數據庫。

你的 bitbucket-pipelines.yml 文件應該以下所示:

image: php:7.1.15

pipelines:
  default:
    - step:
        deployment: test
        caches:
          - composer
        script:
          - apt-get update && apt-get install -y unzip git mysql-client
          - docker-php-ext-install pdo_mysql
          - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
          - cp -n .env.example .env
          - export DB_USERNAME=root
          - export DB_DATABASE=first_db
          - export DB_PASSWORD=supersecret
          - export DB_SECOND_USERNAME=root
          - export DB_SECOND_DATABASE=second_db
          - export DB_SECOND_PASSWORD=supersecret
          - export DB_THIRD_USERNAME=root
          - export DB_THIRD_DATABASE=third_db
          - export DB_THIRD_PASSWORD=supersecret
          - composer install
          - php artisan key:generate
          - mysql -uroot -psupersecret -h127.0.0.1 -e 'create database second_db; create database third_db;'
          - vendor/bin/phpunit --colors=always -c phpunit.xml
        services:
          - mariadb
definitions:
  services:
    mariadb:
      image: mariadb:5.5
      environment:
        MYSQL_DATABASE: 'first_db'
        MYSQL_ROOT_PASSWORD: 'supersecret'
複製代碼

export 這幾行爲咱們的應用程序做用的三個數據庫中的每一個數據庫進行配置。咱們讓 MariaDB 服務使用 MYSQL_DATABASE 環境變量配置第一個數據庫,而後使用 MySQL 客戶端建立 second_dbthird_db

MYSQL_ROOT_PASSWORD 變量被定義爲一個靜態字符串,由於我沒弄明白如何把隨機密碼注入部署步驟中,可是若是您知道如何作,請告訴我!

結論

若是您發現本身須要使用共享兩個或更多數據庫的應用程序,我但願您在本文中學到了有關管理和使用它們的知識。

涵蓋以下內容:

  • 打包模型和獨立遷移 Vagabond project
  • 利用 Nomad 把遷移做爲獨立應用程序運行
  • 在測試中處理多個數據庫鏈接
  • 使用 BitBucket Pipelines 在多個數據庫中成功運行測試

因爲應用程序與數據庫的分離,咱們必須考慮的一個因素是遷移應該如何以及什麼時候運行,由於咱們如今須要將其做爲單獨的操做來完成。它固然會根據具體狀況而有所不一樣,咱們須要確保針對每一個應用程序進行測試,以確保不會對數據庫引入重大更改。

我花了幾個月的時間才把它變成了工做狀態,因此我但願在將來的某個時候,若是你遇到和我類似的狀況,我可以爲你節省一些時間!

感謝 Keith DamianiSepehr Lajevardi 指出我拼圖中缺失的最後一塊。

Jake Bennett 和我在North Meets South網絡播客的 episode 43 中討論了這種遷移行爲。

若是您對本文中涵蓋的任何內容有任何疑問,或有任何改進建議,請隨時在 Twitter 上提出


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索