Grenke DTOs
app/DataTransferObjects/Grenke/
Alle Daten die zwischen Controller, Action, Service und Grenke-API hin- und herfließen, gehen durch readonly DTOs. Externer Wire-Format ist PascalCase, internes PHP ist camelCase — die DTOs sind der einzige Ort, an dem konvertiert wird.
Übersicht (13 DTOs)
| DTO | Verwendung |
|---|---|
RequestPayloadData | Request-Body für POST /requests |
RequestResponseData | Response von GET/POST/PATCH /requests/... |
PatchRequestPayloadData | Request-Body für PATCH /requests/{id} |
PatchLesseePayloadData | Request-Body für PATCH /requests/{id}/lessee |
LesseeData | enthält addresses[], telephones[], legalForm, … |
AddressData | Adress-Datensatz (line1, postCode, city, country, type) |
TelephoneData | Telefon (number, type=Phone/Mobile/Fax) |
LegalFormData | Rechtsform |
ThirdPartyIdentifierData | externe IDs (Steuer-Nr, Handelsregister, …) |
FinancingObjectData | Leasing-Objekt (Quantity, ObjectTypeId, Manufacturer, …) |
ESignaturePayloadData | Request-Body für POST .../e-signature |
ESignatureConfigurationData | Response von GET .../e-signature/configuration |
ESignatureSigneeData | enthalten in ESignaturePayloadData.signees[] |
Anatomie
Jede DTO folgt demselben Muster:
namespace App\DataTransferObjects\Grenke;
class RequestPayloadData
{
public function __construct(
public readonly string $financingId,
public readonly string $productType,
public readonly float $financingAmount,
public readonly LesseeData $lessee,
public readonly array $financingObjects, // FinancingObjectData[]
// … 16 weitere Properties
) {}
public static function fromArray(array $data): self
{
return new self(
financingId: (string) ($data['FinancingId'] ?? ''),
productType: (string) ($data['ProductType'] ?? ''),
financingAmount: (float) ($data['FinancingAmount'] ?? 0),
lessee: LesseeData::fromArray($data['Lessee'] ?? []),
financingObjects: array_map(
fn (array $i) => FinancingObjectData::fromArray($i),
$data['FinancingObjects'] ?? []
),
);
}
public function toArray(): array
{
return [
'FinancingId' => $this->financingId,
'ProductType' => $this->productType,
'FinancingAmount' => $this->financingAmount,
'Lessee' => $this->lessee->toArray(),
'FinancingObjects' => array_map(
fn (FinancingObjectData $i) => $i->toArray(),
$this->financingObjects
),
];
}
}
Verschachtelung
Komplexe DTOs verschachteln andere DTOs:
Beim toArray() werden die verschachtelten DTOs rekursiv aufgelöst — keine Sorge.
Beispiel — kompletter Request
$payload = RequestPayloadData::fromArray([
'FinancingAmount' => 33877.56,
'Period' => 84,
'PaymentFrequency'=> 'Monthly',
'PaymentMethod' => 'DirectDebit',
'Currency' => 'EUR',
'ProductType' => 'ClassicLease',
'HasRepurchase' => true,
'Lessee' => [
'CompanyName' => 'Dr. Bettina Brem & Katrin Schimmelpfennig',
'ExternalId' => 'K562983',
'Email' => 'info@example.com',
'Addresses' => [[
'Line1' => 'Truderinger Str. 330',
'PostCode' => '81825',
'City' => 'München',
'Country' => 'DE',
'Type' => 'main',
]],
'Telephones' => [
['Number' => '+49 89 890566800', 'Type' => 'Phone'],
['Number' => '+49 89 890566808', 'Type' => 'Fax'],
],
'LegalFormId' => 0,
],
'FinancingObjects' => [[
'Quantity' => 2,
'ObjectTypeId' => 13,
'Name' => 'Human Medical Equipment',
'Manufacturer' => 'BLUE SAFETY',
'Details' => 'SAFEWATER 4.2',
'NetPricePerObject'=> 16938.78,
]],
]);
$response = $this->grenkeApiService->postJson('requests', $payload->toArray());
$result = RequestResponseData::fromArray($response);
Eigene DTO schreiben
- Datei anlegen:
app/DataTransferObjects/Grenke/<Name>Data.php - Konstruktor: ausschließlich
public readonlyProperties fromArray(array $data): selfmit Defensive-Defaults (?? null,?? '',?? 0)toArray(): arraymit dem PascalCase-Wire-Format- Verschachtelte DTOs ebenfalls mit
fromArray()/toArray()einbinden
Tipp: vor allem für Response-DTOs ist
?? nullwichtig, weil Grenke je nach Status nicht alle Felder mitschickt.