* * * * *
[TOC]
## 簡介
擴展包是添加功能到 Laravel 的主要方式。擴展包可以包含許多好用的功能,像?[Carbon](https://github.com/briannesbitt/Carbon)?可用于處理時間,或像?[Behat](https://github.com/Behat/Behat)?這種完整的 BDD 測試框架。
當然,這有非常多不同類型的擴展包。有些擴展包是獨立運作的,意思是指他們在任何 PHP 框架中都可以使用。剛剛所提到的 Carbon 及 Behat 就是這種擴展包。要在 Laravel 中使用這種擴展包只需要在?`composer.json`?文件里引入它們即可。
另一方面,有些擴展包特別指定只能在 Laravel 里面集成。這些擴展包可能包含路由、控制器、視圖以及擴展包的相關設置,目的是增強 Laravel 本身的功能。這份指南里將主要以開發 Laravel 專屬的擴展包為目標進行說明。
### Facade 注解
當開發 Laravel 應用程序時,通常來講你使用契約(contracts) 還是 facades 并沒有什么區別,因為他們都提供了基本相同的水平的可測試性。但是,在進行擴展包開發的時候,你開發的擴展包并不能訪問所有 Laravel 提供的測試輔助函數。如果你想寫擴展包的測試,并讓這些測試看起來像是在一個典型的 Laravel 應用程序里,您可以使用?[Orchestral Testbench](https://github.com/orchestral/testbench)。
## 擴展包發現
在 Laravel 應用程序的?`config/app.php`?配置文件中,`providers`?選項定義了應該被 Laravel 加載的服務提供者的列表。當有人安裝你的擴展包時,你需要讓你的服務提供者包含在這個列表里。而不是要求用戶手動將你的服務提供者添加到這個列表里,你可能需要在你擴展包?`composer.json`?文件的?`extra`?部分的定義這些提供者。除了服務提供者,你也要列出可能想要注冊的?[facades](http://www.hmoore.net/tonyyu/laravel_5_6/786058):
~~~
"extra": {
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
~~~
當 Laravel 安裝的時候,一旦發現你的擴展包被配置,Laravel 將會自動的注冊它的服務提供者和 facades,為擴展包的用戶提供一個方便的安裝體驗。
### 選擇擴展包發現
如果你是擴展包的使用者,你想要禁用一個包的擴展包發現,你可以在應用程序的?`composer.json`?文件的?`extra`?部分列出這個擴展包:
~~~
"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar"
]
}
},
~~~
你可以通過在應用程序的?`dont-discover`?指令中使用?`*`?字符,禁用擴展包發現功能:
~~~
"extra": {
"laravel": {
"dont-discover": [
"*"
]
}
},
~~~
## 服務提供者
[服務提供者](http://www.hmoore.net/tonyyu/laravel_5_6/786057)?是你的擴展包與 Laravel 連接的重點。服務提供者負責綁定一些東西至 Laravel 的?[服務容器](http://www.hmoore.net/tonyyu/laravel_5_6/786056)?并告知 Laravel 要從哪加載擴展包的資源,例如視圖、配置文件、語言包。
服務提供者繼承了?`Illuminate\Support\ServiceProvider`?類并包含了兩個方法:?`register`?和?`boot`. 。基礎的?`ServiceProvider`?類被放置在 Composer 的?`illuminate/support`?擴展包,你必須將它加入至你自己的擴展包依賴中。若要了解更多關于服務提供者的結構與用途,請查閱?[它的文檔](http://www.hmoore.net/tonyyu/laravel_5_6/786057)。
## 資源文件
### 配置
有時候,你可能想要將擴展包的配置文件發布到應用程序本身的?`config`?目錄上。這能夠讓擴展包的用戶輕松的重寫這些默認的設置選項。如果要發布擴展包的配置文件,只需要在服務提供者里的?`boot`?方法內使用?`publishes`?方法:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->publishes([
__DIR__.'/path/to/config/courier.php' => config_path('courier.php'),
]);
}
~~~
現在當擴展包的用戶使用 Laravel 的?`vendor:publish`?命令時,擴展包的文件將會被復制到指定的位置上。當然,只要你的配置文件被發布,就可以如其它配置文件一樣被訪問:
~~~
$value = config('courier.option');
~~~
> {note} 您不應在配置文件中定義閉包函數。 當用戶執行?`config:cache`?Artisan命令時,它們不能正確地序列化。
#### 默認的擴展包配置文件
你也可以選擇合并你的擴展包配置文件和應用程序里的副本配置文件。這樣能夠讓你的用戶在已經發布的副本配置文件中只包含他們想要重寫的設置選項。如果想要合并配置文件,可在服務提供者里的?`register`?方法里使用?`mergeConfigFrom`?方法:
~~~
/**
* 在容器中注冊綁定。
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(
__DIR__.'/path/to/config/courier.php', 'courier'
);
}
~~~
> {note} 此方法僅合并配置數組的第一級。如果您的用戶部分定義了多維配置數組,則不會合并缺失的選項。
### 路由
如果您的擴展包中包含路由,您可以使用?`loadRoutesFrom`?方法加載它們。此方法將自動確定應用程序的路由是否已緩存,如果路由已緩存,將不會加載路由文件:
~~~
/**
* 執行服務的注冊后啟動。
*
* @return void
*/
public function boot()
{
$this->loadRoutesFrom(__DIR__.'/routes.php');
}
~~~
### 數據庫遷移
如果你的擴展包包含?[數據庫遷移](http://www.hmoore.net/tonyyu/laravel_5_6/786263)?,你需要使用?`loadMigrationsFrom`?方法告知 Laravel 如何去加載他們。`loadMigrationsFrom`?方法只需要你的擴展包的遷移文件路徑作為唯一參數:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->loadMigrationsFrom(__DIR__.'/path/to/migrations');
}
~~~
完成擴展包遷移文件注冊之后,在運行?`php artisan migrate`?命令時,它們就會自動被執行。你并不需要把他們導出到應用程序的?`database/migrations`?目錄。
### 語言包
如果你的擴展包里面包含了?[本地化](http://www.hmoore.net/tonyyu/laravel_5_6/786202)?,則可以使用?`loadTranslationsFrom`?方法來告知 Laravel 該如何加載它們。舉個例子,如果你的擴展包名稱為?`courier`?,你可以按照以下方式將其添加至服務提供者的?`boot`?方法:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier');
}
~~~
擴展包翻譯參照使用了雙分號?`package::file.line`?語法。所以,你可以按照以下方式來加載?`courier`?擴展包中的?`messages`?文件?`welcome`?語句:
~~~
echo trans('courier::messages.welcome');
~~~
#### 發布語言包
如果你想將擴展包的語言包發布至應用程序的?`resources/lang/vendor`?目錄,則可以使用服務提供者的?`publishes`方法。`publishes`?方法接受一個包含擴展包路徑及對應發布位置的數組。例如,在?`courier`?擴展包中發布語言包,示例如下:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier');
$this->publishes([
__DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'),
]);
}
~~~
現在,當使用你擴展包的用戶運行 Laravel 的?`vendor:publish`?Artisan 命令時,擴展包的語言包將會被復制到指定的位置上。
### 視圖
若要在 Laravel 中注冊擴展包?[視圖](http://www.hmoore.net/tonyyu/laravel_5_6/786178),則必須告訴 Laravel 你的視圖位置。你可以使用服務提供者的?`loadViewsFrom`?方法來實現。`loadViewsFrom`?方法允許兩個參數:視圖模板路徑與擴展包名稱。例如,如果你的擴展包名稱是?`courier`?,你可以按照以下方式將其添加至服務提供者的?`boot`?方法內:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @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`?方法。`publishes`?方法允許一個包含擴展包視圖路徑及對應發布路徑的數組:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->loadViewsFrom(__DIR__.'/path/to/views', 'courier');
$this->publishes([
__DIR__.'/path/to/views' => resource_path('views/vendor/courier'),
]);
}
~~~
現在,當你的擴展包用戶運行 Laravel 的?`vendor:publish`?Artisan 命令時,擴展包的視圖將會被復制到指定的位置上。
## 命令
給你的擴展包注冊 Artisan 命令,您可以使用?`commands`?方法。此方法需要一個命令類的數組。一旦命令被注冊,您可以使用?[Artisan 命令行](http://www.hmoore.net/tonyyu/laravel_5_6/786238)?執行它們:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->commands([
FooCommand::class,
BarCommand::class,
]);
}
}
~~~
## 公用 Assets
你的擴展包內可能會包含許多的資源文件,像 JavaScript、CSS 和圖片等文件。如果要發布這些資源文件到應用程序的?`public`?目錄上,只需使用服務提供者的?`publishes`?方法。在這個例子中,我們也會增加一個?`public`?的資源分類標簽,可用于發布與分類關聯的資源文件:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->publishes([
__DIR__.'/path/to/assets' => public_path('vendor/courier'),
], 'public');
}
~~~
現在,當您的擴展包的用戶執行?`vendor:publish`?命令時,您的 Assets 將被復制到指定的發布位置。由于每次更新包時通常都需要覆蓋資源,因此您可以使用?`--force`?標志:
~~~
php artisan vendor:publish --tag=public --force
~~~
## 發布群組文件
你可能想要分別發布分類的擴展包資源文件或是資源。舉例來說,你可能想讓用戶不用發布擴展包的所有資源文件,只需要單獨發布擴展包的配置文件即可。這可以通過在調用?`publishes`?方法時使用「標簽」來實現。例如,讓我們在擴展包的服務提供者中的?`boot`?方法定義兩個發布群組:
~~~
/**
* 在注冊后進行服務的啟動。
*
* @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');
}
~~~
現在當你的用戶使用?`vendor:publish`?Artisan 命令時,就可以通過標簽名稱分別發布不同分類的資源文件:
~~~
php artisan vendor:publish --tag=config
~~~
- 前言
- 翻譯說明
- 發行說明
- 升級指南
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- Homestead
- Valet
- 部署
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- Facades
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- URL
- Session
- 表單驗證
- 錯誤
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全相關
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試相關
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Scout 全文搜索
- Socialite 社會化登錄