包开发
介绍
包是向 Laravel 添加功能的主要方式。包可以是任何东西,从一个处理日期的好方法如 Carbon,到一个完整的 BDD 测试框架如 Behat。
当然,包有不同的类型。有些包是独立的,意味着它们可以与任何 PHP 框架一起工作。Carbon 和 Behat 就是独立包的例子。任何这些包都可以通过在 composer.json
文件中请求它们来与 Laravel 一起使用。
另一方面,其他包是专门为 Laravel 使用而设计的。这些包可能有路由、控制器、视图和配置,专门用于增强 Laravel 应用程序。本指南主要涵盖那些专门为 Laravel 开发的包。
关于 Facades 的说明
在编写 Laravel 应用程序时,使用 contracts 还是 facades 通常无关紧要,因为两者都提供了基本相同的可测试性。然而,在编写包时,您的包通常无法访问所有 Laravel 的测试助手。如果您希望能够像在典型的 Laravel 应用程序中一样编写包测试,可以使用 Orchestral Testbench 包。
包发现
在 Laravel 应用程序的 config/app.php
配置文件中,providers
选项定义了 Laravel 应该加载的服务提供者列表。当有人安装您的包时,您通常希望您的服务提供者被包含在此列表中。您可以在包的 composer.json
文件的 extra
部分中定义提供者,而不是要求用户手动将您的服务提供者添加到列表中。除了服务提供者,您还可以列出任何您希望注册的 facades:
"extra": {
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
一旦您的包配置为发现,Laravel 将在安装时自动注册其服务提供者和 facades,为您的包用户创造一个方便的安装体验。
选择退出包发现
如果您是包的消费者并希望禁用包发现,可以在应用程序的 composer.json
文件的 extra
部分列出包名:
"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar"
]
}
},
您可以使用应用程序的 dont-discover
指令中的 *
字符禁用所有包的发现:
"extra": {
"laravel": {
"dont-discover": [
"*"
]
}
},
服务提供者
服务提供者 是您的包与 Laravel 之间的连接点。服务提供者负责将内容绑定到 Laravel 的 服务容器 并告知 Laravel 从哪里加载包资源,如视图、配置和本地化文件。
服务提供者扩展了 Illuminate\Support\ServiceProvider
类,并包含两个方法:register
和 boot
。基础 ServiceProvider
类位于 illuminate/support
Composer 包中,您应该将其添加到您自己的包依赖项中。要了解有关服务提供者的结构和目的的更多信息,请查看 他们的文档。
资源
配置
通常,您需要将包的配置文件发布到应用程序自己的 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');
您不应在配置文件中定义闭包。当用户执行 config:cache
Artisan 命令时,它们无法正确序列化。
默认包配置
您还可以将自己的包配置文件与应用程序的已发布副本合并。这将允许您的用户仅定义他们实际想要在已发布配置副本中覆盖的选项。要合并配置,请在服务提供者的 register
方法中使用 mergeConfigFrom
方法:
/**
* 在容器中注册绑定。
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(
__DIR__.'/path/to/config/courier.php', 'courier'
);
}
此方法仅合并配置数组的第一级。如果您的用户部分定义了多维配置数组,缺少的选项将不会被合并。
路由
如果您的包包含路由,可以使用 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
命令时,它们将自动运行。您不需要将它们导出到应用程序的主 database/migrations
目录。
翻译
如果您的包包含 翻译文件,可以使用 loadTranslationsFrom
方法告知 Laravel 如何加载它们。例如,如果您的包名为 courier
,您应该在服务提供者的 boot
方法中添加以下内容:
/**
* 执行服务的注册后引导。
*
* @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
方法。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,您需要告诉 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 命令注册到 Laravel,可以使用 commands
方法。此方法期望一个命令类名的数组。一旦命令被注册,您可以使用 Artisan CLI 执行它们:
/**
* 引导应用程序服务。
*
* @return void
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->commands([
FooCommand::class,
BarCommand::class,
]);
}
}
公共资源
您的包可能有 JavaScript、CSS 和图像等资源。要将这些资源发布到应用程序的 public
目录,可以使用服务提供者的 publishes
方法。在此示例中,我们还将添加一个 public
资源组标签,可以用来发布相关资源组:
/**
* 执行服务的注册后引导。
*
* @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
发布文件组
您可能希望单独发布包资源和资源组。例如,您可能希望允许用户发布包的配置文件,而不必强制发布包的资源。可以通过在包的服务提供者的 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
命令时引用其标签来单独发布这些组:
php artisan vendor:publish --tag=config