翻譯進度
52.02% 已翻譯
更新時間:
2023年2月11日 中午12:59:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

套件開發

簡介

套件是用來給 Laravel 新增功能的主要方法。套件可以是任何東西,有像 Carbon 這樣可以方便處理日期的套件、或者是像 Spatie 的 Laravel Media Library 這樣用來處理與 Eloquent Model 關聯檔案的套件。

There are different types of packages. Some packages are stand-alone, meaning they work with any PHP framework. Carbon and Pest are examples of stand-alone packages. Any of these packages may be used with Laravel by requiring them in your composer.json file.

另一方面,有的套件是特別為了供 Laravel 使用而設計的。這些套件可能會有 Route、Controller、View、設定檔等等用來增強 Laravel 程式的功能。本篇指南主要就是在討論有關開發這些專為 Laravel 設計的套件。

A Note on Facades

在撰寫 Laravel 專案時,要使用 Contract 還是 Facade,一般來說沒什麼差別,因為兩者的可測試性都是相同的。不過,在開發套件的時候,我們要開發的套件可能無法存取所有的 Laravel 測試輔助函式。若想在測試套件是能像在一般的 Laravel 專案一樣測試,可使用 Orchestral Testbench 套件。

Package Discovery

A Laravel application's bootstrap/providers.php file contains the list of service providers that should be loaded by Laravel. However, instead of requiring users to manually add your service provider to the list, you may define the provider in the extra section of your package's composer.json file so that it is automatically loaded by Laravel. In addition to service providers, you may also list any facades you would like to be registered:

1"extra": {
2 "laravel": {
3 "providers": [
4 "Barryvdh\\Debugbar\\ServiceProvider"
5 ],
6 "aliases": {
7 "Debugbar": "Barryvdh\\Debugbar\\Facade"
8 }
9 }
10},
1"extra": {
2 "laravel": {
3 "providers": [
4 "Barryvdh\\Debugbar\\ServiceProvider"
5 ],
6 "aliases": {
7 "Debugbar": "Barryvdh\\Debugbar\\Facade"
8 }
9 }
10},

設定好 Discovery 後,Larave 就會在套件安裝時自動註冊套件的 Service Provider 與 Facade,帶給套件使用者一個方便的體驗。

Opting Out of Package Discovery

若有使用到某個套件且想為該套件禁用 Package Discovery 的話,可以將該套件名稱列在專案 composer.json 檔中的 extra 段落內:

1"extra": {
2 "laravel": {
3 "dont-discover": [
4 "barryvdh/laravel-debugbar"
5 ]
6 }
7},
1"extra": {
2 "laravel": {
3 "dont-discover": [
4 "barryvdh/laravel-debugbar"
5 ]
6 }
7},

可以在 dont-discover 指示詞內使用 * 字元來禁用所有套件的 Package Discovery:

1"extra": {
2 "laravel": {
3 "dont-discover": [
4 "*"
5 ]
6 }
7},
1"extra": {
2 "laravel": {
3 "dont-discover": [
4 "*"
5 ]
6 }
7},

Service Provider

Service Provider 是套件與 Laravel 間的連結點。Service Provider 負責將各種東西繫結到 Laravel 的 Service Container 上,並告訴 Laravel 要在哪裡載入套件的資源,如 View、設定檔、語系檔等。

Service Provider 應繼承 Illuminate\Support\ServiceProvider 類別,並包含兩個方法:registerbootServiceProvider 基礎類別放在 illuminate/support Composer 套件中,請在你的套件中將其加為相依性套件。若要瞭解更多有關 Service Provider 的架構與功能,請參見 Service Provider 的說明文件

資源

設定

一般來說,在製作套件的時候我們會想將套件的設定檔安裝到專案的 config 目錄內。這樣一來套件使用者就能輕鬆地覆寫預設設定。若要讓設定檔能安裝到專案內,請在 Service Provider 的 boot 方法內呼叫 publishes 方法:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishes([
7 __DIR__.'/../config/courier.php' => config_path('courier.php'),
8 ]);
9}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishes([
7 __DIR__.'/../config/courier.php' => config_path('courier.php'),
8 ]);
9}

