docs: document full and partial update patterns for readonly Models
This commit is contained in:
+76
-2
@@ -594,7 +594,10 @@ Um die UseCases schlank zu halten, findet die Transformation von Eingabe-DTOs (`
|
||||
|
||||
- **Ort**: `src/Logic/{Module}/{Feature}/Mapping/`
|
||||
- **Verantwortung**: Abbildung der Struktur von einem DTO auf ein Business Model (einschließlich Child-Models).
|
||||
- **Dependency Rule**: Diese Mappers liegen zwingend in der Logic Layer und kennen keine Entitys oder Provider.
|
||||
- **Dependency Rule**: Diese Mapper liegen zwingend in der Logic Layer und kennen keine Entities oder Provider.
|
||||
|
||||
#### Factory-Pattern (Create-Szenario)
|
||||
Für neue Objekte liefert die Factory ein komplett neues, valides Business-Model.
|
||||
|
||||
```php
|
||||
namespace App\Logic\Sales\Order\Mapping;
|
||||
@@ -610,7 +613,7 @@ readonly class OrderModelFactory
|
||||
{
|
||||
return new Order(
|
||||
customerId: $request->customerId,
|
||||
// Delegierung der Child-Objekte
|
||||
// Delegierung der Child-Objects
|
||||
items: array_map(
|
||||
fn($data) => new OrderItem(productId: $data['productId'], quantity: $data['quantity']),
|
||||
$request->items
|
||||
@@ -621,6 +624,77 @@ readonly class OrderModelFactory
|
||||
}
|
||||
```
|
||||
|
||||
#### Factory-Pattern für Updates (Full Rebuild)
|
||||
Das einfachste Verfahren. Die Factory erhält den Request-DTO und erstellt wie gewohnt ein neues Model mit allen Daten des Requests — inklusive der ID des bestehenden Objekts. Da Models im Logic Layer rein funktional sind, ist das Erstellen eines neuen Modells billiger als ein Objekt zu kopieren und zu manipulieren.
|
||||
|
||||
```php
|
||||
namespace App\Logic\Sales\Order\Mapping;
|
||||
|
||||
use App\Logic\Sales\Order\Dto\UpdateOrderRequest; // Enthält id:, email:, amount: ...
|
||||
use App\Logic\Sales\Order\Model\Order;
|
||||
|
||||
readonly class OrderModelFactory
|
||||
{
|
||||
public function updateFromRequest(UpdateOrderRequest $request): Order
|
||||
{
|
||||
return new Order(
|
||||
id: $request->id, // ID aus dem Request übernehmen
|
||||
customerEmail: $request->customerEmail ?? null,
|
||||
totalAmount: $request->totalAmount,
|
||||
// ... restliche Felder (bei Partial Updates ggf. per Provider ergänzt)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Kopier-Pattern für Partial-Updates (Model.copyWith)
|
||||
Wenn nur bestimmte Felder eines bestehenden Business-Models geändert werden sollen, empfiehlt es sich, eine **copyWith**-Methode im Model selbst zu implementieren:
|
||||
|
||||
```php
|
||||
namespace App\Logic\Sales\Order\Model;
|
||||
|
||||
readonly class Order
|
||||
{
|
||||
public function __construct(
|
||||
public string $id,
|
||||
public string $customerEmail,
|
||||
public float $totalAmount,
|
||||
public int $version,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Erstellt eine Kopie und überschreibt nur die mitgegebenen Felder.
|
||||
*/
|
||||
public function with(
|
||||
?string $customerEmail = null,
|
||||
?float $totalAmount = null,
|
||||
): self {
|
||||
return new self(
|
||||
id: $this->id,
|
||||
customerEmail: $customerEmail ?? $this->customerEmail,
|
||||
totalAmount: $totalAmount ?? $this->totalAmount,
|
||||
version: 0, // Wird beim Speichern durch den Data Layer aktualisiert.
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine Version-Kopie für ein neues Update (Concurrency Handling).
|
||||
*/
|
||||
public function nextVersion(): self
|
||||
{
|
||||
return new self(
|
||||
id: $this->id,
|
||||
customerEmail: $this->customerEmail,
|
||||
totalAmount: $this->totalAmount,
|
||||
version: $this->version + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Verwendung im UseCase oder in der Factory
|
||||
$updatedOrder = $existingOrder->with(customerEmail: 'new@example.com', totalAmount: 123.45);
|
||||
```
|
||||
|
||||
### Code Beispiel (Data Layer Mapping)
|
||||
|
||||
#### Mapper Implementierung
|
||||
|
||||
Reference in New Issue
Block a user