擴展包開發(fā)
擴展包開發(fā)
擴展包開發(fā)
簡介
擴展包是向 Laravel 中添加功能的主要方式。擴展包可以包含很多有用的功能,例如時間處理擴展包 Carbon,或提供完整 BDD 測試框架的擴展包 Behat。
當然,擴展包有很多種類型。有些擴展包是獨立運行的,意味著他們可以在任意的 PHP 框架中使用。Carbon 和 Behat 就是這樣的獨立擴展包。要在 Laravel 中使用這種擴展包只需要在 composer.json
文件中引入他們即可。
另一方面,有些擴展包只能在 Laravel 中使用。這些擴展包可能包含專門用來增強 Laravel 應用的路由、控制器、視圖和配置的文件。這份指南主要介紹 Laravel 擴展包的開發(fā)。
Facades 注解
當開發(fā) Laravel 應用時,通常使用契約(contracts)或 facades 沒有什么區(qū)別,因為他們都提供基本相同的可測試能力。然而,在進行擴展包開發(fā)的時候,擴展包并不能訪問 Laravel 提供的所有測試輔助函數。如果你想像在 Laravel 應用中一樣編寫擴展包的測試用例,你可以使用擴展包 Orchestral Testbench。
發(fā)現擴展包
在 Laravel 應用的 config/app.php
配置文件中,providers
選項定義了能夠被 Laravel 加載的服務提供者列表。當有人安裝你的擴展包時,你需要將你的服務提供者包含到這個列表中。你可以將服務提供者定義到擴展包的 composer.json
文件中的 extra
部分,而不是讓用戶手動將你的服務提供者添加到列表中。除了服務提供者,還可以列出所有你想注冊的 facades:
"extra": { "laravel": { "providers": [ "Barryvdh\\Debugbar\\ServiceProvider" ], "aliases": { "Debugbar": "Barryvdh\\Debugbar\\Facade" } } },
一旦你的擴展包配置為可發(fā)現,Laravel 就會在安裝時自動注冊擴展包的服務提供者和 facades,為擴展包的用戶提供一個友好的安裝體驗。
選擇性的發(fā)現擴展包
如果你是擴展包的用戶,想要禁止一個擴展包被發(fā)現,你可以在應用的 composer.json
文件中的 extra
部分列出這個擴展包:
"extra": { "laravel": { "dont-discover": [ "barryvdh/laravel-debugbar" ] } },
你也可以通過在應用的 dont-discover
指令中使用 *
字符,禁用擴展包發(fā)現功能:
"extra": { "laravel": { "dont-discover": [ "*" ] } },
服務提供者
服務提供者 讓你的擴展包與 Laravel 聯系在一起。服務提供者負責將一些東西綁定到 Laravel 的 服務容器 中,并且告訴 Laravel 從哪里加載擴展包的資源文件,例如視圖、配置文件、語言包等。
服務提供者繼承了 Illuminate\Support\ServiceProvider
類,并包含了兩個方法:register
和 boot
?;?ServiceProvider
位于名為 illuminate/support
的 Composer 擴展包中,你必須將它加入到你的擴展包依賴。想要了解更多關于服務提供者的結構和用途,請查閱 它的文檔.
資源文件
配置
有時,你需要將擴展包配置文件發(fā)布到應用本身的 config
目錄中。這樣使用擴展包的用戶就可以輕松的重寫默認配置項。想要發(fā)布擴展包配置文件,只需要在服務提供者的 boot
方法中調用 publishes
方法即可:
/** * 在注冊后啟動服務。 * * @return void */ public function boot(){ $this->publishes([ __DIR__.'/path/to/config/courier.php' => config_path('courier.php'), ]); }
現在,當擴展包的用戶執(zhí)行 Laravel 的 vendor:publish
命令,擴展包文件就會被復制到指定的目錄中。當然,一旦你的配置文件被發(fā)布,就可以如同其他配置一樣被訪問:
$value = config('courier.option');
{note} 你不應該在配置文件中定義閉包函數。因為當用戶執(zhí)行
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'); }
數據庫遷移
如果你的擴展包中包含 數據庫遷移,你需要使用 loadMigrationsFrom
方法告知 Laravel 如何加載他們。loadMigrationsFrom
方法只需要擴展包遷移文件路徑作為唯一參數:
/** * 在注冊后啟動服務。 * * @return void */ public function boot(){ $this->loadMigrationsFrom(__DIR__.'/path/to/migrations'); }
一旦你的擴展包遷移文件被注冊,當運行 php artisan migrate
命令時他們就會被自動執(zhí)行。你不需要將他們導入到應用的 database/migrations
目錄中。
語言包
如果你的擴展包中包含 語言包文件,你需要使用 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');
發(fā)布語言包
如果你想要將擴展包中的語言包發(fā)布到應用的 resources/lang/vendor
目錄,可以使用服務提供者的 publishes
方法。publishes
方法接收一個包含語言包路徑和對應發(fā)布位置的數組。例如,發(fā)布 courier
擴展包的語言包文件,操作如下:
/** * 在注冊后啟動服務。 * * @return void */ public function boot(){ $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); $this->publishes([ __DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'), ]); }
現在,當擴展包的用戶執(zhí)行 Laravel 的 vendor:publish
Artisan 命令,語言包將會被發(fā)布到指定的目錄中。
視圖
想要在 Laravel 中注冊你的擴展包的 視圖, 需要告知 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 首先會檢查開發(fā)人員是否在 resources/views/vendor/courier
中提供了一個自定義版本的視圖。然后,如果視圖尚未被定義,Laravel 將會搜索在 loadViewsFrom
中定義的視圖目錄。這種方法可以讓用戶很簡單的自定義或重寫擴展包的視圖。
發(fā)布視圖
如果你希望將你的視圖發(fā)布到應用的 resources/views/vendor
目錄中,可以使用服務提供者的 publishes
方法。publishes
方法接收一個包含視圖路徑和對應發(fā)布位置的數組:
/** * 在注冊后啟動服務。 * * @return void */ public function boot(){ $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); $this->publishes([ __DIR__.'/path/to/views' => resource_path('views/vendor/courier'), ]); }
現在,當擴展包的用戶執(zhí)行 Laravel 的 vendor:publish
Artisan 命令,視圖將會被發(fā)布到自定的目錄中。
命令
想要在 Laravel 中注冊擴展包的 Artisan 命令,需要使用 commands
方法。此方法接收一個命令類的數組。一旦這些命令注冊成功,可以使用 Artisan 命令行 執(zhí)行他們:
/** * 引導應用服務。 * * @return void */ public function boot(){ if ($this->app->runningInConsole()) { $this->commands([ FooCommand::class, BarCommand::class, ]); } }
公共資源文件
你的擴展包中可能存在 JavaScript、CSS 和圖片之類的資源文件。想要發(fā)布這些資源文件到應用的 public
目錄,可以使用服務提供者的 publishes
方法。在下面的例子中,我們也可以添加一個 public
資源分類標簽,可用于相關發(fā)布資源的分類:
/** * 在注冊后啟動服務。 * * @return void */ public function boot(){ $this->publishes([ __DIR__.'/path/to/assets' => public_path('vendor/courier'), ], 'public'); }
現在,當擴展包的用戶執(zhí)行 vendor:publish
命令,你的資源文件將會被復制到指定的目錄中。由于每次更新擴展包時通常都需要覆蓋資源文件,因此需要使用 --force
標簽:
php artisan vendor:publish --tag=public --force
發(fā)布群組文件
你可能想要分別打包發(fā)布擴展包資源文件或資源。舉個例子,你想讓用戶單獨發(fā)布擴展包中的配置文件,而不是被強制發(fā)布擴展包中的所有資源文件。你可以通過調用擴展包服務提供者中的 publishes
方法給不同文件打上「標簽」。例如,讓我們使用擴展包服務提供者中的 boot
方法來定義兩個發(fā)布群組:
/** * 在注冊后啟動服務。 * * @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'); }
現在你的用戶就可以通過執(zhí)行 vendor:publish
命令,根據定義的標簽來發(fā)布不同的群組文件:
php artisan vendor:publish --tag=config