1、簡介
包是添加功能到Laravel 的主要方式。包可以提供任何功能,小到處理日期如 Carbon,大到整個 BDD 測試架構如 Behat。
當然,有很多不同類型的包。有些包是獨立的,意味著可以在任何架構中使用,而不僅是 Laravel。比如 Carbon 和 Behat 都是獨立的包。所有這些包都可以通過在 composer.json檔案中請求以便被 Laravel 使用。
另一方面,其它包只能特定和 Laravel 一起使用,這些包可能有路由,控制器、視圖和配置用於加強 Laravel 應用的功能,本章主要討論只能在 Laravel 中使用的包。
2、服務提供者
服務提供者是包和 Laravel 之間的連接點。服務提供者負責綁定對象到 Laravel 的服務容器並告知 Laravel 從哪裡載入包資源如視圖、配置和本地化檔案。
服務提供者繼承自 Illuminate\Support\ServiceProvider類並包含兩個方法: register和 boot。 ServiceProvider基類位於Composer包 illuminate/support。
要瞭解更多關於服務提供者的內容,查看其文檔。
3、路由
要定義包的路由,只需要在包服務提供者中的 boot方法中引入路由檔案。在路由檔案中,可以使用 Route門面註冊路由,和Laravel應用中註冊路由一樣:
/** * Perform post-registration booting of services. * * @return void */public function boot(){ if (! $this->app->routesAreCached()) { require __DIR__.'/../../routes.php'; }}
4、資源
4.1 視圖
要在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 */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時,你的視圖包將會被拷貝到指定路徑。
4.2 翻譯
如果你的包包含翻譯檔案,你可以使用 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將包翻譯檔案發布到應用的指定目錄。
4.3 配置
通常,你想要發布包設定檔到應用根目錄下的 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');
預設包配置
你還可以選擇將自己的包設定檔合并到應用的拷貝版本,這允許使用者只引入他們在應用設定檔中實際想要覆蓋的配置選項。要合并兩個配置,在服務提供者的 register方法中使用 mergeConfigFrom方法即可:
/** * Register bindings in the container. * * @return void */public function register(){ $this->mergeConfigFrom( __DIR__.'/path/to/config/courier.php', 'courier' );}
5、前端資源
你的包可能包含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
如果你想要確保前端資源已經更新到最新版本,可添加該命令到 composer.json檔案的 post-update-cmd列表。
6、發布檔案組
你可能想要分開發布包前端資源群組和資源,例如,你可能想要使用者發布包配置的同時不發布包前端資源,可以通過在調用時給它們打上“標籤”來實現分離。下面我們在包服務提供者的 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 --provider="Vendor\Providers\PackageServiceProvider" --tag="config"