Skip to content

包开发

介绍

包是向 Laravel 添加功能的主要方式。包可以是任何东西,从像 Carbon 这样处理日期的好方法,到像 Behat 这样完整的 BDD 测试框架。

包有不同的类型。有些包是独立的,意味着它们可以与任何 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

php
"extra": {
    "laravel": {
        "providers": [
            "Barryvdh\\Debugbar\\ServiceProvider"
        ],
        "aliases": {
            "Debugbar": "Barryvdh\\Debugbar\\Facade"
        }
    }
},

一旦您的包配置为发现,Laravel 将在安装时自动注册其服务提供者和 facades,为您的包用户创建一个方便的安装体验。

选择退出包发现

如果您是包的消费者并希望禁用包发现,可以在应用程序的 composer.json 文件的 extra 部分列出包名:

php
"extra": {
    "laravel": {
        "dont-discover": [
            "barryvdh/laravel-debugbar"
        ]
    }
},

您可以使用应用程序的 dont-discover 指令中的 * 字符禁用所有包的发现:

php
"extra": {
    "laravel": {
        "dont-discover": [
            "*"
        ]
    }
},

服务提供者

服务提供者 是您的包与 Laravel 之间的连接点。服务提供者负责将内容绑定到 Laravel 的 服务容器 并告知 Laravel 从哪里加载包资源,如视图、配置和本地化文件。

服务提供者扩展 Illuminate\Support\ServiceProvider 类,并包含两个方法:registerboot。基础 ServiceProvider 类位于 illuminate/support Composer 包中,您应该将其添加到您自己的包依赖项中。要了解有关服务提供者结构和目的的更多信息,请查看 他们的文档

资源

配置

通常,您需要将包的配置文件发布到应用程序自己的 config 目录。这将允许您的包用户轻松覆盖您的默认配置选项。要允许发布配置文件,请从服务提供者的 boot 方法中调用 publishes 方法:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    $this->publishes([
        __DIR__.'/path/to/config/courier.php' => config_path('courier.php'),
    ]);
}

现在,当您的包用户执行 Laravel 的 vendor:publish 命令时,您的文件将被复制到指定的发布位置。一旦您的配置被发布,其值可以像任何其他配置文件一样访问:

php
$value = config('courier.option');
exclamation

您不应在配置文件中定义闭包。当用户执行 config:cache Artisan 命令时,它们无法正确序列化。

默认包配置

您还可以将自己的包配置文件与应用程序的已发布副本合并。这将允许您的用户仅在配置的已发布副本中定义他们实际想要覆盖的选项。要合并配置,请在服务提供者的 register 方法中使用 mergeConfigFrom 方法:

php
/**
 * 注册任何应用程序服务。
 *
 * @return void
 */
public function register()
{
    $this->mergeConfigFrom(
        __DIR__.'/path/to/config/courier.php', 'courier'
    );
}
exclamation

此方法仅合并配置数组的第一级。如果您的用户部分定义了多维配置数组,缺少的选项将不会被合并。

路由

如果您的包包含路由,可以使用 loadRoutesFrom 方法加载它们。此方法将自动确定应用程序的路由是否已缓存,并且如果路由已缓存,将不会加载您的路由文件:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    $this->loadRoutesFrom(__DIR__.'/routes.php');
}

迁移

如果您的包包含 数据库迁移,可以使用 loadMigrationsFrom 方法告知 Laravel 如何加载它们。loadMigrationsFrom 方法接受包迁移的路径作为其唯一参数:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    $this->loadMigrationsFrom(__DIR__.'/path/to/migrations');
}

一旦您的包迁移被注册,当执行 php artisan migrate 命令时,它们将自动运行。您不需要将它们导出到应用程序的主 database/migrations 目录。

工厂

如果您的包包含 数据库工厂,可以使用 loadFactoriesFrom 方法告知 Laravel 如何加载它们。loadFactoriesFrom 方法接受包工厂的路径作为其唯一参数:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    $this->loadFactoriesFrom(__DIR__.'/path/to/factories');
}

一旦您的包工厂被注册,您可以在应用程序中使用它们:

php
factory(Package\Namespace\Model::class)->create();

翻译

如果您的包包含 翻译文件,可以使用 loadTranslationsFrom 方法告知 Laravel 如何加载它们。例如,如果您的包名为 courier,您应该在服务提供者的 boot 方法中添加以下内容:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier');
}

包翻译使用 package::file.line 语法约定引用。因此,您可以像这样从 messages 文件中加载 courier 包的 welcome 行:

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

发布翻译

如果您希望将包的翻译发布到应用程序的 resources/lang/vendor 目录,可以使用服务提供者的 publishes 方法。publishes 方法接受包路径及其所需发布位置的数组。例如,要发布 courier 包的翻译文件,可以执行以下操作:

php
/**
 * 启动任何应用程序服务。
 *
 * @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 方法中添加以下内容:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier');
}

包视图使用 package::view 语法约定引用。因此,一旦视图路径在服务提供者中注册,您可以像这样加载 courier 包的 admin 视图:

php
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 方法接受包视图路径及其所需发布位置的数组:

php
/**
 * 启动任何应用程序服务。
 *
 * @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 执行它们:

php
/**
 * 启动应用程序服务。
 *
 * @return void
 */
public function boot()
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            FooCommand::class,
            BarCommand::class,
        ]);
    }
}

公共资源

您的包可能有 JavaScript、CSS 和图像等资源。要将这些资源发布到应用程序的 public 目录,可以使用服务提供者的 publishes 方法。在此示例中,我们还将添加一个 public 资源组标签,可以用来发布相关资源组:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    $this->publishes([
        __DIR__.'/path/to/assets' => public_path('vendor/courier'),
    ], 'public');
}

现在,当您的包用户执行 vendor:publish 命令时,您的资源将被复制到指定的发布位置。由于通常需要在每次更新包时覆盖资源,可以使用 --force 标志:

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

发布文件组

您可能希望单独发布包资源和资源组。例如,您可能希望允许用户发布包的配置文件,而不必强制发布包的资源。可以通过在包的服务提供者的 publishes 方法中调用时对它们进行“标记”来实现。例如,让我们在包服务提供者的 boot 方法中使用标签定义两个发布组:

php
/**
 * 启动任何应用程序服务。
 *
 * @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
php artisan vendor:publish --tag=config