包是添加功能到Laravel的主要方式。包可以提供任何功能,小到處理日期如Carbon,大到整個BDD測試框架如Behat。
當然,有很多不同類型的包。有些包是獨立的,意味著可以在任何框架中使用,而不僅是Laravel。比如Carbon和Behat都是獨立的包。所有這些包都可以通過在composer.json
文件中請求以便被Laravel使用。
另一方面,其它包只能特定和Laravel一起使用,這些包可能有路由用于加強Laravel應用的功能,本章主要討論只能在Laravel中使用的包。
服務提供者是包和Laravel之間的連接點。服務提供者負責綁定對象到Laravel的服務容器并告知Laravel從哪里加載包資源如視圖、配置和本地化文件。
服務提供者繼承自Illuminate\Support\ServiceProvider
類并包含兩個方法:register
和boot
。ServiceProvider
基類位于Composer包illuminate/support
。
要了解更多關于服務提供者的內容,查看其文檔。
要定義包的路由,只需要在包服務提供者中的boot
方法中引入路由文件。在路由文件中,可以使用Route
門面注冊路由,和Laravel應用中注冊路由一樣:
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot(){
if (! $this->app->routesAreCached()) {
require __DIR__.'/../../routes.php';
}
}
要在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首先檢查開發(fā)者是否在resources/views/vendor/courier
提供了自定義版本的視圖,如果該視圖不存在,Laravel才會搜索你調用loadViewsFrom
方法時指定的目錄。這種機制使得終端用戶可以輕松地自定義/覆蓋包視圖。
如果你想要視圖能夠發(fā)布到應用的resources/views/vendor
目錄,可以使用服務提供者的publishes
方法。該方法接收包視圖路徑及其相應的發(fā)布路徑數組作為參數:
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot(){
$this->loadViewsFrom(__DIR__.'/path/to/views', 'courier');
$this->publishes([
__DIR__.'/path/to/views' => base_path('resources/views/vendor/courier'),
]);
}
現在,當包用戶執(zhí)行Laravel的Artisan命令vendor:publish
時,你的視圖包將會被拷貝到指定路徑。
如果你的包包含翻譯文件,你可以使用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');
通常,你想要發(fā)布包配置文件到應用根目錄下的config
目錄,這將允許包用戶輕松覆蓋默認配置選項,要發(fā)布一個配置文件,只需在服務提供者的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'),
]);
}
現在,當包用戶執(zhí)行Laravel的Artisan命令vendor:publish
時,你的文件將會被拷貝到指定位置,當然,配置被發(fā)布后,可以通過和其它配置選項一樣的方式進行訪問:
$value = config('courier.option');
你還可以選擇將自己的包配置文件合并到應用的拷貝版本,這允許用戶只引入他們在應用配置文件中實際想要覆蓋的配置選項。要合并兩個配置,在服務提供者的register
方法中使用mergeConfigFrom
方法即可:
/**
* Register bindings in the container.
*
* @return void
*/
public function register(){
$this->mergeConfigFrom(
__DIR__.'/path/to/config/courier.php', 'courier'
);
}
你的包可能包含JavaScript、CSS和圖片,要發(fā)布這些前端資源到應用根目錄下的public
目錄,使用服務提供者的publishes
方法。在本例中,我們添加一個前端資源組標簽public
,用于發(fā)布相關的前端資源組:
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot(){
$this->publishes([
__DIR__.'/path/to/assets' => public_path('vendor/courier'),
], 'public');
}
現在,當包用戶執(zhí)行vendor:publish
命令時,前端資源將會被拷貝到指定位置,由于你需要在每次包更新時重寫前端資源,可以使用--force
標識:
php artisan vendor:publish --tag=public --force
如果你想要確保前端資源已經更新到最新版本,可添加該命令到composer.json
文件的post-update-cmd
列表。
你可能想要分開發(fā)布包前端資源組和資源,例如,你可能想要用戶發(fā)布包配置的同時不發(fā)布包前端資源,可以通過在調用時給它們打上“標簽”來實現分離。下面我們在包服務提供者的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
時通過引用標簽名來分開發(fā)布這兩個組:
php artisan vendor:publish --provider="Vendor\Providers\PackageServiceProvider" --tag="config"
更多建議: