Розробка Пакетів

Вступ

Пакети є основним способом додавання функціональності до Laravel. Пакети можуть бути чим завгодно, від чудового способу роботи з датами, як-от Carbon, до пакета, який дозволяє асоціювати файли з моделями Eloquent, як-от Spatie's Laravel Media Library.

Існують різні типи пакетів. Деякі пакети є автономними, тобто вони працюють з будь-яким PHP фреймворком. Carbon і Pest є прикладами автономних пакетів. Будь-який з цих пакетів може бути використаний з Laravel, якщо додати їх у ваш файл composer.json.

З іншого боку, інші пакети спеціально призначені для використання з Laravel. Ці пакети можуть мати маршрути, контролери, представлення та конфігурацію, спеціально призначені для покращення застосунку Laravel. Цей посібник в основному охоплює розробку тих пакетів, які є специфічними для Laravel.

Примітка щодо фасадів

Коли ви пишете застосунок Laravel, зазвичай не має значення, чи використовуєте ви контракти або фасади, оскільки обидва забезпечують практично однаковий рівень тестованості. Однак, при написанні пакетів, ваш пакет зазвичай не матиме доступу до всіх тестових хелперів Laravel. Якщо ви хочете мати можливість писати тести для вашого пакета так, ніби пакет встановлено всередині типового застосунку Laravel, ви можете використовувати пакет Orchestral Testbench.

Виявлення пакетів

Файл bootstrap/providers.php Laravel-застосунку містить список сервіс-провайдерів, які повинні бути завантажені Laravel. Однак, замість того щоб вимагати від користувачів вручну додавати ваш сервіс-провайдер до списку, ви можете визначити провайдер у секції extra файлу composer.json вашого пакету, щоб він автоматично завантажувався Laravel. На додаток до сервіс-провайдерів, ви також можете вказати будь-які фасади, які ви хотіли б зареєструвати:

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

Як тільки ваш пакет налаштовано для виявлення, Laravel автоматично зареєструє його Сервіс-провайдери та фасади під час встановлення, створюючи зручний досвід встановлення для користувачів вашого пакета.

Відмова від автоматичного виявлення пакетів

Якщо ви є споживачем пакета і хочете вимкнути автоматичне виявлення пакета, ви можете вказати назву пакета в розділі extra файлу composer.json вашого застосунку:

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

Ви можете вимкнути виявлення пакетів для всіх пакетів, використовуючи символ * всередині директиви dont-discover вашого застосунку:

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

Сервіс-провайдери

Сервіс-провайдери є точкою з'єднання між вашим пакетом і Laravel. Сервіс-провайдер відповідає за зв'язування речей у сервіс-контейнер Laravel та інформування Laravel, де завантажувати ресурси пакета, такі як представлення, конфігураційні та мовні файли.

Сервіс-провайдер розширює клас Illuminate\Support\ServiceProvider і містить два методи: register та boot. Базовий клас ServiceProvider знаходиться в пакеті illuminate/support компонувальника, який ви повинні додати до залежностей вашого власного пакета. Щоб дізнатися більше про структуру та призначення сервіс-провайдерів, перегляньте їх документацію.

Ресурси

Конфігурація

Зазвичай, вам потрібно опублікувати файл конфігурації вашого пакета в директорію config застосунку. Це дозволить користувачам вашого пакета легко перевизначати ваші параметри конфігурації за замовчуванням. Щоб дозволити публікацію ваших конфігураційних файлів, викличте метод publishes з методу boot вашого сервіс-провайдера:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/courier.php' => config_path('courier.php'),
]);
}

Тепер, коли користувачі вашого пакету виконують команду Laravel vendor:publish, ваш файл буде скопійовано до вказаного місця публікації. Після того як ваша конфігурація буде опублікована, її значення можуть бути доступні, як і будь-який інший конфігураційний файл:

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

Ви не повинні визначати замикання у ваших конфігураційних файлах. Вони не можуть бути серіалізовані правильно, коли користувачі виконують команду Artisan config:cache.

Конфігурація Пакету За Замовчуванням

Ви також можете об'єднати власний файл конфігурації пакета з опублікованою копією конфігурації застосунку. Це дозволить вашим користувачам визначати лише ті параметри, які вони дійсно хочуть перевизначити в опублікованій копії файлу конфігурації. Щоб об'єднати значення файлу конфігурації, використовуйте метод mergeConfigFrom у методі register вашого сервіс-провайдера.

Метод mergeConfigFrom приймає шлях до файлу конфігурації вашого пакета як свій перший аргумент і назву копії файлу конфігурації застосунку як свій другий аргумент:

/**
* Зареєструвати будь-які сервіси застосунку.
*/
public function register(): void
{
$this->mergeConfigFrom(
__DIR__.'/../config/courier.php', 'courier'
);
}

Цей метод об'єднує лише перший рівень масиву конфігурації. Якщо ваші користувачі частково визначають багатовимірний масив конфігурації, відсутні параметри не будуть об'єднані.

Маршрути

Якщо ваш пакет містить маршрути, ви можете завантажити їх за допомогою методу loadRoutesFrom. Цей метод автоматично визначить, чи маршрути застосунку кешовані, і не завантажуватиме ваш файл маршрутів, якщо маршрути вже були кешовані:

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

