LaravelDocs(中文)

套件 (Packages)

開發 Laravel 套件的指南

簡介 (Introduction)

套件是為 Laravel 新增功能的主要方式。套件可以是任何東西,從像 Carbon 這樣處理日期的好方法,到像 Spatie 的 Laravel Media Library 這樣允許你將檔案與 Eloquent 模型關聯的套件。

有不同類型的套件。有些套件是獨立的,這意味著它們可以與任何 PHP 框架一起使用。Carbon 和 Pest 是獨立套件的例子。任何這些套件都可以透過在你的 composer.json 檔案中引入它們來與 Laravel 一起使用。

另一方面,其他套件是專門為與 Laravel 一起使用而設計的。這些套件可能具有專門用於增強 Laravel 應用程式的路由、控制器、視圖和設定。本指南主要涵蓋那些特定於 Laravel 的套件的開發。

關於 Facades 的說明 (A Note on Facades)

在編寫 Laravel 應用程式時,使用 contracts 還是 facades 通常並不重要,因為兩者本質上都提供了同等水平的可測試性。但是,在編寫套件時,你的套件通常無法存取所有 Laravel 的測試輔助函式。如果你希望能夠像在典型的 Laravel 應用程式中安裝套件一樣編寫套件測試,你可以使用 Orchestral Testbench 套件。

套件發現 (Package Discovery)

Laravel 應用程式的 bootstrap/providers.php 檔案包含 Laravel 應該載入的服務提供者列表。但是,你可以不在要求使用者手動將你的服務提供者新增到列表中,而是在套件的 composer.json 檔案的 extra 部分定義提供者,以便 Laravel 自動載入它。除了服務提供者之外,你還可以列出任何你想要註冊的 facades

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

一旦你的套件被設定為發現,Laravel 將在安裝時自動註冊其服務提供者和 facades,為你的套件使用者創造便利的安裝體驗。

退出套件發現 (Opting Out Of Package Discovery)

如果你是套件的消費者,並且想要停用套件的套件發現,你可以在應用程式的 composer.json 檔案的 extra 部分列出套件名稱:

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

你可以使用應用程式 dont-discover 指令中的 * 字元停用所有套件的套件發現:

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

服務提供者 (Service Providers)

服務提供者是你的套件與 Laravel 之間的連接點。服務提供者負責將事物綁定到 Laravel 的 service container 中,並通知 Laravel 在哪裡載入套件資源,如視圖、設定和語言檔案。

服務提供者繼承了 Illuminate\Support\ServiceProvider 類別,並包含兩個方法:registerboot。基礎 ServiceProvider 類別位於 illuminate/support Composer 套件中,你應該將其新增到你自己的套件依賴中。要了解更多關於服務提供者的結構和用途,請查看他們的文檔

資源 (Resources)

設定 (Configuration)

通常,你需要將套件的設定檔案發布到應用程式的 config 目錄。這將允許你的套件使用者輕鬆覆蓋你的預設設定選項。要允許發布你的設定檔案,請從服務提供者的 boot 方法呼叫 publishes 方法:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    $this->publishes([
        __DIR__.'/../config/courier.php' => config_path('courier.php'),
    ]);
}

現在,當你的套件使用者執行 Laravel 的 vendor:publish 命令時,你的檔案將被複製到指定的發布位置。一旦你的設定被發布,它的值就可以像任何其他設定檔案一樣被存取:

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

[!WARNING] 你不應該在設定檔案中定義閉包。當使用者執行 config:cache Artisan 命令時,它們無法被正確序列化。

預設套件設定 (Default Package Configuration)

你也可以將你自己的套件設定檔案與應用程式的發布副本合併。這將允許你的使用者僅定義他們實際想要在設定檔案的發布副本中覆蓋的選項。要合併設定檔案值,請在服務提供者的 register 方法中使用 mergeConfigFrom 方法。

mergeConfigFrom 方法接受你的套件設定檔案的路徑作為第一個參數,以及應用程式設定檔案副本的名稱作為第二個參數:

/**
 * 註冊任何套件服務。
 */
public function register(): void
{
    $this->mergeConfigFrom(
        __DIR__.'/../config/courier.php', 'courier'
    );
}

[!WARNING] 此方法僅合併設定陣列的第一層。如果你的使用者部分定義了多維設定陣列,則缺少的選項將不會被合併。

路由 (Routes)

如果你的套件包含路由,你可以使用 loadRoutesFrom 方法載入它們。此方法將自動判斷應用程式的路由是否已被快取,如果路由已被快取,則不會載入你的路由檔案:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}

Migrations (Migrations)

如果你的套件包含 database migrations,你可以使用 publishesMigrations 方法通知 Laravel 給定的目錄或檔案包含 migrations。當 Laravel 發布 migrations 時,它會自動更新其檔案名稱中的時間戳記以反映當前的日期和時間:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    $this->publishesMigrations([
        __DIR__.'/../database/migrations' => database_path('migrations'),
    ]);
}

語言檔案 (Language Files)

如果你的套件包含語言檔案,你可以使用 loadTranslationsFrom 方法通知 Laravel 如何載入它們。例如,如果你的套件名為 courier,你應該將以下內容新增到你的服務提供者的 boot 方法中:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
}