然後,當套件使用者執行 Laravel 的 vendor:publish 指令時,這些檔案就會被複製到指定的安裝(Publish)地點。安裝好設定檔後,就可以像其他設定檔樣存取這些設定值:

1$value = config('courier.option');
1$value = config('courier.option');
lightbulb

請不要在設定檔中定義閉包。因為當使用者執行 config:cache Artisan 指令時,這些閉包沒有辦法被序列化。

預設套件設定

可以將套件自己的設定檔跟安裝到專案裡的設定檔合併。這樣一來,就能讓使用者在設定檔中只定義要覆寫的值。若要合併設定檔,請在 Service Provider 的 register 方法中使用 mergeConfigFrom 方法。

mergeConfigFrom 方法接受套件設定檔的路徑作為其第一個引數,而專案中的設定檔名稱則為其第二個引數:

1/**
2 * Register any application services.
3 */
4public function register(): void
5{
6 $this->mergeConfigFrom(
7 __DIR__.'/../config/courier.php', 'courier'
8 );
9}
1/**
2 * Register any application services.
3 */
4public function register(): void
5{
6 $this->mergeConfigFrom(
7 __DIR__.'/../config/courier.php', 'courier'
8 );
9}
lightbulb

該方法只會合併設定陣列中的第一層。若套件使用者只定義了多為陣列中的一部分,則未定義的部分將不會被合併。

Route

若套件中包含 Route,可使用 loadRoutesFrom 方法。該方法會自動判斷專案的 Route 是否有被快取,當有快取時將不會載入這些 Route 檔:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
7}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
7}

Migration

If your package contains database migrations, you may use the publishesMigrations method to inform Laravel that the given directory or file contains migrations. When Laravel publishes the migrations, it will automatically update the timestamp within their filename to reflect the current date and time:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishesMigrations([
7 __DIR__.'/../database/migrations' => database_path('migrations'),
8 ]);
9}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishesMigrations([
7 __DIR__.'/../database/migrations' => database_path('migrations'),
8 ]);
9}

語系檔

若套件有包含語系檔,可使用 loadTranslationsFrom 方法來讓 Laravel 載入這些檔案。舉例來說,若套件名稱為 courier,則可在 Service Provider 的 boot 方法中這樣寫:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
7}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
7}

套件的語系檔使用 package::file.line (套件::檔名.行) 語法慣例來參照。所以,courier 套件的 messages 檔案中,welcome 行可以這樣載入:

1echo trans('courier::messages.welcome');
1echo trans('courier::messages.welcome');

You can register JSON translation files for your package using the loadJsonTranslationsFrom method. This method accepts the path to the directory that contains your package's JSON translation files:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadJsonTranslationsFrom(__DIR__.'/../lang');
7}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadJsonTranslationsFrom(__DIR__.'/../lang');
7}

安裝語系檔

若想將套件的語系檔安裝到專案的 lang/vendor 目錄下,可使用 Service Provider 的 publishes 方法。publishes 方法接受一組套件路徑與欲安裝位置的陣列。舉例來說,若要為 courier 套件安裝語系檔,可以這樣寫:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
7 
8 $this->publishes([
9 __DIR__.'/../lang' => $this->app->langPath('vendor/courier'),
10 ]);
11}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
7 
8 $this->publishes([
9 __DIR__.'/../lang' => $this->app->langPath('vendor/courier'),
10 ]);
11}

接著,當套件使用者執行 Laravel 的 vendor:publish Artisan 指令後,套件的翻譯語系檔就會被安裝到指定的安裝位置內。

View

若要向 Laravel 註冊套件的 [View],我們需要告訴 Laravel 這些 View 存在哪裡。可以使用 Service Provider 的 loadViewsFrom 方法。loadViewsFrom 方法接受兩個引數:View 樣板的路徑,以及套件的名稱。舉例來說,若套件名稱為 courier,則可在 Service Provider 的 boot 方法中加入下列程式:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
7}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
7}

