- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
4.8 KiB
4.8 KiB
Erweiterungsmuster im Framework
Übersicht
Dieses Dokument beschreibt die verschiedenen Muster und Techniken, um das Framework zu erweitern oder anzupassen, ohne den Kern-Code zu verändern.
Event-basierte Erweiterungen
Event-Listener
Die primäre Methode zur Erweiterung des Frameworks ist das Lauschen auf System-Events:
// Event-Listener registrieren
public function __construct(private readonly EventDispatcher $eventDispatcher)
{
$this->eventDispatcher->addHandler(
'App\Framework\Core\Events\ApplicationBooted',
[$this, 'onApplicationBooted']
);
}
// Event-Handler-Methode
public function onApplicationBooted(ApplicationBooted $event): void
{
// Erweiterungslogik implementieren
}
Eigene Events
Benutzerdefinierte Events erstellen:
final readonly class UserRegistered
{
public function __construct(
public string $userId,
public string $email,
public \DateTimeImmutable $timestamp
) {}
}
// Event auslösen
$this->eventDispatcher->dispatch(new UserRegistered(
$user->getId(),
$user->getEmail(),
new \DateTimeImmutable()
));
Middleware
HTTP-Anfragen können durch Middleware-Klassen erweitert werden:
final readonly class CustomMiddleware implements Middleware
{
public function process(Request $request, callable $next): Response
{
// Vor der Anfrageverarbeitung
$modifiedRequest = $this->modifyRequest($request);
// Anfrage weiterleiten
$response = $next($modifiedRequest);
// Nach der Anfrageverarbeitung
return $this->modifyResponse($response);
}
}
// Middleware registrieren
$app->addMiddleware(CustomMiddleware::class);
Service-Erweiterungen
Service-Ersetzen
Standardimplementierungen durch eigene ersetzen:
#[Initializer]
final readonly class CustomStorageInitializer
{
public function __invoke(Container $container): StorageInterface
{
return new CustomStorage();
}
}
Service-Decorator
Bestehende Services erweitern ohne Änderung der Original-Implementierung:
#[Initializer]
final readonly class LoggingAnalyticsInitializer
{
public function __construct(
private readonly Configuration $config,
private readonly LoggerInterface $logger
) {}
public function __invoke(Container $container): Analytics
{
// Original-Analytics-Service erstellen
$originalAnalytics = new Analytics(
new AnalyticsManager($this->config->get('analytics'), new FileStorage($path)),
$container->get(EventDispatcher::class)
);
// Mit Logging-Decorator umhüllen
return new LoggingAnalyticsDecorator($originalAnalytics, $this->logger);
}
}
// Decorator-Implementierung
final readonly class LoggingAnalyticsDecorator implements AnalyticsInterface
{
public function __construct(
private Analytics $analytics,
private LoggerInterface $logger
) {}
public function track(string $event, array $properties = [], ?string $userId = null): void
{
$this->logger->debug("Tracking event: {$event}", [
'properties' => $properties,
'user_id' => $userId
]);
$this->analytics->track($event, $properties, $userId);
}
// Andere Methoden implementieren
}
Plugin-System
Plugin-Interface
interface PluginInterface
{
public function register(Application $app): void;
public function boot(Application $app): void;
}
// Plugin-Implementierung
final readonly class CustomPlugin implements PluginInterface
{
public function register(Application $app): void
{
// Services registrieren
}
public function boot(Application $app): void
{
// Nach Initialisierung der Anwendung
}
}
// Plugin registrieren
$app->registerPlugin(new CustomPlugin());
Konfigurationserweiterungen
Konfigurationsquellen
Benutzerdefinierte Konfigurationsquellen implementieren:
final readonly class EnvironmentConfigSource implements ConfigSourceInterface
{
public function load(string $key, mixed $default = null): mixed
{
$envKey = strtoupper(str_replace('.', '_', $key));
return $_ENV[$envKey] ?? $default;
}
}
// Konfigurationsquelle registrieren
$config->addSource(new EnvironmentConfigSource());
Zusammenfassung
Die bevorzugten Erweiterungsmuster sind:
- Event-Listener für reaktive Erweiterungen
- Middleware für HTTP-Anfrageverarbeitung
- Service-Initializer zum Ersetzen oder Dekorieren von Services
- Plugins für umfassendere Funktionalitätserweiterungen
- Konfigurationsquellen für benutzerdefinierte Konfigurationen
Diese Muster ermöglichen es, das Framework zu erweitern, ohne den Kern zu modifizieren, was zu einer besseren Wartbarkeit und einfacheren Updates führt.