Міграції

Якщо ваш пакет містить міграції бази даних, ви можете використовувати метод publishesMigrations, щоб повідомити Laravel, що вказаний каталог або файл містить міграції. Коли Laravel публікує міграції, він автоматично оновлює часову мітку у їхньому імені файлу, щоб відобразити поточну дату та час:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
public function boot(): void
{
$this->publishesMigrations([
__DIR__.'/../database/migrations' => database_path('migrations'),
]);
}

Файли мови

Якщо ваш пакет містить файли локалізації, ви можете використовувати метод loadTranslationsFrom, щоб повідомити Laravel, як їх завантажувати. Наприклад, якщо ваш пакет називається courier, ви повинні додати наступне до методу boot вашого Сервіс-провайдера:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
}

Рядки перекладу пакету посилаються за допомогою синтаксису package::file.line. Отже, ви можете завантажити рядок welcome з файлу messages пакету courier таким чином:

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

Ви можете зареєструвати JSON файли перекладу для вашого пакета, використовуючи метод loadJsonTranslationsFrom. Цей метод приймає шлях до каталогу, що містить JSON файли перекладу вашого пакета:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
public function boot(): void
{
$this->loadJsonTranslationsFrom(__DIR__.'/../lang');
}

Публікація мовних файлів

Якщо ви хочете опублікувати мовні файли вашого пакета в директорію lang/vendor вашого застосунку, ви можете скористатися методом publishes сервіс-провайдера. Метод publishes приймає масив шляхів пакета та їх бажані місця публікації. Наприклад, щоб опублікувати мовні файли для пакета courier, ви можете зробити наступне:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
 
$this->publishes([
__DIR__.'/../lang' => $this->app->langPath('vendor/courier'),
]);
}

Тепер, коли користувачі вашого пакету виконують Artisan команду Laravel vendor:publish, мовні файли вашого пакету будуть опубліковані в зазначеному місці публікації.

Представлення

Щоб зареєструвати представлення вашого пакета в Laravel, вам потрібно вказати Laravel, де знаходяться представлення. Ви можете зробити це за допомогою методу loadViewsFrom сервіс-провайдера. Метод loadViewsFrom приймає два аргументи: шлях до ваших шаблонів представлення та ім'я вашого пакета. Наприклад, якщо ім'я вашого пакета courier, ви повинні додати наступне до методу boot вашого сервіс-провайдера:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
}

Пакетні представлення посилаються, використовуючи синтаксис package::view. Отже, як тільки шлях до вашого представлення зареєстровано в сервіс-провайдері, ви можете завантажити представлення dashboard з пакету courier таким чином:

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

Перевизначення Представлень Пакету

Коли ви використовуєте метод loadViewsFrom, Laravel фактично реєструє два місця для ваших представлень: каталог resources/views/vendor вашого застосунку та каталог, який ви вказуєте. Отже, використовуючи пакет courier як приклад, Laravel спочатку перевірить, чи була розміщена користувацька версія представлення в каталозі 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'),
]);
}

Тепер, коли користувачі вашого пакету виконують Artisan команду Laravel vendor:publish, представлення вашого пакету будуть скопійовані до вказаного місця публікації.

Компоненти Представлення

Якщо ви створюєте пакет, що використовує 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/>

Автозавантаження Компонентів Пакету

Альтернативно, ви можете використовувати метод componentNamespace для автозавантаження класів компонентів за конвенцією. Наприклад, пакет Nightshade може мати компоненти Calendar та ColorPicker, які знаходяться в просторі імен Nightshade\Views\Components:

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 автоматично визначить клас, пов'язаний з цим компонентом, перетворивши ім'я компонента у формат PascalCase. Підкаталоги також підтримуються за допомогою нотації "крапка".

Анонімні Компоненти

Якщо ваш пакет містить анонімні компоненти, вони повинні бути розміщені в каталозі components каталогу "представлень" вашого пакета (як зазначено методом loadViewsFrom). Потім ви можете відобразити їх, додавши до імені компонента префікс простору імен представлення пакета:

<x-courier::alert />

Artisan Команда "Про"

Вбудована команда Artisan about у Laravel надає короткий огляд середовища та конфігурації застосунку. Пакети можуть додавати додаткову інформацію до виводу цієї команди через клас AboutCommand. Зазвичай, ця інформація може бути додана з методу boot вашого сервіс-провайдера пакету:

use Illuminate\Foundation\Console\AboutCommand;
 
/**
* Зареєструвати будь-які сервіси застосунку.
*/
public function boot(): void
{
AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
}

Команди

Щоб зареєструвати Artisan-команди вашого пакету в Laravel, ви можете використовувати метод 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,
]);
}
}

Оптимізувати Команди

Laravel's команда optimize кешує конфігурацію, події, маршрути та представлення застосунку. Використовуючи метод optimizes, ви можете зареєструвати власні Artisan-команди вашого пакету, які повинні викликатися при виконанні команд optimize та optimize:clear:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
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 з сервіс-провайдера пакета. Наприклад, давайте використаємо теги для визначення двох груп публікації для пакета courier (courier-config і courier-migrations) у методі boot сервіс-провайдера пакета:

/**
* Ініціалізувати будь-які сервіси пакета.
*/
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"