Skip to content

软件包开发

介绍

包是向 Laravel 添加功能的主要方式。包可以是任何东西,从使用 Carbon 等日期的好方法,到允许您将文件与 Eloquent 模型关联的包,如 Spatie 的 Laravel Media Library

有不同类型的包。有些软件包是独立的,这意味着它们适用于任何 PHP 框架。Carbon 和 Pest 是独立软件包的示例。这些包中的任何一个都可以与 Laravel 一起使用,只需在您的 composer.json 文件中要求它们即可。

另一方面,其他软件包专门用于 Laravel。这些包可能具有专门用于增强 Laravel 应用程序的路由、控制器、视图和配置。本指南主要介绍特定于 Laravel 的包的开发。

关于Facades的说明

在编写 Laravel 应用程序时,使用 Contract 或 Facade 通常并不重要,因为两者都提供了基本相同级别的可测试性。但是,在编写包时,你的包通常无法访问 Laravel 的所有测试助手。如果你希望能够编写你的包测试,就好像包安装在典型的 Laravel 应用程序中一样,你可以使用 Orchestral Testbench 包。

包发现

Laravel 应用程序的 bootstrap/providers.php 文件包含应由 Laravel 加载的服务提供商列表。但是,您可以不需要用户手动将您的服务提供商添加到列表中,而是可以在软件包的 composer.json 文件的 extra 部分中定义提供商,以便 Laravel 自动加载它。除了服务提供商之外,您还可以列出您希望注册的任何facades:

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

一旦您的包被配置为发现,Laravel 将在安装时自动注册其服务提供商和外观,从而为您的包用户创建便捷的安装体验。

禁用软件包发现

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

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

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

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

服务提供商

服务提供商是您的软件包和 Laravel 之间的连接点。服务提供商负责将内容绑定到 Laravel 的服务容器中,并通知 Laravel 在何处加载包资源,例如视图、配置和语言文件。

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

资源

配置

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

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->publishes([
            __DIR__.'/../config/courier.php' => config_path('courier.php'),
        ]);
    }

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

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

WARNING

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

默认包配置

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

mergeConfigFrom 方法接受包的配置文件的路径作为其第一个参数,并将应用程序配置文件副本的名称作为其第二个参数:

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

WARNING

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

路由

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

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
    }

迁移

如果您的包包含数据库迁移,则可以使用 publishesMigrations 方法通知 Laravel 给定的目录或文件包含迁移。当 Laravel 发布迁移时,它将自动更新其文件名中的时间戳以反映当前日期和时间:

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->publishesMigrations([
            __DIR__.'/../database/migrations' => database_path('migrations'),
        ]);
    }

语言文件

如果你的包包含语言文件,你可以使用 loadTranslationsFrom 方法来通知 Laravel 如何加载它们。例如,如果您的软件包名为 courier,则应将以下内容添加到服务提供商的引导方法中:

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
    }

包翻译行使用 package::file.line 语法约定引用。因此,您可以从 messages 文件中加载 courier 包的欢迎行,如下所示:

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

您可以使用 loadJsonTranslationsFrom 方法为包注册 JSON 翻译文件。此方法接受包含包的 JSON 翻译文件的目录的路径:

php
/**
 * 引导任何包服务
 */
public function boot(): void
{
    $this->loadJsonTranslationsFrom(__DIR__.'/../lang');
}

发布语言文件

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

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');

        $this->publishes([
            __DIR__.'/../lang' => $this->app->langPath('vendor/courier'),
        ]);
    }

现在,当包的用户执行 Laravel 的 vendor:publish Artisan 命令时,包的语言文件将发布到指定的发布位置。

视图

要向 Laravel 注册包的视图,您需要告诉 Laravel 视图的位置。您可以使用服务提供商的 loadViewsFrom 方法执行此操作。loadViewsFrom 方法接受两个参数:视图模板的路径和包的名称。例如,如果您的软件包的名称是 courier,则可以将以下内容添加到服务提供商的引导方法中:

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
    }

Package 视图使用 package::view 语法约定引用。因此,在服务提供商中注册视图路径后,您可以从 courier 包中加载dashboard视图,如下所示:

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

覆盖包视图