套件翻譯行使用 package::file.line 語法慣例引用。因此,你可以像這樣從 messages 檔案載入 courier 套件的 welcome 行:

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

你可以使用 loadJsonTranslationsFrom 方法為你的套件註冊 JSON 翻譯檔案。此方法接受包含你的套件 JSON 翻譯檔案的目錄路徑:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    $this->loadJsonTranslationsFrom(__DIR__.'/../lang');
}

發布語言檔案 (Publishing Language Files)

如果你想將套件的語言檔案發布到應用程式的 lang/vendor 目錄,你可以使用服務提供者的 publishes 方法。publishes 方法接受一個包含套件路徑及其所需發布位置的陣列。例如,要為 courier 套件發布語言檔案,你可以執行以下操作:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');

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

現在,當你的套件使用者執行 Laravel 的 vendor:publish Artisan 命令時,你的套件語言檔案將被發布到指定的發布位置。

視圖 (Views)

要向 Laravel 註冊你的套件視圖,你需要告訴 Laravel 視圖位於何處。你可以使用服務提供者的 loadViewsFrom 方法來執行此操作。loadViewsFrom 方法接受兩個參數:你的視圖模板的路徑和你的套件名稱。例如,如果你的套件名稱是 courier,你會將以下內容新增到你的服務提供者的 boot 方法中:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
}

套件視圖使用 package::view 語法慣例引用。因此,一旦你的視圖路徑在服務提供者中註冊,你就可以像這樣從 courier 套件載入 dashboard 視圖:

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

覆蓋套件視圖 (Overriding Package Views)

當你使用 loadViewsFrom 方法時,Laravel 實際上為你的視圖註冊了兩個位置:應用程式的 resources/views/vendor 目錄和你指定的目錄。因此,以 courier 套件為例,Laravel 將首先檢查開發人員是否已將自訂版本的視圖放置在 resources/views/vendor/courier 目錄中。然後,如果視圖未被自訂,Laravel 將搜尋你在呼叫 loadViewsFrom 時指定的套件視圖目錄。這使得套件使用者可以輕鬆自訂/覆蓋你的套件視圖。

發布視圖 (Publishing Views)

如果你想讓你的視圖可用於發布到應用程式的 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 Components (View Components)

如果你正在建立一個使用 Blade 元件或將元件放置在非傳統目錄中的套件,你需要手動註冊你的元件類別及其 HTML 標籤別名,以便 Laravel 知道在哪裡找到該元件。你通常應該在套件服務提供者的 boot 方法中註冊你的元件:

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

/**
 * 啟動你的套件服務。
 */
public function boot(): void
{
    Blade::component('package-alert', AlertComponent::class);
}

一旦你的元件被註冊,它就可以使用其標籤別名進行渲染:

<x-package-alert/>

自動載入套件元件 (Autoloading Package Components)

或者,你可以使用 componentNamespace 方法按慣例自動載入元件類別。例如,Nightshade 套件可能有位於 Nightshade\Views\Components 命名空間內的 CalendarColorPicker 元件:

use Illuminate\Support\Facades\Blade;

/**
 * 啟動你的套件服務。
 */
public function boot(): void
{
    Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

這將允許使用 package-name:: 語法透過其供應商命名空間使用套件元件:

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

Blade 將透過將元件名稱轉換為 Pascal 大小寫來自動檢測連結到此元件的類別。使用「點」表示法也支援子目錄。

匿名元件 (Anonymous Components)

如果你的套件包含匿名元件,它們必須放置在套件「視圖」目錄的 components 目錄中(如 loadViewsFrom 方法所指定)。然後,你可以透過在元件名稱前加上套件的視圖命名空間來渲染它們:

<x-courier::alert />

"About" Artisan Command ("About" Artisan Command)

Laravel 內建的 about Artisan 命令提供了應用程式環境和設定的概要。套件可以透過 AboutCommand 類別將額外資訊推送到此命令的輸出。通常,此資訊可以從你的套件服務提供者的 boot 方法中新增:

use Illuminate\Foundation\Console\AboutCommand;

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
}

命令 (Commands)

要向 Laravel 註冊你的套件 Artisan 命令,你可以使用 commands 方法。此方法需要一個命令類別名稱的陣列。一旦命令被註冊,你就可以使用 Artisan CLI 執行它們:

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

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            InstallCommand::class,
            NetworkCommand::class,
        ]);
    }
}

最佳化命令 (Optimize Commands)

Laravel 的 optimize command 快取應用程式的設定、事件、路由和視圖。使用 optimizes 方法,你可以註冊你的套件自己的 Artisan 命令,這些命令應該在執行 optimizeoptimize:clear 命令時被呼叫:

/**
 * 啟動任何套件服務。
 */
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->optimizes(
            optimize: 'package:optimize',
            clear: 'package:clear-optimizations',
        );
    }
}

公開資源 (Public Assets)

你的套件可能有 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

發布檔案群組 (Publishing File Groups)

你可能想要分開發布套件資源群組。例如,你可能想要允許你的使用者發布你的套件設定檔案,而不被強制發布你的套件資源。你可以透過在從套件的服務提供者呼叫 publishes 方法時「標記」它們來做到這一點。例如,讓我們在套件服務提供者的 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"