Dokumentation durchblättern
Module entwickeln
Das ServiceProvider-Muster
Der ServiceProvider ist der einzige Einstiegspunkt eines Moduls. Register- gegen Boot-Phase, Views und Übersetzungen laden, Einstellungen registrieren — mit Beispielen.
Jedes Modul hat genau einen ServiceProvider, der Illuminate\Support\ServiceProvider
erweitert. Er ist der einzige Einstiegspunkt, an dem das Modul alle seine Fähigkeiten
anmeldet. Alles, was ein Modul kann, beginnt hier.
Aufbau eines Modul-ServiceProviders
<?php
namespace Schneespur\Module\MyModule;
use Illuminate\Support\ServiceProvider;
class MyModuleServiceProvider extends ServiceProvider
{
public function register(): void
{
// Phase 1: Services in den Container binden.
// Andere Module/Provider sind evtl. noch nicht gebootet.
// Hier KEINE anderen Services auflösen.
}
public function boot(): void
{
// Phase 2: Alle Provider sind registriert.
// Jetzt ist es sicher, Registries aufzulösen und einzutragen.
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'my-module');
$this->registerNavigation();
$this->registerWidget();
$this->registerRoutes();
// … weitere Registrierungen
}
}
Register gegen Boot
Der Unterschied zwischen den beiden Phasen ist nicht kosmetisch — er entscheidet, ob Ihr Modul zuverlässig lädt:
| Phase | register() | boot() |
|---|---|---|
| Wann | bevor irgendein Provider gebootet ist | nachdem alle Provider registriert sind |
| Erlaubt | in den Container binden, Config mergen | Services auflösen, in Registries eintragen, Views/Routen laden |
| Nicht tun | andere Services oder Registries auflösen | in den Container binden (geht, verletzt aber die Konvention) |
Der Grund: In register() steht noch nicht fest, dass jeder andere Provider schon
registriert wurde. Wer dort eine Registry auflöst, riskiert, dass sie noch gar nicht
existiert. In boot() ist diese Garantie gegeben — deshalb gehören alle Registry-Einträge
dorthin.
Views laden
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'my-module');
Views werden danach als my-module::view-name referenziert:
return view('my-module::settings', ['data' => $data]);
Übersetzungen laden
Übersetzungen lädt der ModuleManager automatisch aus modules/{slug}/lang/. Sie sind als
{slug}::file.key namespaced:
// In lang/de/messages.php: return ['hello' => 'Hallo'];
__('example::messages.hello'); // → 'Hallo'
Sie müssen $this->loadTranslationsFrom() nicht selbst aufrufen — das erledigt der
ModuleManager.
Einstellungen registrieren
Mit ModuleManager::registerSettings() definieren Sie Standard-Einstellungen. Sie landen in
der Tabelle settings, jeweils mit dem Modul-Slug als Präfix:
protected function registerSettings(): void
{
app(ModuleManager::class)->registerSettings('my-module', [
'api_key' => '',
'enabled' => true,
'max_retries' => 3,
]);
}
Gespeichert wird als my-module.api_key, my-module.enabled usw. Der Typ wird automatisch
erkannt:
| PHP-Typ | gespeichert als |
|---|---|
string | 'string' |
bool | 'bool' |
int | 'int' |
array | 'json' |
Einstellungen lesen:
use App\Models\Setting;
$apiKey = Setting::get('my-module.api_key');
$enabled = Setting::get('my-module.enabled', false);
Einstellungen schreiben:
Setting::set('my-module.api_key', 'new-value');
Setting::set('my-module.enabled', true, 'bool');
Das Slug-Präfix ist auch der Grund, warum sich Einstellungen beim Entfernen eines Moduls
sauber aufräumen lassen — der ModuleManager löscht einfach alle Schlüssel, die mit
{slug}. beginnen.
Ein vollständiges Beispiel
Einen kompletten, lauffähigen ServiceProvider — mit Navigation, Dashboard-Widget, Routen,
Einstellungen und Übersetzungen — bauen Sie Schritt für Schritt im
Schnelleinstieg auf. Außerdem liegt der Anwendung ein
Referenzmodul unter modules/example/ bei, das die Erweiterungspunkte demonstriert — Abschnitt
für Abschnitt erklärt im Kapitel Beispielmodul.
Gängiges Muster: bedingtes Booten
Das Referenzmodul nutzt einen shouldBoot()-Wächter, um sich nur in der Entwicklung zu laden:
protected function shouldBoot(): bool
{
return (bool) env('EXAMPLE_MODULE_ENABLED', false);
}
Produktive Module sollten dieses Muster nicht verwenden — Aktivieren und Deaktivieren
läuft über die Modul-Verwaltung in der Oberfläche. Der shouldBoot()-Wächter ist
ausschließlich für das mitgelieferte Entwicklungs-Referenzmodul gedacht.
ServiceProvider-Checkliste
Ein Modul-ServiceProvider registriert typischerweise einige oder alle dieser Punkte (in
boot()):
- Views:
$this->loadViewsFrom() - Einstellungen:
ModuleManager::registerSettings() - Navigationspunkte:
NavigationRegistry::addItem() - Dashboard-Widgets:
DashboardWidgetRegistry::registerWidget() - Filter:
FilterRegistry::register() - Template-Slots:
SlotRegistry::append()/SlotRegistry::replace() - Event-Listener:
$this->app['events']->listen() - Benachrichtigungs-Kanäle:
NotificationChannelRegistry::register() - 2FA-Verfahren:
TwoFactorMethodRegistry::registerMethod() - Dispatch-Strategien:
DispatchStrategyRegistry::register() - Web-Routen:
Route::middleware(...)->group() - API-Routen:
ModuleApiRegistrar::routes() - Berechtigungen:
PermissionRegistry::registerPermission() - Rollen-Vorlagen:
RoleTemplateRegistry::registerTemplate() - geplante Aufgaben:
ScheduledTaskRegistry::register() - Backup-Ziele:
BackupTargetRegistry::register() - Speicher-Backends:
StorageBackendRegistry::register() - Diagnose-Reporter:
DiagnosticReporterRegistry::register()
Die genaue API jeder dieser Registries steht unter Registries.