套件的 View 使用 package::view (套件::View) 語法慣例來參照。所以,在 Service Provider 內註冊好 View 的路徑後,就可以在 courier 套件中像這樣載入 dashboard View:

1Route::get('/dashboard', function () {
2 return view('courier::dashboard');
3});
1Route::get('/dashboard', function () {
2 return view('courier::dashboard');
3});

覆寫套件的 View

使用 loadViewsFrom 方法時,Laravel 實際上在兩個地方上都註冊為這個套件的 View 存放位置:專案的 resources/views/vendor 目錄,以及你所指定的目錄。所以,若以 courier 套件為例,Laravel 會先檢查 resources/views/vendor/courier 目錄下是否有開發人員覆寫的自訂版本。若沒找到自訂版本,Laravel 接著才會在呼叫 loadViewsFrom 時提供的路徑下搜尋套件的 View。這樣一來,套件使用者就能輕鬆地客製化 / 覆寫套件的 View。

安裝 View

若想讓 View 可被安裝到專案的 resources/views/vendor 目錄下,可使用 Service Provider 的 publishes 方法。publishes 方法接受一組套件 View 路徑與欲安裝路徑的陣列:

1/**
2 * Bootstrap the package services.
3 */
4public function boot(): void
5{
6 $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
7 
8 $this->publishes([
9 __DIR__.'/../resources/views' => resource_path('views/vendor/courier'),
10 ]);
11}
1/**
2 * Bootstrap the package services.
3 */
4public function boot(): void
5{
6 $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
7 
8 $this->publishes([
9 __DIR__.'/../resources/views' => resource_path('views/vendor/courier'),
10 ]);
11}

接著,當套件使用者執行 Laravel 的 vendor:publish Artisan 指令後,套件的 View 就會被複製到指定的安裝位置內。

View 元件

若想製作使用 Blade 元件的套件或將元件放在不符合慣例的目錄內,則需要手動註冊元件類別與其 HTML 標籤別名,以讓 Laravel 知道要在哪裡尋找元件。通常,應在套件的 Service Provider 內的 boot 方法中註冊你的元件:

1use Illuminate\Support\Facades\Blade;
2use VendorPackage\View\Components\AlertComponent;
3 
4/**
5 * Bootstrap your package's services.
6 */
7public function boot(): void
8{
9 Blade::component('package-alert', AlertComponent::class);
10}
1use Illuminate\Support\Facades\Blade;
2use VendorPackage\View\Components\AlertComponent;
3 
4/**
5 * Bootstrap your package's services.
6 */
7public function boot(): void
8{
9 Blade::component('package-alert', AlertComponent::class);
10}

註冊好元件後,便可使用其標籤別名來轉譯:

1<x-package-alert/>
1<x-package-alert/>

自動載入套件元件

或者,也可以使用 componentNamespace 方法來依照慣例自動載入元件類別。舉例來說,Nightshade 套件可能包含了放在 Nightshade\Views\Components Namespace 下的 CalendarColorPicker 元件:

1use Illuminate\Support\Facades\Blade;
2 
3/**
4 * Bootstrap your package's services.
5 */
6public function boot(): void
7{
8 Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
9}
1use Illuminate\Support\Facades\Blade;
2 
3/**
4 * Bootstrap your package's services.
5 */
6public function boot(): void
7{
8 Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
9}

這樣一來,就可以讓套件元件通過其 Vendor Namespace 來使用 package-name:: 語法:

1<x-nightshade::calendar />
2<x-nightshade::color-picker />
1<x-nightshade::calendar />
2<x-nightshade::color-picker />

Blade 會通過將元件名稱轉為 Pascal 命名法來自動偵測與這個元件關連的類別。也可以使用「點」語法來支援子目錄。

匿名元件

若套件中有匿名元件,則這些套件必須放在套件「view」目錄 (即 loadViewsFrom 方法 所指定的目錄) 下的 components 目錄內。接著,就可以使用套件 View 命名空間作為前置詞來轉譯套件:

1<x-courier::alert />
1<x-courier::alert />

