[ Laravel 5.8 文件 ] 進階系列 —— 擴充套件包開發
簡介
擴充套件包是新增額外功能到 Laravel 的主要方式。擴充套件包可以提供任何功能,小到處理日期如Carbon ,大到整個 BDD 測試框架如Behat 。
當然,有很多不同型別的擴充套件包。有些擴充套件包是獨立於 Laravel 的,意味著可以在任何框架中使用,而不僅是 Laravel。比如 Carbon 和 Behat 都是獨立的擴充套件包。所有這些擴充套件包都可以通過在composer.json
檔案中宣告以便被 Laravel 使用。
另一方面,其它非獨立擴充套件包只能和 Laravel 一起使用,這些包可能有特定的路由、控制器、檢視和配置用於增強 Laravel 的功能,本文件主要討論只能在 Laravel 中使用的擴充套件包。
關於門面的注意點
編寫 Laravel 應用時,不管你使用契約還是門面,通常並沒有什麼關係,因為兩者都提供了基本同等級別的可測試性。不過,編寫擴充套件包時,在擴充套件包裡不能訪問所有的 Laravel 測試輔助函式。如果你想要像在擴充套件包中自如編寫擴充套件包測試,就像在Laravel應用中一樣,可以使用Orchestral Testbench 擴充套件包。
包自動發現
在 Laravel 應用的配置檔案config/app.php
中,providers
配置項定義了一個會被 Laravel 載入的服務提供者列表。當安裝完新的擴充套件包後,在老版本中需要將擴充套件包的服務提供者新增到這個列表以便被 Laravel 使用。從 Laravel 5.5 開始,我們不必再手動新增服務提供者到該列表,而是將提供者定義到擴充套件包下composer.json
檔案的extra
選項中,除了服務提供者之外,我們還可以以這種方式註冊門面:
"extra": { "laravel": { "providers": [ "Barryvdh\\Debugbar\\ServiceProvider" ], "aliases": { "Debugbar": "Barryvdh\\Debugbar\\Facade" } } },
定義好之後,在安裝擴充套件包之後 Laravel 就會自動註冊相應的服務提供者和門面,從而為擴充套件包使用者提供一個更加便捷的安裝體驗。
選擇包發現
如果你是包的使用者並且不想使用包自動發現功能,那麼可以像這樣在應用composer.json
檔案的section
選項中列出包名:
"extra": { "laravel": { "dont-discover": [ "barryvdh/laravel-debugbar" ] } },
你還可以在dont-discover
配置項中通過萬用字元*
禁止所有擴充套件包的自動發現功能:
"extra": { "laravel": { "dont-discover": [ "*" ] } },
服務提供者
服務提供者是擴充套件包和 Laravel 之間的連線紐帶。服務提供者負責繫結物件到 Laravel 的服務容器並告知 Laravel 從哪裡載入包資源如檢視、配置和本地化檔案。
服務提供者繼承自Illuminate\Support\ServiceProvider
類幷包含兩個方法:register
和boot
。ServiceProvider
基類位於 Composer 包illuminate/support
。要了解更多關於服務提供者的內容,檢視其文件。
資源
配置
通常,需要釋出擴充套件包配置檔案到應用根目錄下的config
目錄,這將允許擴充套件包使用者輕鬆覆蓋預設配置選項,要釋出一個配置檔案,只需在服務提供者的boot
方法中使用publishes
方法即可:
/** * Perform post-registration booting of services. * * @return void */ public function boot(){ $this->publishes([ __DIR__.'/path/to/config/courier.php' => config_path('courier.php'), ]); }
現在,當擴充套件包使用者執行 Laravel 的 Artisan 命令vendor:publish
時,你的檔案將會被拷貝到指定位置,當然,配置被髮布後,可以通過和其它配置選項一樣的方式進行訪問:
$value = config('courier.option');
注:不要在配置檔案中定義閉包,因為當用戶執行 Artisan 命令config:cache
時,閉包將不能被正確序列化。
預設擴充套件包配置
你還可以選擇將自己的擴充套件包配置檔案合併到應用的釋出副本,這允許使用者只引入他們在應用配置檔案中實際想要覆蓋的配置選項。要合併兩個配置,在服務提供者的register
方法中使用mergeConfigFrom
方法即可:
/** * 在容器中註冊繫結 * * @return void */ public function register(){ $this->mergeConfigFrom( __DIR__.'/path/to/config/courier.php', 'courier' ); }
注:這個方法只合併到配置資料第一維度。如果使用者定義了多維配置陣列,缺失的部分將不能被合併。
路由
如果擴充套件包包含路由,可以使用loadRoutesFrom
方法載入它們,這個方法會自動判定應用的路由是否被快取,如果路由已經被快取將不會載入路由檔案:
/** * Perform post-registration booting of services. * * @return void */ public function boot() { $this->loadRoutesFrom(__DIR__.'/routes.php'); }
遷移
如果你的擴充套件包包含資料庫遷移,可以使用loadMigrationsFrom
方法告知 Laravel 如何載入它們。loadMigrationsFrom
方法接收擴充套件包遷移的路徑作為其唯一引數:
/** * Perform post-registration booting of services. * * @return void */ public function boot() { $this->loadMigrationsFrom(__DIR__.'/path/to/migrations'); }
擴充套件包遷移註冊好之後,會在執行php artisan migrate
時自動執行。不需要將它們匯出到應用的database/migrations
目錄。
翻譯
如果你的擴充套件包包含翻譯檔案,你可以使用loadTranslationsFrom
方法告訴 Laravel 如何載入它們,例如,如果你的擴充套件包命名為courier
,應該新增如下程式碼到服務提供者的boot
方法:
/** * Perform post-registration booting of services. * * @return void */ public function boot(){ $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); }
擴充套件包翻譯使用形如package::file.line
的語法進行引用。所以,你可以使用如下方式從messages
檔案中載入courier
包的welcome
行:
echo trans('courier::messages.welcome');
釋出翻譯檔案
如果你想要釋出擴充套件包翻譯到應用的resources/lang/vendor
目錄,可以使用服務提供者的publishes
方法,該方法接收一個包路徑和相應釋出路徑陣列引數,例如,要釋出courier
擴充套件包的翻譯檔案,可以這麼做:
/** * Perform post-registration booting of services. * * @return void */ public function boot(){ $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); $this->publishes([ __DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'), ]); }
這樣,使用者就可以執行 Artisan 命令vendor:publish
將擴充套件包翻譯檔案釋出到應用的指定目錄。
檢視
要在 Laravel 中註冊擴充套件包檢視,需要告訴 Laravel 檢視在哪,可以使用服務提供者的loadViewsFrom
方法來實現。loadViewsFrom
方法接收兩個引數:檢視模板的路徑和擴充套件包名稱。例如,如果你的擴充套件包名稱是courier
,新增如下程式碼到服務提供者的boot
方法即可:
/** * Perform post-registration booting of services. * * @return void */ public function boot(){ $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); }
擴充套件包檢視通過使用形如package::view
的語法來引用。所以,你可以通過如下方式載入courier
擴充套件包上的admin
檢視:
Route::get('admin', function () { return view('courier::admin'); });
覆蓋擴充套件包檢視
當你使用loadViewsFrom
方法的時候,Laravel 實際上為檢視註冊了兩個存放位置:一個是resources/views/vendor
目錄,另一個是你指定的目錄。所以,以courier
為例:當請求一個擴充套件包檢視時,Laravel 首先檢查開發者是否在resources/views/vendor/courier
提供了自定義版本的檢視,如果該檢視不存在,Laravel 才會搜尋你呼叫loadViewsFrom
方法時指定的目錄。這種機制使得終端使用者可以輕鬆地自定義/覆蓋擴充套件包檢視。
釋出檢視
如果你想要檢視能夠釋出到應用的resources/views/vendor
目錄,可以使用服務提供者的publishes
方法。該方法接收包檢視路徑及其相應的釋出路徑陣列作為引數:
/** * Perform post-registration booting of services. * * @return void * @translator laravelacademy.org */ public function boot(){ $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); $this->publishes([ __DIR__.'/path/to/views' => base_path('resources/views/vendor/courier'), ]); }
現在,當使用者執行 Laravel Artisan 命令vendor:publish
時,擴充套件包檢視將會被拷貝到指定路徑。
命令
要通過 Laravel 註冊擴充套件包的 Artisan 命令,可以使用commands
方法。該方法需要傳入命令名稱陣列,註冊號命令後,可以使用Artisan CLI 執行它們:
/** * Bootstrap the application services. * * @return void */ public function boot() { if ($this->app->runningInConsole()) { $this->commands([ FooCommand::class, BarCommand::class, ]); } }
前端資源
你的擴充套件包可能包含 JavaScript、CSS 和圖片,要釋出這些前端資源到應用根目錄下的public
目錄,可以使用服務提供者的publishes
方法。在本例中,我們新增一個前端資源組標籤public
,用於釋出相關的前端資源組:
/** * Perform post-registration booting of services. * * @return void */ public function boot(){ $this->publishes([ __DIR__.'/path/to/assets' => public_path('vendor/courier'), ], 'public'); }
現在,當使用者執行vendor:publish
命令時,前端資源將會被拷貝到指定位置,由於需要在每次包更新時覆蓋前端資源,可以使用--force
標識:
php artisan vendor:publish --tag=public --force
釋出檔案組
有時候你可能想要分開發布擴充套件包前端資源和業務資源(配置、檢視等),例如,你可能想要使用者釋出擴充套件包配置的同時不釋出前端資源,這可以通過在擴充套件包的服務提供者中呼叫publishes
方法時給它們打上“標籤”來實現。下面我們在擴充套件包服務提供者的boot
方法中定義兩個釋出組:
/** * Perform post-registration booting of services. * * @return void */ public function boot(){ $this->publishes([ __DIR__.'/../config/package.php' => config_path('package.php') ], 'config'); $this->publishes([ __DIR__.'/../database/migrations/' => database_path('migrations') ], 'migrations'); }
現在,使用者可以在使用 Artisan 命令vendor:publish
時通過引用標籤名來分開發布這兩個組:
php artisan vendor:publish --tag=config