# 擴展包開發
- [簡介](#introduction)
- [Facade 注解](#a-note-on-facades)
- [服務提供者](#service-providers)
- [路由](#routing)
- [資源文件](#resources)
- [配置](#configuration)
- [數據庫遷移](#migrations)
- [語言](#translations)
- [視圖](#views)
- [公共 Assets](#public-assets)
- [發布分類文件](#publishing-file-groups)
<a name="introduction"></a>
## 簡介
擴展包是添加功能到 Laravel 的主要方式。擴展包可以包含許多好用的功能,像 [Carbon](https://github.com/briannesbitt/Carbon) 可用于處理時間,或像 [Behat](https://github.com/Behat/Behat) 這種完整的 BDD 測試框架。
當然,這有非常多不同類型的擴展包。有些擴展包是獨立運作的,意思是指他們并不依賴于任何框架,包括 Laravel。剛剛所提到的 Carbon 及 Behat 就是這種擴展包。要使用這種擴展包只需要在 `composer.json` 文件里引入它們即可。
另一方面,有些擴展包特別指定只能在 Laravel 里面集成。這些擴展包可能包含路由、控制器、視圖以及擴展包的相關設置,目的是增強 Laravel 本身的功能。這份指南里將主要以開發 Laravel 專屬的擴展包為目標進行說明。
<a name="a-note-on-facades"></a>
### Facade 注解
當開發 Laravel 應用程序時,通常來講你使用契約(contracts) 還是 facades 并沒有什么區別,因為他們都提供了基本相同的水平的可測試性。但是,在進行擴展包開發的時候,最好的方式是使用 [契約](/docs/{{version}}/contracts),而不是 [facades](/docs/{{version}}/facades)。因為你開發的包并不能訪問所有 Laravel 提供的測試輔助函數,模擬契約(contracts) 要比模擬 facade 簡單很多。
<a name="service-providers"></a>
## 服務提供者
[服務提供者](/docs/{{version}}/providers) 是你的擴展包與 Laravel 連接的重點。服務提供者負責綁定一些東西至 Laravel 的 [服務容器](/docs/{{version}}/container) 并告知 Laravel 要從哪加載擴展包的資源,例如視圖、配置文件、語言包。
服務提供者繼承了 `Illuminate\Support\ServiceProvider` 類并包含了兩個方法:`register` 及 `boot`。基底的 `ServiceProvider` 類被放置在 Composer 的 `illuminate/support` 擴展包,你必須將它加入至你自己的擴展包依賴中。
若要了解更多關于服務提供者的結構與用途,請查閱 [它的文檔](/docs/{{version}}/provider)。
<a name="routing"></a>
## 路由
要為你的擴展包定義路由,只需簡單的在擴展包的服務提供者的 `boot` 方法 `require` 路由文件。在你的路由文件中,你可以如同在一般的 Laravel 應用程序中一樣使用 `Route` facade 來 [注冊路由](/docs/{{version}}/routing):
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
if (! $this->app->routesAreCached()) {
require __DIR__.'/../../routes.php';
}
}
<a name="resources"></a>
## 資源文件
<a name="configuration"></a>
### 配置
有時候,你可能想要將擴展包的配置文件發布到應用程序本身的 `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');
#### 默認的擴展包配置文件
你也可以選擇合并你的擴展包配置文件和應用程序里的副本配置文件。這樣能夠讓你的用戶在已經發布的副本配置文件中只包含他們想要重寫的設置選項。如果想要合并配置文件,可在服務提供者里的 `register` 方法里使用 `mergeConfigFrom` 方法:
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(
__DIR__.'/path/to/config/courier.php', 'courier'
);
}
<a name="migrations"></a>
### 數據庫遷移
如果你的擴展包包含 [數據庫遷移文件](/docs/{{version}}/migrations),你需要使用 `loadMigrationsFrom` 方法告知 Laravel 如何去加載他們。`loadMigrationsFrom` 方法只需要你的擴展包的遷移文件路徑作為唯一參數。
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->loadMigrationsFrom(__DIR__.'/path/to/migrations');
}
完成擴展包遷移文件注冊之后,在運行 `php artisan migrate` 命令時,它們就會自動被執行。你并不需要把他們導出到應用程序的 `database/migrations` 目錄。
<a name="translations"></a>
### 語言
如果你的擴展包里面包含了 [語言文件](/docs/{{version}}/localization),則可以使用 `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 命令時,擴展包的語言包將會被復制到指定的位置上。
<a name="views"></a>
### Views
若要在 Laravel 中注冊擴展包 [視圖](/docs/{{version}}/views),則必須告訴 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 命令時,擴展包的視圖將會被復制到指定的位置上。
<a name="public-assets"></a>
## 公用 Assets
你的擴展包內可能會包含許多的資源文件,像 JavaScript、CSS 和圖片等文件。如果要發布這些資源文件到應用程序的 `public` 目錄上,只需使用服務提供者的 `publishes` 方法。在這個例子中,我們也會增加一個 `public` 的資源分類標簽,可用于發布與分類關聯的資源文件:
/**
* 在注冊后進行服務的啟動。
*
* @return void
*/
public function boot()
{
$this->publishes([
__DIR__.'/path/to/assets' => public_path('vendor/courier'),
], 'public');
}
如果你想要確保公用資源文件始終保持在最新的版本,可以將此命令加入 `composer.json` 文件中的 `post-update-cmd` 列表。
php artisan vendor:publish --tag=public --force
<a name="publishing-file-groups"></a>
## 發布分類文件
你可能想要分別發布分類的擴展包資源文件或是資源。舉例來說,你可能想讓用戶不用發布擴展包的所有資源文件,只需要單獨發布擴展包的配置文件即可。這可以通過在調用 `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"
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@JobsLong](https://phphub.org/users/56) | <img class="avatar-66 rm-style" src="http://i4.buimg.com/567571/a3dc28a55fdb2b7a.png"> | 翻譯 | 個人主頁:[http://jobslong.com](http://jobslong.com) |
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 錯誤與日志
- 開發環境
- HomeStead
- Valet
- 核心概念
- 服務容器
- 服務提供者
- 門面(facades)
- contracts
- HTTP層
- 路由
- 中間件
- CSRF保護
- 控制器
- 請求
- 響應
- Session
- 表單驗證
- 視圖與模板
- 視圖
- Blade模板
- 本地化
- Javascript與CSS
- 入門指南
- laravel-elixir
- 安全
- 用戶認證
- 用戶授權
- 重置密碼
- API授權
- 加密解密
- 哈希
- 綜合話題
- 廣播系統
- 緩存系統
- 事件系統
- 文件存儲
- 郵件發送
- 消息通知
- 隊列
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent集合
- 修改器
- 序列化
- Artisan控制臺
- Artisan 命令行
- 任務調度
- 測試
- 快速入門
- 應用程序測試
- 數據庫測試
- 模擬器
- 官方擴展包
- Cashier交易包
- Envoy 部署工具
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 附錄
- 集合
- 輔助函數
- 擴展包開發
- 交流說明