当您使用 loadViewsFrom 方法时,Laravel 实际上会为您的视图注册两个位置:应用程序的 resources/views/vendor 目录和您指定的目录。所以,以 courier 包为例,Laravel 会首先检查开发者是否已经将自定义版本的 view 放在 resources/views/vendor/courier 目录中。然后,如果视图尚未自定义,Laravel 将搜索您在调用 loadViewsFrom 中指定的包视图目录。这使包用户可以轻松地自定义/覆盖包的视图。

发布视图

如果您想将视图发布到应用程序的 resources/views/vendor 目录,您可以使用服务提供商的 publishes 方法。publishes 方法接受一组包视图路径及其所需的发布位置:

/**
 * 引导软件包服务
 */
public function boot(): void
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');

    $this->publishes([
        __DIR__.'/../resources/views' => resource_path('views/vendor/courier'),
    ]);
}

现在,当您的包的用户执行 Laravel 的 vendor:publish Artisan 命令时,您的包的视图将被复制到指定的发布位置。

View 组件

如果您正在构建一个使用 Blade 组件的包或将组件放置在非常规目录中,则需要手动注册组件类及其 HTML 标签别名,以便 Laravel 知道在哪里可以找到组件。通常,您应该在软件包的服务提供商的 boot 方法中注册您的组件:

php
    use Illuminate\Support\Facades\Blade;
    use VendorPackage\View\Components\AlertComponent;

    /**
     * 引导您的软件包的服务
     */
    public function boot(): void
    {
        Blade::component('package-alert', AlertComponent::class);
    }

注册组件后,可以使用其标签别名进行渲染:

blade
<x-package-alert/>

自动加载包组件

或者,你可以按照约定使用 componentNamespace 方法来自动加载组件类。例如,Nightshade 包可能具有位于 Nightshade\Views\Components 命名空间中的 CalendarColorPicker 组件:

php
    use Illuminate\Support\Facades\Blade;

    /**
     * 引导您的软件包的服务
     */
    public function boot(): void
    {
        Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
    }

这将允许 vendor 命名空间使用 package-name:: 语法来使用包组件:

blade
<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade 将通过对组件名称进行 pascal 大小写来自动检测链接到此组件的类。子目录也支持使用 “dot” 表示法。

匿名组件

如果您的包包含匿名组件,则必须将它们放置在包的 “views” 目录的 components 目录中(由 loadViewsFrom 方法指定)。然后,你可以通过在组件名称前加上包的 view 命名空间来渲染它们:

blade
<x-courier::alert />

关于Artisan 命令

Laravel 内置的 about Artisan 命令提供了应用程序环境和配置的概要。包可以通过 AboutCommand 类将其他信息推送到此命令的输出中。通常,此信息可以从包服务提供商的启动方法中添加:

php
    use Illuminate\Foundation\Console\AboutCommand;

    /**
     * 引导任何应用程序服务
     */
    public function boot(): void
    {
        AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
    }

命令

要向 Laravel 注册包的 Artisan 命令,你可以使用 commands 方法。此方法需要一个命令类名称数组。注册命令后,您可以使用 Artisan CLI 执行它们:

php
    use Courier\Console\Commands\InstallCommand;
    use Courier\Console\Commands\NetworkCommand;

    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->commands([
                InstallCommand::class,
                NetworkCommand::class,
            ]);
        }
    }

发布静态资源

您的包可能包含 JavaScript、CSS 和图像等资产。要将这些资源发布到应用程序的 public 目录,请使用服务提供商的 publishes 方法。在这个例子中,我们还将添加一个公共资产组标签,该标签可以用来轻松发布相关资产的分组:

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->publishes([
            __DIR__.'/../public' => public_path('vendor/courier'),
        ], 'public');
    }

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

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

发布文件组

您可能希望单独发布包资源和资源组。例如,您可能希望允许用户发布包的配置文件,而无需强制发布包的资源。您可以通过在从包的服务提供商调用 publishes 方法时“标记”它们来实现此目的。例如,让我们使用标记在包的服务提供商的引导方法中为 courier 包定义两个发布组(courier-configcourier-migrations):

php
    /**
     * 引导任何包服务
     */
    public function boot(): void
    {
        $this->publishes([
            __DIR__.'/../config/package.php' => config_path('package.php')
        ], 'courier-config');

        $this->publishesMigrations([
            __DIR__.'/../database/migrations/' => database_path('migrations')
        ], 'courier-migrations');
    }

现在,您的用户可以在执行 vendor:publish 命令时通过引用他们的标签来单独发布这些组:

shell
php artisan vendor:publish --tag=courier-config