Files
michaelschiemer/docs/framework/ERWEITERUNGSPATTERN.md

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:

  1. Event-Listener für reaktive Erweiterungen
  2. Middleware für HTTP-Anfrageverarbeitung
  3. Service-Initializer zum Ersetzen oder Dekorieren von Services
  4. Plugins für umfassendere Funktionalitätserweiterungen
  5. 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.