Пакет живе в чужому застосунку. Що менше він нав'язує, то легше його встановити, налаштувати й замінити.
Залежності в коді пакета - через інтерфейси й контейнер:
namespace Acme\Invoices\Contracts;
interface PdfRenderer
{
public function render(string $html): string;
}
// InvoicesServiceProvider::register()
$this->app->singleton(PdfRenderer::class, fn ($app) => new DompdfRenderer(
$app['config']->get('invoices.pdf'),
));
$this->app->singleton(InvoiceGenerator::class);
final class InvoiceGenerator
{
public function __construct(
private PdfRenderer $renderer,
private Filesystem $files, // Illuminate\Contracts\Filesystem\Filesystem
) {}
}
Застосунок замінює реалізацію одним рядком у своєму провайдері - без форку пакета:
$this->app->singleton(PdfRenderer::class, BrowsershotRenderer::class);
Фасади:
- фасад - зручність для користувача, а не спосіб писати внутрішній код пакета. Усередині пакета краще впровадження залежностей: код тестується без фасадів і не залежить від глобального стану;
- фасад пакета вказує на прив'язку в контейнері (
getFacadeAccessorповертає клас чи ключ), тож заміна реалізації працює й для нього; - реєструвати аліас через
extra.laravel.aliases- необов'язково: багато користувачів імпортують клас фасаду напряму.
Необов'язкові залежності:
"require": { "illuminate/support": "^12.0|^13.0" },
"suggest": { "spatie/browsershot": "Для рендерингу PDF через Chrome" }
if (! class_exists(\Spatie\Browsershot\Browsershot::class)) {
throw new MissingDependency('Install spatie/browsershot to use the browsershot driver.');
}
Важка залежність (headless Chrome, SDK хмари) не має ставитися всім, кому потрібна лише частина пакета.
Моделі застосунку:
- не імпортувати
App\Models\User- модель береться з конфігурації:config('invoices.user_model', config('auth.providers.users.model')); - власні моделі пакета дозволяти розширювати:
config('invoices.models.invoice')і використовувати їх через цей ключ.
Події замість жорстких викликів: InvoicePaid дозволяє застосунку реагувати (лист, вебхук, бухгалтерія), не змінюючи код пакета.
Ознака добре спроєктованого пакета: його можна використовувати без фасадів, без публікації файлів і з власною реалізацією кожної зовнішньої залежності.