翻译进度
8
分块数量
1
参与人数

扩展包开发

这是一篇协同翻译的文章,你可以点击『我来翻译』按钮来参与翻译。


Package Development

Introduction

Packages are the primary way of adding functionality to Laravel. Packages might be anything from a great way to work with dates like Carbon or a package that allows you to associate files with Eloquent models like Spatie's Laravel Media Library.

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.

On the other hand, other packages are specifically intended for use with Laravel. These packages may have routes, controllers, views, and configuration specifically intended to enhance a Laravel application. This guide primarily covers the development of those packages that are Laravel specific.

A Note on Facades

When writing a Laravel application, it generally does not matter if you use contracts or facades since both provide essentially equal levels of testability. However, when writing packages, your package will not typically have access to all of Laravel's testing helpers. If you would like to be able to write your package tests as if the package were installed inside a typical Laravel application, you may use the Orchestral Testbench package.

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:

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

Once your package has been configured for discovery, Laravel will automatically register its service providers and facades when it is installed, creating a convenient installation experience for your package's users.

Opting Out of Package Discovery

If you are the consumer of a package and would like to disable package discovery for a package, you may list the package name in the extra section of your application's composer.json file:

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

You may disable package discovery for all packages using the * character inside of your application's dont-discover directive:

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

Service Providers

Service providers are the connection point between your package and Laravel. A service provider is responsible for binding things into Laravel's service container and informing Laravel where to load package resources such as views, configuration, and language files.

A service provider extends the Illuminate\Support\ServiceProvider class and contains two methods: register and boot. The base ServiceProvider class is located in the illuminate/support Composer package, which you should add to your own package's dependencies. To learn more about the structure and purpose of service providers, check out their documentation.

资源

配置

通常情况下,你需要将包的配置文件发布到应用程序的 config 目录下。这将允许在使用包时覆盖扩展包中的默认配置选项。要允许发布配置文件,需要在服务提供者的 boot 方法中调用 publishes 方法:

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

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

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

警告
你不应该在你的配置文件中定义闭包。当用户执行 config:cache Artisan 命令时,它们不能被正确序列化。

默认的包配置

你也可以将你自己的包的配置文件与应用程序的发布副本合并。这将允许你的用户在配置文件的发布副本中只定义他们真正想要覆盖的选项。要合并配置文件的值,请在你的服务提供者的 register 方法中使用 mergeConfigFrom 方法。

mergeConfigFrom 方法的第一个参数是你的包的配置文件的路径,第二个参数是应用程序的配置文件副本的名称:

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

警告
这个方法只合并了配置数组的第一层。如果你的用户部分地定义了一个多维的配置数组,缺少的选项将不会被合并。

dkp 翻译于 28分钟前

Routes

If your package contains routes, you may load them using the loadRoutesFrom method. This method will automatically determine if the application's routes are cached and will not load your routes file if the routes have already been cached:

/**
 * Bootstrap any package services.
 */
public function boot(): void
{
    $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}

Migrations

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:

/**
 * Bootstrap any package services.
 */
public function boot(): void
{
    $this->publishesMigrations([
        __DIR__.'/../database/migrations' => database_path('migrations'),
    ]);
}

Language Files

If your package contains language files, you may use the loadTranslationsFrom method to inform Laravel how to load them. For example, if your package is named courier, you should add the following to your service provider's boot method:

/**
 * Bootstrap any package services.
 */
public function boot(): void
{
    $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
}

Package translation lines are referenced using the package::file.line syntax convention. So, you may load the courier package's welcome line from the messages file like so:

echo 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:

/**
 * Bootstrap any package services.
 */
public function boot(): void
{
    $this->loadJsonTranslationsFrom(__DIR__.'/../lang');
}

Publishing Language Files

If you would like to publish your package's language files to the application's lang/vendor directory, you may use the service provider's publishes method. The publishes method accepts an array of package paths and their desired publish locations. For example, to publish the language files for the courier package, you may do the following:

/**
 * Bootstrap any package services.
 */
