diff --git a/architektur-patterns.md b/architektur-patterns.md index f36a1d0..46a3729 100644 --- a/architektur-patterns.md +++ b/architektur-patterns.md @@ -10,6 +10,52 @@ Das UseCase Pattern bildet das Herzstück der Business-Logik. Zusammen mit dem R - **Eingabe/Ausgabe**: Daten werden strikt über DTOs (Data Transfer Objects) ausgetauscht. - **Rückgabewert**: Ein UseCase gibt entweder ein Response-DTO zurück oder `void` (bei reinen Schreiboperationen). Die PHP-Signatur ist native typisiert, sodass zur Laufzeit keine `instanceof`-Prüfungen nötig sind. - **Fehlerbehandlung**: Business-Fehler werden über spezifische **Domain-Exceptions** signalisiert. +- **Dependency Limitation**: Ein UseCase sollte maximal 3–4 Dependencies injizieren. Ab 5+ Dependencies wird dringend empfohlen, einen **Orchestrator** einzusetzen. + +### Orchestrator Pattern (Optional für komplexe Koordination) +Wenn ein UseCase die Zuständigkeit mehrerer Domänen abdeckt (z. B. `Sales`, `Stock` und `Accounting` gleichzeitig), sollte er diese Manager nicht einzeln injizieren. + +- **Ort**: `src/Logic/{Module}/{Feature}/Orchestrator/` +- **Zweck**: Bündelt mehrere Manager zu einer einzigen fachlichen Operation (z. B. `OrderFulfillmentOrchestrator`). +- **Vorteil**: Reduziert den UseCase-Konstruktor auf eine einzige Abhängigkeit und isoliert komplexe Multi-Domain-Logik, was die Testbarkeit massiv verbessert. + +```php +// src/Logic/Sales/Order/Orchestrator/ +readonly class OrderFulfillmentOrchestrator +{ + public function __construct( + private OrderManagerInterface $orders, + private StockManagerInterface $stock, + private TransactionManagerInterface $transactions, + ) {} + + public function fulfillOrder(CreateOrderRequest $request): Order + { + return $this->transactions->execute(function() use ($request) { + if (!$this->stock->isSufficient($request->items)) { + throw new InsufficientStockException(); + } + // Business Model anlegen & persistieren + $order = new Order(/* ... */); + return $this->orders->create($order); + }); + } +} + +// Der UseCase profitiert von der schlanken Injektion: +readonly class CreateOrderUseCase { + public function __construct( + private OrderFulfillmentOrchestrator $orchestrator, + private EventDispatcherInterface $eventDispatcher, + ) {} + + public function execute(CreateOrderRequest $request): CreateOrderResponse { + $order = $this->orchestrator->fulfillOrder($request); + $this->eventDispatcher->dispatch(new OrderCreatedEvent(orderId: $order->id)); + return new CreateOrderResponse(orderId: $order->id); + } +} +``` ### DTOs (Data Transfer Objects) - **Typ**: Readonly-Klassen (PHP 8.2+).