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.
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.
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éthode | Ce 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.
// 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.
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à.
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.