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/`
|
- **Ort**: `src/Logic/{Module}/{Feature}/Mapping/`
|
||||||
- **Verantwortung**: Abbildung der Struktur von einem DTO auf ein Business Model (einschließlich Child-Models).
|
- **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
|
```php
|
||||||
namespace App\Logic\Sales\Order\Mapping;
|
namespace App\Logic\Sales\Order\Mapping;
|
||||||
@@ -610,7 +613,7 @@ readonly class OrderModelFactory
|
|||||||
{
|
{
|
||||||
return new Order(
|
return new Order(
|
||||||
customerId: $request->customerId,
|
customerId: $request->customerId,
|
||||||
// Delegierung der Child-Objekte
|
// Delegierung der Child-Objects
|
||||||
items: array_map(
|
items: array_map(
|
||||||
fn($data) => new OrderItem(productId: $data['productId'], quantity: $data['quantity']),
|
fn($data) => new OrderItem(productId: $data['productId'], quantity: $data['quantity']),
|
||||||
$request->items
|
$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)
|
### Code Beispiel (Data Layer Mapping)
|
||||||
|
|
||||||
#### Mapper Implementierung
|
#### Mapper Implementierung
|
||||||
|
|||||||
Reference in New Issue
Block a user