public function boot(): void
{
    $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');

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

Now, when users of your package execute Laravel's vendor:publish Artisan command, your package's language files will be published to the specified publish location.

Views

To register your package's views with Laravel, you need to tell Laravel where the views are located. You may do this using the service provider's loadViewsFrom method. The loadViewsFrom method accepts two arguments: the path to your view templates and your package's name. For example, if your package's name is courier, you would add the following to your service provider's boot method:

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

Package views are referenced using the package::view syntax convention. So, once your view path is registered in a service provider, you may load the dashboard view from the courier package like so:

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

Overriding Package Views

When you use the loadViewsFrom method, Laravel actually registers two locations for your views: the application's resources/views/vendor directory and the directory you specify. So, using the courier package as an example, Laravel will first check if a custom version of the view has been placed in the resources/views/vendor/courier directory by the developer. Then, if the view has not been customized, Laravel will search the package view directory you specified in your call to loadViewsFrom. This makes it easy for package users to customize / override your package's views.

Publishing Views

If you would like to make your views available for publishing to the application's resources/views/vendor directory, you may use the service provider's publishes method. The publishes method accepts an array of package view paths and their desired publish locations:

/**
 * Bootstrap the package services.
 */
public function boot(): void
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');

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

Now, when users of your package execute Laravel's vendor:publish Artisan command, your package's views will be copied to the specified publish location.

View Components

If you are building a package that utilizes Blade components or placing components in non-conventional directories, you will need to manually register your component class and its HTML tag alias so that Laravel knows where to find the component. You should typically register your components in the boot method of your package's service provider:

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

/**
 * Bootstrap your package's services.
 */
public function boot(): void
{
    Blade::component('package-alert', AlertComponent::class);
}

Once your component has been registered, it may be rendered using its tag alias:

<x-package-alert/>

Autoloading Package Components

Alternatively, you may use the componentNamespace method to autoload component classes by convention. For example, a Nightshade package might have Calendar and ColorPicker components that reside within the Nightshade\Views\Components namespace:

use Illuminate\Support\Facades\Blade;

/**
 * Bootstrap your package's services.
 */
public function boot(): void
{
    Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

This will allow the usage of package components by their vendor namespace using the package-name:: syntax:

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

Blade will automatically detect the class that's linked to this component by pascal-casing the component name. Subdirectories are also supported using "dot" notation.

Anonymous Components

If your package contains anonymous components, they must be placed within a components directory of your package's "views" directory (as specified by the loadViewsFrom method). Then, you may render them by prefixing the component name with the package's view namespace:

<x-courier::alert />

"About" Artisan Command

Laravel's built-in about Artisan command provides a synopsis of the application's environment and configuration. Packages may push additional information to this command's output via the AboutCommand class. Typically, this information may be added from your package service provider's boot method:

use Illuminate\Foundation\Console\AboutCommand;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
}

Commands

To register your package's Artisan commands with Laravel, you may use the commands method. This method expects an array of command class names. Once the commands have been registered, you may execute them using the Artisan CLI:

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

/**
 * Bootstrap any package services.
 */
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            InstallCommand::class,
            NetworkCommand::class,
        ]);
    }
}

Optimize Commands

Laravel's optimize command caches the application's configuration, events, routes, and views. Using the optimizes method, you may register your package's own Artisan commands that should be invoked when the optimize and optimize:clear commands are executed:

/**
 * Bootstrap any package services.
 */
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->optimizes(
            optimize: 'package:optimize',
            clear: 'package:clear-optimizations',
        );
    }
}

公共资源

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

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

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

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

发布文件组

你可能想要分别发布包资源和资源组。例如,你可能希望允许用户发布包的配置文件而不强迫发布包的资源。当从包的服务提供者调用 publishes 方法时,你可以通过「tagging」它们来实现这一点。例如,让我们在包服务提供者的 boot 方法中使用标签为 courier 包定义两个发布组(courier-configcourier-migrations):

/**
 * 引导包服务
 */
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 命令时引用其标签,分别发布这些组:

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

你的用户还可以使用 --provider 标志发布包服务提供商定义的所有可发布文件:

php artisan vendor:publish --provider="Your\Package\ServiceProvider"
dkp 翻译于 23分钟前

本文章首发在 LearnKu.com 网站上。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
贡献者:1
讨论数量: 0
发起讨论 查看所有版本


暂无话题~