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