Skip to content

Plugins ​

Un plugin est la façon dont un paquet Composer ajoute des pages, des scripts, des feuilles de style, des textes et des routes à un panneau, sans que l'application ait à copier quoi que ce soit. L'application décide sur quels panneaux elle l'active. Disponible depuis la 1.2.

php
Panel::make('admin')
    ->plugins([BillingPlugin::make()])

Un même plugin ne peut pas être enregistré deux fois sur le même panneau : Arrel lève une exception.

Écrire un plugin ​

Un plugin étend Arrel\Plugins\Plugin. Seul id() est obligatoire ; les autres méthodes renvoient une liste vide si vous ne les redéfinissez pas.

php
use Arrel\Pages\CustomPage;
use Arrel\Plugins\Plugin;

final class BillingPlugin extends Plugin
{
    public static function make(): self
    {
        return new self;
    }

    public function id(): string
    {
        return 'billing';
    }

    public function customPages(): array
    {
        return [
            CustomPage::make('billing', __('billing::billing.navigation_label'))
                ->icon('credit-card')
                ->visible(fn (): bool => Gate::allows('billing.manage')),
        ];
    }

    public function scripts(): array
    {
        return [asset('vendor/billing/billing.js')];
    }

    public function stylesheets(): array
    {
        return [asset('vendor/billing/billing.css')];
    }

    public function translations(): array
    {
        return ['title' => __('billing::billing.title')];
    }
}
MéthodeCe qu'elle apporte
id()L'identifiant du plugin. Il préfixe ses textes et ses routes.
customPages()Des pages personnalisées, avec leur entrée de navigation.
scripts()Des scripts que le panneau charge après les siens.
stylesheets()Des feuilles de style que le panneau charge après les siennes.
translations()Des textes pour le frontend.

Le panneau lit ces méthodes chaque fois qu'il sert une page, pas au moment où le plugin est enregistré. C'est pourquoi l'ordre de plugins() et customPages() dans la définition du panneau n'a pas d'importance, et pourquoi __() renvoie déjà le texte dans la langue de l'utilisateur.

La page ​

Le script du plugin enregistre sa page comme le ferait l'application, en général avec registerMountablePage et sa propre instance de Vue. Si le paquet utilise le kit de composants d'Arrel, il l'intègre à son propre build.

Si vous construisez le script avec Vite en mode bibliothèque, définissez process.env.NODE_ENV. Vite ne le remplace pas dans ce mode et Vue le lit : sans le define, le script échoue au chargement et la page n'est jamais enregistrée.

js
// vite.config.js
export default defineConfig({
    define: {
        'process.env.NODE_ENV': JSON.stringify('production'),
    },
    build: {
        lib: { entry: 'resources/js/main.ts', formats: ['es'], fileName: () => 'billing.js' },
    },
})

Textes ​

Les textes de translations() arrivent dans window.Arrel.translations préfixés par l'identifiant du plugin. Ainsi, title d'un plugin billing devient billing.title, et ne remplace jamais un texte du panneau.

ts
const title = window.Arrel.translations?.['billing.title']

Les textes PHP (messages de validation, navigation) sont chargés par le paquet avec loadTranslationsFrom(), comme pour n'importe quel paquet Laravel. Arrel n'intervient pas.

Routes ​

ArrelRoutes::plugin() enregistre les routes du paquet derrière la même pile de middleware que l'API authentifiée d'Arrel, y compris arrel.middleware et arrel.authenticated_middleware. Si votre application identifie le tenant dans ce middleware, les routes du plugin l'ont déjà.

php
use Arrel\Http\ArrelRoutes;

ArrelRoutes::plugin('billing', function (): void {
    Route::get('/', [BillingController::class, 'context'])->name('context');
    Route::post('checkout', [BillingController::class, 'checkout'])->name('checkout');
});

Les routes se trouvent sous /arrel-plugins/{id} et sont nommées arrel.plugins.{id}.* : l'exemple sert GET /arrel-plugins/billing sous le nom arrel.plugins.billing.context.

Le préfixe est volontairement en dehors de /arrel/api et du préfixe du panneau. Les routes d'Arrel qui en dépendent capturent n'importe quel chemin, et l'ordre dans lequel Laravel démarre les paquets n'est pas garanti : une route enregistrée ensuite par un paquet serait masquée.

Comme pour tout endpoint qui vous est propre, autorisez chaque requête. Le fait que visible() masque l'entrée de navigation n'empêche pas quelqu'un d'appeler la route à la main.