包開發
包是在 laravel 中添加功能的主要方式。包可以是任何形式,比如處理日期的 Carbon 或者是整個 BDD 測試框架 Behat。
當然,包是有不同類型的。有些包是獨立的包。意味著它可以在任何框架中使用,而不僅僅是在 laravel 中。Carbon 和 Behat 就是獨立的包。這些包你可以簡單的通過在 composer.json
文件中進行引入安裝使用。
而在另一方面,有些包是專門用于 laravel 使用的。這些包可能擁有路由,控制器,視圖和配置文件,他們配合起來旨在提高 laravel 的功能。這篇指南就是來告訴你如何開發增強 laravel 功能的包。
服務提供者
服務提供者是 laravel 和包的連接點。服務提供者主要負責包內容在服務容器中的綁定以及應用應該如何加載資源文件如視圖,配置文件和語言文件。
一個服務提供者應該繼承 Illuminate\Support\ServiceProvider
類并且包含兩個方法: register
和 boot
。基類 ServiceProvider
類位于 Composer 包的 illuminate/support
中。你應該在你的包中添加這個依賴。
路由
你可以在你的服務提供者的 boot
方法中簡單的 require
路由文件來定義包的路由。在你的路由文件中,你可以使用 Route
假面來注冊路由,其方式就如普通的 laravel 應用一樣:
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
if (! $this->app->routesAreCached(){
requir __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
目錄,另一個是你指定的目錄。所以,我們還使用上面的例子:當請求引入包視圖時,laravel 會首先檢查 resources/views/vendor/courier
目錄中是否有相應的視圖,然后,如果沒有才會通過 loadViewFrom
方法來加載指定的目錄下的視圖。這就引入了一種自定義包視圖的簡便方式。
發布視圖
如果你希望有一種簡單的方式將包的視圖發布到 resources/views/vendor
目錄。你可以在服務提供者中使用 publishes
方法。publishes
方法接收一個包視圖路徑和其發布地址路徑所組成的數組:
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
$this->loadViewsFrom(__DIR__.'/path/to/views', 'courier');
$this->publishes([
__DIR__./path/to/views' => resource_path('views/vendor/courier'),
]);
}
現在,當你通過命令行工具使用 vendor:publish
Artisan 命令時,你的包視圖會被復制到其所指定的位置。
譯文
如果你的包中包含了翻譯文件。你可以使用 loadTranslationsFrom
方法來指導 laravel 如何載入它們。比如,如果你的包名稱為 'courier',你應該使用如下的方式在你的服務提供者的 boot
方法中添加:
/**
* Perform post-registration booting of services
*
* @return void
*/
public function boot()
{
$this->loadTranslationsFrom(__DIR__./path/to/translations', 'courier');
}
包譯文的引入使用 package::filer.line
類似的語法。所以,你可以像這樣來加載 courier
包中的 messages
文件的 welcome
鍵:
echo trans('courier::messages.welcome');
發布譯文
如果你希望發布包的譯文到應用的 resources/lang/vendor
目錄,你可以使用服務提供者的 publishes
方法。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')
]);
}
現在,當你通過命令行工具使用 vendor:publish
Artisan 命令時,包中的譯文會自動的發布到指定的位置。
配置文件
通常,你希望發布你的包配置文件到應用的 config
目錄。這樣就允許用戶通過簡單的配置來覆蓋默認的配置選項。你可以使用 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 的 vendor:push
命令時,你的配置文件將會復制到指定的位置。當然,一旦你的配置文件被發布到 config
目錄,它就可以像訪問其他配置文件一樣被訪問:
$value = config('courier.option');
默認的包配置
你也可以選擇合并包的默認配置和應用復制的配置。這樣就允許用戶只引入其真實需要變更的配置選項。你可以使用 mergeConfigFrom
方法來在你的服務提供者的 register
方法中進行合并:
/**
* Register bindingsin the container.
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(
__DIR__.'/path/to/config/courier.php', 'courier'
);
}
公共資源文件
你的包文件中可能含有一些資源文件比如 JavaScript,CSS,圖片。你同樣可以在你的服務提供者中使用 publishes
方法來發布這些資源到應用的 public
目錄。我們同樣可以添加一個 public
組標簽,這樣可以選擇在發布時只發布 public
標簽組的文件:
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
$this->published([
__DIR__.'/path/to/assets' => public_path('vendor/courier'),
], 'public');
}
現在,使用你的包的用戶在執行 vendor:publish
命令時,你的資源文件會被發布到指定的位置。如果你需要每次發布資源時覆蓋之前發布的內容,你可以使用 --force
標識:
php artisan vendor:publish --tag=public --force
如果你希望你的公共資源總是在發布時是最新的版本,你應該在你的 composer.json
文件中的 post-update-cmd
列中添加上述命令。
發布組文件
你可能希望將前端資源和后端資源進行分組分開發布。比如,你可能希望用戶在發布配置文件的同時并不重新發布更新公共資源文件。你可以通過在使用 publishes
方法時對發布項打標簽的方式來對發布進行分組:
/**
* 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');
}
現在,你的包用戶可以在發布文件時通過組標簽來分開發布了:
php artisan vendor:publish --provider="Vendor\Providers\PackageServiceProvider"