「About」Artisan 指令

Laravel 的內建 about Artisan 指令提供了有關專案環境與設定的一覽。套件也可以使用 AboutCommand 類別來將額外資訊推入該指令的輸出中。一般來說,可在套件 Service Provider 的 boot 方法內加上該資訊:

1use Illuminate\Foundation\Console\AboutCommand;
2 
3/**
4 * Bootstrap any application services.
5 */
6public function boot(): void
7{
8 AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
9}
1use Illuminate\Foundation\Console\AboutCommand;
2 
3/**
4 * Bootstrap any application services.
5 */
6public function boot(): void
7{
8 AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
9}

指令

若要向 Laravel 註冊 Artisan 指令,可使用 commands 方法。這個方法接受一組指令類別名稱的陣列。註冊好指令後,就可以使用 Artisan CLI 來執行這些指令:

1use Courier\Console\Commands\InstallCommand;
2use Courier\Console\Commands\NetworkCommand;
3 
4/**
5 * Bootstrap any package services.
6 */
7public function boot(): void
8{
9 if ($this->app->runningInConsole()) {
10 $this->commands([
11 InstallCommand::class,
12 NetworkCommand::class,
13 ]);
14 }
15}
1use Courier\Console\Commands\InstallCommand;
2use Courier\Console\Commands\NetworkCommand;
3 
4/**
5 * Bootstrap any package services.
6 */
7public function boot(): void
8{
9 if ($this->app->runningInConsole()) {
10 $this->commands([
11 InstallCommand::class,
12 NetworkCommand::class,
13 ]);
14 }
15}

公用素材

套件也可以有像 JavaScript、CSS、圖片等的素材。若要將這些素材安裝到 public 目錄內,可使用 Service Provider 的 publishes 方法。在這個範例中,我們也給這些素材嫁了一個 public 素材群組標籤,這樣我們就能使用該標籤來輕鬆將一組相關的素材安裝到專案內:

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishes([
7 __DIR__.'/../public' => public_path('vendor/courier'),
8 ], 'public');
9}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishes([
7 __DIR__.'/../public' => public_path('vendor/courier'),
8 ], 'public');
9}

接著,當專案使用者執行 vendor:publish 指令後,素材就會被複製到指定的位置。由於使用者通常會需要在每次套件更新後都覆寫這些素材,因此可以使用 --force 旗標:

1php artisan vendor:publish --tag=public --force
1php artisan vendor:publish --tag=public --force

安裝檔案群組

有時候我們可能會想分別安裝套件素材與資源。舉例來說,我們可以讓使用者安裝套件的設定檔,但不強制使用者安裝套件素材。我們可以通過在 Service Provider 內呼叫 publishes 方法時為這些檔案指定「標籤」。舉例來說,我們來在 Service Provider 內 boot 方法中為 courier 套件定義兩個安裝群組 (courier-configcourier-migrations):

1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishes([
7 __DIR__.'/../config/package.php' => config_path('package.php')
8 ], 'courier-config');
9 
10 $this->publishesMigrations([
11 __DIR__.'/../database/migrations/' => database_path('migrations')
12 ], 'courier-migrations');
13}
1/**
2 * Bootstrap any package services.
3 */
4public function boot(): void
5{
6 $this->publishes([
7 __DIR__.'/../config/package.php' => config_path('package.php')
8 ], 'courier-config');
9 
10 $this->publishesMigrations([
11 __DIR__.'/../database/migrations/' => database_path('migrations')
12 ], 'courier-migrations');
13}

接著,使用者在執行 vendor:publish 指令時就可以使用標籤來分別安裝這些群組:

1php artisan vendor:publish --tag=courier-config
1php artisan vendor:publish --tag=courier-config
翻譯進度
52.02% 已翻譯
更新時間:
2023年2月11日 中午12:59:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

留言

尚無留言

“Laravel” is a Trademark of Taylor Otwell.
The source documentation is released under MIT license. See laravel/docs on GitHub for details.
The translated documentations are released under MIT license. See cornch/laravel-docs-l10n on GitHub for details.