feat: harden xml parsing to avoid uncaught errors

This commit is contained in:
Björn Fromme
2026-03-20 12:14:02 +01:00
parent 3849ae306c
commit 3234c78f0d
9 changed files with 229 additions and 147 deletions
+59 -48
View File
@@ -25,56 +25,67 @@ class ApiResponseParser extends AbstractParser
$resultNode = $crawler->filterXPath('//ergebnis');
switch ($responseType) {
case ApiClient::TYPE_NOTIFICATION:
return (new NotificationParser())->parse($crawler);
case ApiClient::TYPE_CUSTOMER_DATA:
$subType = $resultNode->filterXPath('//art')->text();
try {
switch ($responseType) {
case ApiClient::TYPE_NOTIFICATION:
return (new NotificationParser())->parse($crawler);
case ApiClient::TYPE_CUSTOMER_DATA:
$subType = $this->getStringOrNullValue($resultNode->filterXPath('//art'));
if (null === $subType || '' === $subType) {
throw new ResponseParserException('Unable to determine customer data subtype from XML response');
}
switch ($subType) {
case 'Adressdaten':
case 'Adressdaten_Ändern':
case 'Newsletter':
return (new PersonalDataParser())->parse($resultNode);
case 'Adresse_Neu':
return (new ContactFormResponseParser())->parse($resultNode);
case 'SelektionCRM':
case 'SelektionCRM_Ändern':
return (new CrmAttributesResponseParser())->parse($resultNode);
case 'Vorgänge':
return (new BookingsParser())->parse($resultNode);
case 'Vorgang_Details':
return (new BookingParser())->parse($resultNode);
case 'Dokumentdruck':
return (new DocumentsParser())->parseDocuments($resultNode);
case 'Vorgangdruck':
return (new DocumentsParser())->parseConfirmation($resultNode);
}
break;
case ApiClient::TYPE_BASE_DATA_COUNTRIES:
return (new CountriesParser())->parse($resultNode);
case ApiClient::TYPE_MUTABLE_DATA:
return (new MutableDataParser())->parse($resultNode);
case ApiClient::TYPE_AVAILABILITY:
return (new AvailabilitiesParser())->parseServices($resultNode);
case ApiClient::TYPE_AVAILABILITY_HOTEL:
return (new AvailabilitiesParser())->parseRooms($resultNode);
case ApiClient::TYPE_BOOKING_UPDATE:
return (new BookingUpdateParser())->parse($resultNode);
case ApiClient::TYPE_BOOKING:
return (new BookingResponseParser())->parse($resultNode);
case ApiClient::TYPE_PRODUCTS:
return (new ProductsParser())->parse($resultNode);
case ApiClient::TYPE_PRODUCT_DATA:
$travelNode = $crawler->filterXPath('//reise/termin');
switch ($subType) {
case 'Adressdaten':
case 'Adressdaten_Ändern':
case 'Newsletter':
return (new PersonalDataParser())->parse($resultNode);
case 'Adresse_Neu':
return (new ContactFormResponseParser())->parse($resultNode);
case 'SelektionCRM':
case 'SelektionCRM_Ändern':
return (new CrmAttributesResponseParser())->parse($resultNode);
case 'Vorgänge':
return (new BookingsParser())->parse($resultNode);
case 'Vorgang_Details':
return (new BookingParser())->parse($resultNode);
case 'Dokumentdruck':
return (new DocumentsParser())->parseDocuments($resultNode);
case 'Vorgangdruck':
return (new DocumentsParser())->parseConfirmation($resultNode);
}
break;
case ApiClient::TYPE_BASE_DATA_COUNTRIES:
return (new CountriesParser())->parse($resultNode);
case ApiClient::TYPE_MUTABLE_DATA:
return (new MutableDataParser())->parse($resultNode);
case ApiClient::TYPE_AVAILABILITY:
return (new AvailabilitiesParser())->parseServices($resultNode);
case ApiClient::TYPE_AVAILABILITY_HOTEL:
return (new AvailabilitiesParser())->parseRooms($resultNode);
case ApiClient::TYPE_BOOKING_UPDATE:
return (new BookingUpdateParser())->parse($resultNode);
case ApiClient::TYPE_BOOKING:
return (new BookingResponseParser())->parse($resultNode);
case ApiClient::TYPE_PRODUCTS:
return (new ProductsParser())->parse($resultNode);
case ApiClient::TYPE_PRODUCT_DATA:
$travelNode = $crawler->filterXPath('//reise/termin');
return (new TravelParser())->parse($travelNode->first(), ...$additionalArgs);
case ApiClient::TYPE_AGENCIES:
return (new AgencyParser())->parse($resultNode);
case ApiClient::TYPE_PURCHASE_VOUCHER:
return (new PurchaseVoucherParser())->parse($resultNode);
case ApiClient::TYPE_PROMO_VOUCHER:
return (new PromoVoucherParser())->parse($resultNode);
if (0 === $travelNode->count()) {
throw new ResponseParserException('No travel data node found in product data response');
}
return (new TravelParser())->parse($travelNode->first(), ...$additionalArgs);
case ApiClient::TYPE_AGENCIES:
return (new AgencyParser())->parse($resultNode);
case ApiClient::TYPE_PURCHASE_VOUCHER:
return (new PurchaseVoucherParser())->parse($resultNode);
case ApiClient::TYPE_PROMO_VOUCHER:
return (new PromoVoucherParser())->parse($resultNode);
}
} catch (\InvalidArgumentException $e) {
throw new ResponseParserException('Invalid XML response structure: '.$e->getMessage(), 0, $e);
}
throw new ResponseParserException('Unable to parse XML response');