feat: refactoring of xml parsers
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"symfony/asset": "6.4.*",
|
||||
"symfony/console": "6.4.*",
|
||||
"symfony/doctrine-messenger": "6.4.*",
|
||||
"symfony/dom-crawler": "6.4.*",
|
||||
"symfony/dotenv": "6.4.*",
|
||||
"symfony/expression-language": "6.4.*",
|
||||
"symfony/flex": "^2",
|
||||
|
||||
Generated
+137
-136
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "40436ef2d80ce14b8acf4decf58c66e8",
|
||||
"content-hash": "b7889b1556dde930fda7eb3acf8e7532",
|
||||
"packages": [
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
@@ -1506,6 +1506,73 @@
|
||||
},
|
||||
"time": "2024-06-03T08:48:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Masterminds/html5-php.git",
|
||||
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
|
||||
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Masterminds\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matt Butcher",
|
||||
"email": "[email protected]"
|
||||
},
|
||||
{
|
||||
"name": "Matt Farina",
|
||||
"email": "[email protected]"
|
||||
},
|
||||
{
|
||||
"name": "Asmir Mustafic",
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"description": "An HTML5 parser and serializer.",
|
||||
"homepage": "http://masterminds.github.io/html5-php",
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"dom",
|
||||
"html",
|
||||
"parser",
|
||||
"querypath",
|
||||
"serializer",
|
||||
"xml"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
|
||||
},
|
||||
"time": "2024-03-31T07:05:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "3.8.0",
|
||||
@@ -3207,6 +3274,73 @@
|
||||
],
|
||||
"time": "2024-10-18T09:45:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v6.4.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4304e6ad5c894a9c72831ad459f627bfd35d766d",
|
||||
"reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"masterminds/html5": "^2.6",
|
||||
"php": ">=8.1",
|
||||
"symfony/polyfill-ctype": "~1.8",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/css-selector": "^5.4|^6.0|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\DomCrawler\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "[email protected]"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Eases DOM navigation for HTML and XML documents",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dom-crawler/tree/v6.4.16"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-13T15:06:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dotenv",
|
||||
"version": "v6.4.16",
|
||||
@@ -8377,73 +8511,6 @@
|
||||
],
|
||||
"time": "2024-11-27T21:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Masterminds/html5-php.git",
|
||||
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
|
||||
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Masterminds\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matt Butcher",
|
||||
"email": "[email protected]"
|
||||
},
|
||||
{
|
||||
"name": "Matt Farina",
|
||||
"email": "[email protected]"
|
||||
},
|
||||
{
|
||||
"name": "Asmir Mustafic",
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"description": "An HTML5 parser and serializer.",
|
||||
"homepage": "http://masterminds.github.io/html5-php",
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"dom",
|
||||
"html",
|
||||
"parser",
|
||||
"querypath",
|
||||
"serializer",
|
||||
"xml"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
|
||||
},
|
||||
"time": "2024-03-31T07:05:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.12.1",
|
||||
@@ -10272,73 +10339,6 @@
|
||||
],
|
||||
"time": "2024-09-25T14:18:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v6.4.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4304e6ad5c894a9c72831ad459f627bfd35d766d",
|
||||
"reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"masterminds/html5": "^2.6",
|
||||
"php": ">=8.1",
|
||||
"symfony/polyfill-ctype": "~1.8",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/css-selector": "^5.4|^6.0|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\DomCrawler\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "[email protected]"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Eases DOM navigation for HTML and XML documents",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dom-crawler/tree/v6.4.16"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-13T15:06:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/maker-bundle",
|
||||
"version": "v1.61.0",
|
||||
@@ -10655,7 +10655,8 @@
|
||||
"php": ">=8.1",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-simplexml": "*"
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\BusProNet;
|
||||
|
||||
use App\BusProNet\ApiResponseParser\ResponseParser;
|
||||
use App\BusProNet\XmlParser\ApiResponseParser;
|
||||
use App\BusProNet\DataProcessor\BookingDataProcessor;
|
||||
use App\BusProNet\Exception\ApiClientException;
|
||||
use App\BusProNet\Exception\ResponseParserException;
|
||||
@@ -34,9 +34,9 @@ class ApiClient
|
||||
|
||||
public function __construct(
|
||||
private readonly SerializerInterface $serializer,
|
||||
private readonly ResponseParser $responseParser,
|
||||
private readonly LoggerInterface $logger,
|
||||
array $options
|
||||
private readonly ApiResponseParser $responseParser,
|
||||
private readonly LoggerInterface $logger,
|
||||
array $options
|
||||
) {
|
||||
$this->config = $this->resolveOptions($options);
|
||||
}
|
||||
@@ -180,16 +180,15 @@ class ApiClient
|
||||
* @throws ApiClientException
|
||||
* @throws ResponseParserException
|
||||
*/
|
||||
public function updateBooking(BookingData $formData, bool $dryRun = true): Notification|BookingUpdate
|
||||
public function updateBooking(BookingData $formData): Notification|BookingUpdate
|
||||
{
|
||||
$mode = $dryRun ? 'Anfrage' : 'Buchung';
|
||||
$payload = (new BookingDataProcessor())->createUpdateRequestPayload($formData);
|
||||
|
||||
$data = [
|
||||
'user' => $this->config['bpn_username'],
|
||||
'key' => $this->createKey($this->config['bpn_username'], $this->config['bpn_password'], static::TYPE_BOOKING_UPDATE),
|
||||
'satz' => ['@typ' => static::TYPE_BOOKING_UPDATE],
|
||||
'buchungsart' => $mode,
|
||||
'buchungsart' => 'Buchung',
|
||||
...$payload,
|
||||
];
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\Availability;
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
|
||||
class AvailabilitiesResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
public function parse(\SimpleXMLElement $xml): BaseData
|
||||
{
|
||||
$availabilities = [];
|
||||
|
||||
foreach ($xml->leistungen->leistung as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$id = (int) $attributes['id'];
|
||||
|
||||
$availability = new Availability();
|
||||
$availability->serviceId = $id;
|
||||
$availability->status = (string) $attributes['status'];
|
||||
$availability->available = (int) $attributes['frei'];
|
||||
$availability->price = $this->stringToFloat((string) $attributes['preis']);
|
||||
|
||||
$availabilities[$id] = $availability;
|
||||
}
|
||||
|
||||
return new BaseData($availabilities);
|
||||
}
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\Address;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\Communication;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use App\BusProNet\Model\Room;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\BusProNet\Model\Surcharge;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
use voku\helper\AntiXSS;
|
||||
|
||||
class BookingResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
public function parse(\SimpleXMLElement $xml): Booking
|
||||
{
|
||||
$travelData = $xml->reise;
|
||||
|
||||
$booking = new Booking();
|
||||
|
||||
$booking->id = (int) $xml->idbuchung;
|
||||
$booking->agencyId = (int) $xml->idagentur;
|
||||
$booking->bookingNumber = (int) $xml->vorgang;
|
||||
$booking->invoiceNumber = (int) $xml->zahlungsdaten->rechnung;
|
||||
$booking->totalPrice = $this->stringToFloat((string) $xml->zahlungsdaten->gesamtbetrag);
|
||||
$booking->status = (string) $xml->status;
|
||||
|
||||
$booking->travel = (string) $travelData->attributes()['bezeichnung'];
|
||||
$booking->travelId = (int) $xml->idreise;
|
||||
$booking->travelCode = (string) $travelData->attributes()['code'];
|
||||
$booking->travelDate = $this->stringToDate((string) $travelData->attributes()['termin']);
|
||||
|
||||
$booking->hotelId = (int) $xml->idpartner;
|
||||
$booking->hotelName = (string) $xml->partner;
|
||||
|
||||
$booking->applicant = $this->parsePersonalData($xml->anmelder);
|
||||
|
||||
$participantsStatus = $this->stringToArray((string) $xml->status_teilnehmer, '/');
|
||||
$booking->participantsStatus = array_combine(range(1, count($participantsStatus)), $participantsStatus);
|
||||
|
||||
$booking->participants = $this->parseParticipants($xml);
|
||||
|
||||
$paymentData = $xml->zahlung;
|
||||
$booking->paymentId = (int) $paymentData->attributes()['idzahlungsart'];
|
||||
$booking->paymentLabel = (string) $paymentData->attributes()['bezeichnung'];
|
||||
$booking->paymentType = (string) $paymentData->attributes()['art'];
|
||||
|
||||
if ($xml->beförderungen) {
|
||||
$booking->transportationServices = $this
|
||||
->parseServices($xml->beförderungen->beförderung, Service::CATEGORY_TRANSPORTATION);
|
||||
}
|
||||
if ($xml->zusatzleistungen) {
|
||||
$booking->additionalServices = $this
|
||||
->parseServices($xml->zusatzleistungen->zusatzleistung, Service::CATEGORY_ADDITIONAL);
|
||||
}
|
||||
if ($xml->ferienzielunterbringungen) {
|
||||
$booking->rooms = $this->parseRooms($xml->ferienzielunterbringungen);
|
||||
}
|
||||
if ($xml->zustiege) {
|
||||
$booking->pickups = $this->parsePickups($xml->zustiege);
|
||||
}
|
||||
if ($xml->zuschlaege) {
|
||||
$booking->surcharges = $this->parseSurcharges($xml->zuschlaege);
|
||||
}
|
||||
|
||||
return $booking;
|
||||
}
|
||||
|
||||
private function parseParticipants(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$participants = [];
|
||||
|
||||
foreach ($xml->teilnehmerliste->teilnehmer as $participant) {
|
||||
$id = (int) $participant->attributes()['id'];
|
||||
$participants[$id] = $this->parsePersonalData($participant);
|
||||
}
|
||||
|
||||
return $participants;
|
||||
}
|
||||
|
||||
private function parsePersonalData(\SimpleXMLElement $xml): PersonalData
|
||||
{
|
||||
$personalData = new PersonalData();
|
||||
$personalData->addressId = $xml->idadresse ? (int) $xml->idadresse : null;
|
||||
$personalData->personId = (int) $xml->idadresseperson;
|
||||
$personalData->name = (string) $xml->name;
|
||||
$personalData->firstName = (string) $xml->vorname;
|
||||
$personalData->salutation = (string) $xml->anrede;
|
||||
$personalData->title = (string) $xml->titel;
|
||||
$personalData->gender = $xml->geschlecht ? strtoupper((string) $xml->geschlecht) : null;
|
||||
$personalData->dateOfBirth = $xml->geburtsdatum ? $this->stringToDate((string) $xml->geburtsdatum) : null;
|
||||
$personalData->nationality = (string) $xml->nationalitaet;
|
||||
$personalData->height = $xml->sonstiges1 ? (int) $xml->sonstiges1 : null;
|
||||
$personalData->weight = $xml->sonstiges2 ? (int) $xml->sonstiges2 : null;
|
||||
$personalData->shoeSize = $xml->sonstiges3 ? (int) $xml->sonstiges3 : null;
|
||||
|
||||
if ($xml->anschrift) {
|
||||
$address = new Address();
|
||||
$address->street = (string) $xml->anschrift->strasse;
|
||||
$address->postCode = (string) $xml->anschrift->plz;
|
||||
$address->city = (string) $xml->anschrift->ort;
|
||||
$address->district = (string) $xml->anschrift->ortsteil;
|
||||
$address->country = (string) $xml->anschrift->land;
|
||||
|
||||
$personalData->address = $address;
|
||||
}
|
||||
|
||||
if ($xml->kommunikation) {
|
||||
$communication = new Communication();
|
||||
$communication->email = (string) $xml->kommunikation->email;
|
||||
$communication->phone = (string) $xml->kommunikation->telefonprivat;
|
||||
$communication->mobile = (string) $xml->kommunikation->telefonmobil;
|
||||
|
||||
$personalData->communication = $communication;
|
||||
}
|
||||
|
||||
if ($xml->bemerkung) {
|
||||
$antiXss = new AntiXSS();
|
||||
$remarks = $antiXss->xss_clean((string) $xml->bemerkung);
|
||||
$personalData->remarks = $remarks;
|
||||
}
|
||||
|
||||
return $personalData;
|
||||
}
|
||||
|
||||
private function parseServices(\SimpleXMLElement $xml, string $category): array
|
||||
{
|
||||
$services = [];
|
||||
|
||||
foreach ($xml as $service) {
|
||||
$attributes = $service->attributes();
|
||||
$id = (int) $attributes['idleistung'];
|
||||
|
||||
$service = new Service();
|
||||
$service->id = $id;
|
||||
$service->category = $category;
|
||||
$service->source = Service::SOURCE_BOOKING;
|
||||
$service->label = (string) $attributes['leistung'];
|
||||
$service->dateFrom = $attributes['termin'] ? $this->stringToDate((string) $attributes['termin']) : null;
|
||||
$service->dateTo = $attributes['terminbis'] ? $this->stringToDate((string) $attributes['terminbis']) : null;
|
||||
$service->subType = (string) $attributes['unterart'];
|
||||
$service->totalCount = (int) $attributes['anzahl'];
|
||||
$mapping = $this->stringToArray((string) $attributes['zuordnung']);
|
||||
$service->mapping = array_map('intval', $mapping);
|
||||
$service->totalPrice = $this->stringToFloat((string) $attributes['gesamtpreis']);
|
||||
$individualPrices = array_map(
|
||||
function ($price) {
|
||||
return $this->stringToFloat((string) $price);
|
||||
}, $this->stringToArray((string) $attributes['einzelpreis'], '/')
|
||||
);
|
||||
$service->individualPrice = array_combine($mapping, $individualPrices);
|
||||
if (Service::CATEGORY_TRANSPORTATION === $category) {
|
||||
$service->direction = (string) $attributes['richtung'];
|
||||
}
|
||||
|
||||
$services[$id] = $service;
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
||||
private function parseRooms(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$rooms = [];
|
||||
|
||||
foreach ($xml->ferienzielunterbringung as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$id = (int) $attributes['idzimmer'];
|
||||
|
||||
$room = new Room();
|
||||
$room->id = $id;
|
||||
$room->label = (string) $attributes['zimmer'];
|
||||
$room->category = (string) $attributes['kategorie'];
|
||||
$room->boardId = (int) $attributes['idverpflegung'];
|
||||
$room->dateFrom = $attributes['anreise'] ? $this->stringToDate((string) $attributes['anreise']) : null;
|
||||
$room->dateTo = $attributes['abreise'] ? $this->stringToDate((string) $attributes['abreise']) : null;
|
||||
$room->totalCount = (int) $attributes['anzahl'];
|
||||
$room->minPax = (int) $attributes['minpax'];
|
||||
$room->maxPax = (int) $attributes['maxpax'];
|
||||
$room->board = (string) $attributes['verpflegung'];
|
||||
$mapping = $this->stringToArray((string) $attributes['zuordnung']);
|
||||
$room->mapping = array_map('intval', $mapping);
|
||||
$room->totalPrice = $this->stringToFloat((string) $attributes['gesamtpreis']);
|
||||
$individualPrices = array_map(
|
||||
function ($price) {
|
||||
return $this->stringToFloat((string) $price);
|
||||
}, $this->stringToArray((string) $attributes['einzelpreis'], '/')
|
||||
);
|
||||
$room->individualPrice = array_combine($mapping, $individualPrices);
|
||||
|
||||
$rooms[$id] = $room;
|
||||
}
|
||||
|
||||
return $rooms;
|
||||
}
|
||||
|
||||
private function parsePickups(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$pickups = [];
|
||||
|
||||
foreach ($xml->zustieg as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$pickupId = (int) $attributes['idzustieg'];
|
||||
$pickupDate = (string) $attributes['datum'];
|
||||
$pickupTime = (string) $attributes['zeit'];
|
||||
|
||||
$pickup = new Pickup();
|
||||
$pickup->id = $pickupId;
|
||||
$pickup->code = (string) $attributes['code'];
|
||||
$pickup->city = (string) $xml->ort;
|
||||
$pickup->postalCode = (string) $xml->plz;
|
||||
$pickup->street = (string) $xml->strasse;
|
||||
$pickup->time = $this->stringToDateTime($pickupDate.' '.$pickupTime);
|
||||
$pickup->price = $attributes['preis'] ? $this->stringToFloat((string) $attributes['preis']) : null;
|
||||
$mapping = $this->stringToArray((string) $attributes['zuordnung']);
|
||||
$pickup->mapping = array_map('intval', $mapping);
|
||||
|
||||
$pickups[$pickupId] = $pickup;
|
||||
}
|
||||
|
||||
return $pickups;
|
||||
}
|
||||
|
||||
private function parseSurcharges(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$surcharges = [];
|
||||
|
||||
foreach ($xml->zuschlag as $item) {
|
||||
$attributes = $item->attributes();
|
||||
|
||||
$label = empty($attributes['bezeichnung']) ? 'unbekannt' : (string) $attributes['bezeichnung'];
|
||||
|
||||
$surcharge = new Surcharge();
|
||||
$surcharge->label = $label;
|
||||
$surcharge->totalPrice = $this->stringToFloat((string) $attributes['gesamtpreis']);
|
||||
$mapping = $this->stringToArray((string) $attributes['zuordnung']);
|
||||
$surcharge->mapping = array_map('intval', $mapping);
|
||||
$individualPrices = array_map(
|
||||
function ($price) {
|
||||
return $this->stringToFloat((string) $price);
|
||||
}, $this->stringToArray((string) $attributes['einzelpreis'], '/')
|
||||
);
|
||||
$surcharge->individualPrice = array_combine($mapping, $individualPrices);
|
||||
|
||||
$surcharges[] = $surcharge;
|
||||
}
|
||||
|
||||
return $surcharges;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\BookingUpdate;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
|
||||
class BookingUpdateResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
public function parse(\SimpleXMLElement $xml): BookingUpdate
|
||||
{
|
||||
$bookingUpdate = new BookingUpdate();
|
||||
$bookingUpdate->valid = 'möglich' === (string) $xml->aenderung;
|
||||
$bookingUpdate->totalPrice = $this->stringToFloat((string) $xml->gesamtpreis);
|
||||
|
||||
return $bookingUpdate;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
|
||||
class BookingsResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
public function parse(\SimpleXMLElement $xml): BaseData
|
||||
{
|
||||
$bookings = [];
|
||||
|
||||
foreach ($xml->vorgaenge->vorgang as $item) {
|
||||
$booking = new Booking();
|
||||
|
||||
$booking->id = (int) $item->id;
|
||||
$booking->bookingNumber = (int) $item->vorgangsnummer;
|
||||
$booking->status = (string) $item->status;
|
||||
$booking->participantCount = (int) $item->personen;
|
||||
$booking->price = $this->stringToFloat((string) $item->preis);
|
||||
$booking->bookingDate = $this->stringToDateTime((string) $item->buchungsdatum);
|
||||
$booking->travel = (string) $item->reise;
|
||||
$booking->travelId = (int) $item->idreise;
|
||||
$booking->travelDate = $this->stringToDate((string) $item->reisedatum);
|
||||
$booking->document = $this->stringToBool((string) $item->reisedokument);
|
||||
$booking->payment = $this->stringToFloat((string) $item->zahlung);
|
||||
|
||||
$bookings[] = $booking;
|
||||
}
|
||||
|
||||
return new BaseData($bookings);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Country;
|
||||
|
||||
class CountriesResponseParser
|
||||
{
|
||||
public function parse(\SimpleXMLElement $xml): BaseData
|
||||
{
|
||||
$countries = [];
|
||||
|
||||
foreach ($xml->laender->land as $item) {
|
||||
$itemAttributes = $item->attributes();
|
||||
$token = (string) $itemAttributes['kuerzel'];
|
||||
$country = new Country();
|
||||
$country->id = (int) $itemAttributes['id'];
|
||||
$country->name = (string) $itemAttributes['bezeichnung'];
|
||||
$country->token = (string) $itemAttributes['kuerzel'];
|
||||
$country->nationality = (string) $itemAttributes['nationalitaet'];
|
||||
|
||||
$countries[$token] = $country;
|
||||
}
|
||||
|
||||
return new BaseData($countries);
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\CrmAction;
|
||||
use App\BusProNet\Model\CrmAttributes;
|
||||
use App\BusProNet\Model\CrmSelection;
|
||||
use App\BusProNet\Model\CrmSelectionGroup;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
|
||||
class CrmAttributesResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
private const BPN_CRM_ID_ADMIN = 1292;
|
||||
private const BPN_CRM_ID_MANAGER = 1293;
|
||||
private const BPN_CRM_ID_TEAMER = 1070;
|
||||
|
||||
public function parse(\SimpleXMLElement $xml): CrmAttributes
|
||||
{
|
||||
$groups = [];
|
||||
$actions = [];
|
||||
$isAdmin = $isManager = $isHouseManager = $isTeamer = false;
|
||||
$hotelCode = null;
|
||||
|
||||
foreach ($xml->selektionsmerkmale->selektionsgruppe as $item) {
|
||||
$group = new CrmSelectionGroup();
|
||||
$group->id = (int) $item->attributes()['id'];
|
||||
$group->label = (string) $item->attributes()['bezeichnung'];
|
||||
$attributes = [];
|
||||
|
||||
foreach ($item->selektion as $subItem) {
|
||||
$subItemAttributes = $subItem->attributes();
|
||||
$attributeLabel = (string) $subItemAttributes['bezeichnung'];
|
||||
$attribute = new CrmSelection();
|
||||
$attribute->id = (int) $subItemAttributes['id'];
|
||||
$attribute->label = $attributeLabel;
|
||||
$attribute->mutable = $this->stringToBool((string) $subItemAttributes['aenderbar']);
|
||||
$attribute->selected = $this->stringToBool((string) $subItemAttributes['auswahl']);
|
||||
|
||||
if (1 === preg_match('/^Hausleitung ([A-Z0-9]+)$/', $attributeLabel, $matches) && true === $attribute->selected) {
|
||||
$isHouseManager = true;
|
||||
$hotelCode = $matches[1];
|
||||
}
|
||||
if (static::BPN_CRM_ID_ADMIN === $attribute->id && true === $attribute->selected) {
|
||||
$isAdmin = true;
|
||||
}
|
||||
if (static::BPN_CRM_ID_MANAGER === $attribute->id && true === $attribute->selected) {
|
||||
$isManager = true;
|
||||
}
|
||||
if (static::BPN_CRM_ID_TEAMER === $attribute->id && true === $attribute->selected) {
|
||||
$isTeamer = true;
|
||||
}
|
||||
|
||||
$attributes[] = $attribute;
|
||||
}
|
||||
$group->selections = $attributes;
|
||||
$groups[] = $group;
|
||||
}
|
||||
|
||||
foreach ($xml->crmaktionen->crmaktion as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$crmAction = new CrmAction();
|
||||
$crmAction->id = (int) $attributes['id'];
|
||||
$crmAction->code = (string) $attributes['code'];
|
||||
$crmAction->label = (string) $attributes['bezeichnung'];
|
||||
$crmAction->mutable = $this->stringToBool((string) $attributes['aenderbar']);
|
||||
$crmAction->selected = $this->stringToBool((string) $attributes['auswahl']);
|
||||
|
||||
$actions[] = $crmAction;
|
||||
}
|
||||
|
||||
$response = new CrmAttributes();
|
||||
$response->selectionGroups = $groups;
|
||||
$response->crmActions = $actions;
|
||||
$response->admin = $isAdmin;
|
||||
$response->manager = $isManager;
|
||||
$response->houseManager = $isHouseManager;
|
||||
$response->teamer = $isTeamer;
|
||||
$response->hotelCode = $hotelCode;
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\File;
|
||||
use PhpZip\Exception\ZipException;
|
||||
use PhpZip\ZipFile;
|
||||
|
||||
class DocumentsResponseParser
|
||||
{
|
||||
public function parseConfirmation(\SimpleXMLElement $xml): ?File
|
||||
{
|
||||
$item = (string) $xml->bestaetigungpdf;
|
||||
[, $pdfData] = explode(',', $item);
|
||||
|
||||
return new File('bestaetigung.pdf', base64_decode($pdfData), 'application/pdf');
|
||||
}
|
||||
|
||||
public function parseDocuments(\SimpleXMLElement $xml): ?File
|
||||
{
|
||||
if (1 === count($xml->reisedokumente->reisedokument)) {
|
||||
$item = $xml->reisedokumente->reisedokument[0];
|
||||
[, $pdfData] = explode(',', $item->pdf);
|
||||
|
||||
return new File((string) $item->datei.'.pdf', base64_decode($pdfData), 'application/pdf');
|
||||
}
|
||||
|
||||
// In case of multiple documents create ZIP file
|
||||
try {
|
||||
$zip = new ZipFile();
|
||||
|
||||
foreach ($xml->reisedokumente->reisedokument as $item) {
|
||||
[, $pdfData] = explode(',', $item->pdf);
|
||||
$zip->addFromString($item->datei.'.pdf', base64_decode($pdfData));
|
||||
}
|
||||
|
||||
return new File('reisedokumente.zip', $zip->outputAsString(), 'application/zip');
|
||||
}
|
||||
catch (ZipException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\MutableData;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
|
||||
class MutableDataResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
public function parse(\SimpleXMLElement $xml): BaseData
|
||||
{
|
||||
$mutableFields = [];
|
||||
|
||||
foreach ($xml->änderungen->änderung as $item) {
|
||||
$attributes = $item->attributes();
|
||||
|
||||
$category = match ((string) $attributes['art']) {
|
||||
'anzahl_teilnehmer' => MutableData::CATEGORY_PARTICIPANT_COUNT,
|
||||
'beförderung' => MutableData::CATEGORY_TRANSPORTATION,
|
||||
'zustieg' => MutableData::CATEGORY_PICKUP,
|
||||
'unterbringung' => MutableData::CATEGORY_ACCOMMODATION,
|
||||
'zusatzleistung' => MutableData::CATEGORY_ADDITIONAL_SERVICES,
|
||||
'teilnehmerdaten' => MutableData::CATEGORY_PARTICIPANT_DATA,
|
||||
default => null,
|
||||
};
|
||||
|
||||
if (null === $category) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mutableField = new MutableData($category, $this->stringToBool((string) $attributes['möglich']));
|
||||
|
||||
if ($attributes['möglichbiszum']) {
|
||||
$mutableField->mutableBefore = $this->stringToDate((string) $attributes['möglichbiszum']);
|
||||
}
|
||||
|
||||
$mutableFields[$category] = $mutableField;
|
||||
}
|
||||
|
||||
return new BaseData($mutableFields);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\Notification;
|
||||
|
||||
class NotificationResponseParser
|
||||
{
|
||||
public function parse(\SimpleXMLElement $xml): Notification
|
||||
{
|
||||
$recordXml = $xml->satz;
|
||||
|
||||
return new Notification((int) $recordXml->nr, (string) $recordXml->text);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\Model\Address;
|
||||
use App\BusProNet\Model\Communication;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
|
||||
class PersonalDataResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
public function parse(\SimpleXMLElement $xml): PersonalData
|
||||
{
|
||||
$addressXml = $xml->adressdaten;
|
||||
|
||||
$dateString = (string) $addressXml->geburtsdatum;
|
||||
$dateOfBirth = empty($dateString) ? null : \DateTimeImmutable::createFromFormat('d.m.Y', $dateString);
|
||||
|
||||
$personalData = new PersonalData();
|
||||
|
||||
$personalData->addressId = (int) $xml->idadresse;
|
||||
$personalData->personId = (int) $xml->idperson;
|
||||
$personalData->firstName = (string) $addressXml->vorname;
|
||||
$personalData->name = (string) $addressXml->name;
|
||||
$personalData->salutation = (string) $addressXml->anrede;
|
||||
$personalData->title = (string) $addressXml->titel;
|
||||
$personalData->gender = strtoupper((string) $addressXml->geschlecht);
|
||||
$personalData->dateOfBirth = $dateOfBirth;
|
||||
|
||||
$personalData->height = $xml->sonstiges1 ? (int) $xml->sonstiges1 : null;
|
||||
$personalData->weight = $xml->sonstiges2 ? (int) $xml->sonstiges2 : null;
|
||||
$personalData->shoeSize = $xml->sonstiges3 ? (int) $xml->sonstiges3 : null;
|
||||
|
||||
if ($postalXml = $addressXml->anschrift) {
|
||||
$address = new Address();
|
||||
$address->street = (string) $postalXml->strasse;
|
||||
$address->postCode = (string) $postalXml->plz;
|
||||
$address->city = (string) $postalXml->ort;
|
||||
$address->country = (string) $postalXml->land;
|
||||
|
||||
$personalData->address = $address;
|
||||
}
|
||||
|
||||
if ($contactXml = $addressXml->kommunikation) {
|
||||
$communication = new Communication();
|
||||
$communication->phone = (string) $contactXml->telefonprivat;
|
||||
$communication->mobile = (string) $contactXml->telefonmobil;
|
||||
$communication->email = (string) $contactXml->email;
|
||||
$communication->newsletter = $this->stringToBool((string) $contactXml->newsletter);
|
||||
|
||||
$personalData->communication = $communication;
|
||||
}
|
||||
|
||||
return $personalData;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\ApiResponseParser;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\Exception\ResponseParserException;
|
||||
|
||||
class ResponseParser
|
||||
{
|
||||
/**
|
||||
* @throws ResponseParserException
|
||||
*/
|
||||
public function parseXmlString(string $type, string $content): mixed
|
||||
{
|
||||
$xml = simplexml_load_string($content);
|
||||
|
||||
if (false === $xml) {
|
||||
throw new ResponseParserException('Empty response received from server');
|
||||
}
|
||||
|
||||
// Override type when present in XML to catch error responses
|
||||
$responseType = $type;
|
||||
$responseTypeXml = $xml->xpath('satz/@typ');
|
||||
if (0 < count($responseTypeXml)) {
|
||||
$responseType = (string) $xml->xpath('satz/@typ')[0];
|
||||
}
|
||||
|
||||
switch ($responseType) {
|
||||
case ApiClient::TYPE_NOTIFICATION:
|
||||
return (new NotificationResponseParser())->parse($xml);
|
||||
case ApiClient::TYPE_CUSTOMER_DATA:
|
||||
$subType = (string) $xml->art;
|
||||
switch ($subType) {
|
||||
case 'Adressdaten':
|
||||
case 'Adressdaten_Ändern':
|
||||
case 'Newsletter':
|
||||
return (new PersonalDataResponseParser())->parse($xml);
|
||||
case 'SelektionCRM':
|
||||
case 'SelektionCRM_Ändern':
|
||||
return (new CrmAttributesResponseParser())->parse($xml);
|
||||
case 'Vorgänge':
|
||||
return (new BookingsResponseParser())->parse($xml);
|
||||
case 'Vorgang_Details':
|
||||
return (new BookingResponseParser())->parse($xml);
|
||||
case 'Dokumentdruck':
|
||||
return (new DocumentsResponseParser())->parseDocuments($xml);
|
||||
case 'Vorgangdruck':
|
||||
return (new DocumentsResponseParser())->parseConfirmation($xml);
|
||||
}
|
||||
break;
|
||||
case ApiClient::TYPE_BASE_DATA_COUNTRIES:
|
||||
return (new CountriesResponseParser())->parse($xml);
|
||||
case ApiClient::TYPE_MUTABLE_DATA:
|
||||
return (new MutableDataResponseParser())->parse($xml);
|
||||
case ApiClient::TYPE_AVAILABILITY:
|
||||
return (new AvailabilitiesResponseParser())->parse($xml);
|
||||
case ApiClient::TYPE_BOOKING_UPDATE:
|
||||
return (new BookingUpdateResponseParser())->parse($xml);
|
||||
}
|
||||
|
||||
throw new ResponseParserException('Unable to parse XML response');
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class CountryDataProvider
|
||||
{
|
||||
try {
|
||||
return $this->cache->get('bpn_countries', function (ItemInterface $item) {
|
||||
$item->expiresAfter(3600);
|
||||
$item->expiresAfter(6 * 60 * 60);
|
||||
|
||||
return $this
|
||||
->apiClient
|
||||
|
||||
@@ -11,4 +11,5 @@ class CrmAttributes
|
||||
public bool $houseManager = false;
|
||||
public bool $teamer = false;
|
||||
public ?string $hotelCode = null;
|
||||
public array $roles = [];
|
||||
}
|
||||
@@ -7,13 +7,21 @@ use Carbon\Exceptions\InvalidFormatException;
|
||||
|
||||
trait TypeConversionTrait
|
||||
{
|
||||
protected function stringToArray(string $string, string $separator = ','): array
|
||||
protected function stringToArray(?string $string, string $separator = ','): array
|
||||
{
|
||||
if (null === $string) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return explode($separator, $string);
|
||||
}
|
||||
|
||||
protected function stringToFloat(string $string): float
|
||||
protected function stringToFloat(?string $string): ?float
|
||||
{
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (float) str_replace(['.', ','], ['', '.'], $string);
|
||||
}
|
||||
|
||||
@@ -22,8 +30,12 @@ trait TypeConversionTrait
|
||||
return number_format($float, 2, ',', '');
|
||||
}
|
||||
|
||||
protected function stringToBool(string $string): bool
|
||||
protected function stringToBool(?string $string): bool
|
||||
{
|
||||
if (null === $string) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 'True' === $string;
|
||||
}
|
||||
|
||||
@@ -32,8 +44,12 @@ trait TypeConversionTrait
|
||||
return $bool ? 'True' : 'False';
|
||||
}
|
||||
|
||||
protected function stringToDate(string $string): ?\DateTimeImmutable
|
||||
protected function stringToDate(?string $string): ?\DateTimeImmutable
|
||||
{
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$date = Carbon::createFromFormat('d.m.Y', $string)->startOfDay();
|
||||
return $date->toDateTimeImmutable();
|
||||
@@ -42,8 +58,12 @@ trait TypeConversionTrait
|
||||
}
|
||||
}
|
||||
|
||||
protected function stringToDateTime(string $string): ?\DateTimeImmutable
|
||||
protected function stringToDateTime(?string $string): ?\DateTimeImmutable
|
||||
{
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$dateTime = Carbon::createFromFormat('d.m.Y H:i', substr($string, 0, 16))->startOfDay();
|
||||
return $dateTime->toDateTimeImmutable();
|
||||
|
||||
+3
-1
@@ -3,11 +3,13 @@
|
||||
namespace App\BusProNet\XmlLoader;
|
||||
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
use App\BusProNet\XmlParserTrait;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
abstract class AbstractXmlLoader
|
||||
abstract class AbstractLoader
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
use XmlParserTrait;
|
||||
|
||||
public function __construct(protected readonly CacheInterface $cache, protected readonly ?string $xmlPath = null)
|
||||
{
|
||||
+22
-20
@@ -5,24 +5,27 @@ namespace App\BusProNet\XmlLoader;
|
||||
use App\BusProNet\Model\Hotel;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
|
||||
class HotelXmlLoader extends AbstractXmlLoader
|
||||
class HotelLoader extends AbstractLoader
|
||||
{
|
||||
public function loadAll(?string $filename = 'hotel.xml'): array
|
||||
{
|
||||
try {
|
||||
return $this->cache->get('bpn_hotels', function (ItemInterface $item) use ($filename) {
|
||||
$item->expiresAfter(3600);
|
||||
|
||||
$xml = $this->loadXml($filename);
|
||||
$item->expiresAfter(3 * 60 * 60);
|
||||
|
||||
$hotels = [];
|
||||
|
||||
foreach ($xml->hotel as $hotel) {
|
||||
$id = (int)$hotel->attributes()['idbuspro'];
|
||||
$hotels[$id] = $this->parseXml($hotel);
|
||||
}
|
||||
$this
|
||||
->loadXml($filename)
|
||||
->filterXPath('//hotels/hotel')
|
||||
->each(function (Crawler $node) use (&$hotels) {
|
||||
$id = (int) $node->attr('idbuspro');
|
||||
$hotels[$id] = $this->parseXml($node);
|
||||
})
|
||||
;
|
||||
|
||||
return $hotels;
|
||||
});
|
||||
@@ -51,25 +54,24 @@ class HotelXmlLoader extends AbstractXmlLoader
|
||||
return $hotels[$id] ?? null;
|
||||
}
|
||||
|
||||
private function loadXml(?string $filename = 'hotel.xml'): \SimpleXMLElement
|
||||
private function loadXml(?string $filename = 'hotel.xml'): Crawler
|
||||
{
|
||||
$filepath = $this->xmlPath.'/'.$filename;
|
||||
$xml = file_get_contents($filepath);
|
||||
|
||||
return simplexml_load_file($filepath);
|
||||
return new Crawler($xml);
|
||||
}
|
||||
|
||||
public function parseXml(\SimpleXMLElement $xml): Hotel
|
||||
public function parseXml(Crawler $node): Hotel
|
||||
{
|
||||
$attributes = $xml->attributes();
|
||||
|
||||
$hotel = new Hotel();
|
||||
$hotel->id = (int) $attributes['idbuspro'];
|
||||
$hotel->code = (string) $attributes['code'];
|
||||
$hotel->name = (string) $xml->name;
|
||||
$hotel->city = $xml->ort ? (string) $xml->ort : null;
|
||||
$hotel->country = (string) $xml->land;
|
||||
$hotel->street = (string) $xml->strasse;
|
||||
$hotel->phone = $xml->telefon ? (string) $xml->telefon : null;
|
||||
$hotel->id = (int) $node->attr('idbuspro');
|
||||
$hotel->code = $node->attr('code');
|
||||
$hotel->name = $this->getStringOrNullValue($node->filterXPath('//name'));
|
||||
$hotel->city = $this->getStringOrNullValue($node->filterXPath('//ort'));
|
||||
$hotel->country = $this->getStringOrNullValue($node->filterXPath('//land'));
|
||||
$hotel->street = $this->getStringOrNullValue($node->filterXPath('//strasse'));
|
||||
$hotel->phone = $this->getStringOrNullValue($node->filterXPath('//telefon'));
|
||||
|
||||
return $hotel;
|
||||
}
|
||||
+15
-15
@@ -5,24 +5,26 @@ namespace App\BusProNet\XmlLoader;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
|
||||
class PickupXmlLoader extends AbstractXmlLoader
|
||||
class PickupLoader extends AbstractLoader
|
||||
{
|
||||
public function loadAll(?string $filename = 'zustiege.xml'): array
|
||||
{
|
||||
try {
|
||||
return $this->cache->get('bpn_pickups', function (ItemInterface $item) use ($filename) {
|
||||
$item->expiresAfter(3600);
|
||||
$item->expiresAfter(3 * 60 * 60);
|
||||
|
||||
$xml = simplexml_load_file($this->xmlPath . '/' . $filename);
|
||||
$crawler = new Crawler(file_get_contents($this->xmlPath . '/' . $filename));
|
||||
$pickupNodes = $crawler->filterXPath('//zustiege/zustieg');
|
||||
|
||||
$pickups = [];
|
||||
|
||||
foreach ($xml->zustieg as $pickup) {
|
||||
$id = (int)$pickup->attributes()['idbuspro'];
|
||||
$pickups[$id] = $this->parseXml($pickup);
|
||||
}
|
||||
$pickupNodes->each(function (Crawler $node) use (&$pickups) {
|
||||
$id = $node->attr('idbuspro');
|
||||
$pickups[$id] = $this->parseXml($node);
|
||||
});
|
||||
|
||||
return $pickups;
|
||||
});
|
||||
@@ -38,16 +40,14 @@ class PickupXmlLoader extends AbstractXmlLoader
|
||||
return $pickups[$id] ?? null;
|
||||
}
|
||||
|
||||
public function parseXml(\SimpleXMLElement $xml): Pickup
|
||||
public function parseXml(Crawler $node): Pickup
|
||||
{
|
||||
$attributes = $xml->attributes();
|
||||
|
||||
$pickup = new Pickup();
|
||||
$pickup->id = (int) $attributes['idbuspro'];
|
||||
$pickup->code = (string) $attributes['code'];
|
||||
$pickup->city = (string) $xml->ort;
|
||||
$pickup->postalCode = (string) $xml->plz;
|
||||
$pickup->street = (string) $xml->strasse;
|
||||
$pickup->id = (int) $node->attr('idbuspro');
|
||||
$pickup->code = $node->attr('code');
|
||||
$pickup->city = $this->getStringOrNullValue($node->filterXPath('//ort'));
|
||||
$pickup->postalCode = $this->getStringOrNullValue($node->filterXPath('//plz'));
|
||||
$pickup->street = $this->getStringOrNullValue($node->filterXPath('//strasse'));
|
||||
|
||||
return $pickup;
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlLoader;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\CrmSelection;
|
||||
use App\BusProNet\Model\CrmSelectionGroup;
|
||||
use App\BusProNet\Model\Guide;
|
||||
use App\BusProNet\Model\MutableData;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use App\BusProNet\Model\Room;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
|
||||
class TravelLoader extends AbstractLoader
|
||||
{
|
||||
public function __construct(
|
||||
private readonly HotelLoader $hotelDataLoader,
|
||||
CacheInterface $cache,
|
||||
?string $xmlPath = null
|
||||
) {
|
||||
parent::__construct($cache, $xmlPath);
|
||||
}
|
||||
|
||||
public function generateFilesMap(): array
|
||||
{
|
||||
try {
|
||||
return $this->cache->get('bpn_travels_mapping', function (ItemInterface $item) {
|
||||
$item->expiresAfter(3 * 60 * 60);
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->files()->in($this->xmlPath)->name('Ziel_*.xml');
|
||||
|
||||
$mapping = [];
|
||||
$hotels = $this->hotelDataLoader->loadAll();
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$xml = $file->getContents();
|
||||
$crawler = new Crawler($xml);
|
||||
$travelDataNodes = $crawler->filterXPath('//reisen/reise/termin');
|
||||
|
||||
$travelDataNodes->each(function (Crawler $node) use (&$mapping, $hotels, $file) {
|
||||
$travelId = $node->attr('idbuspro');
|
||||
|
||||
$mapping[$travelId] = [
|
||||
'id' => $travelId,
|
||||
'code' => $node->attr('code'),
|
||||
'label' => $this->getStringOrNullValue($node->filterXPath('//text')),
|
||||
'dateFrom' => $this->stringToDate($node->attr('termin')),
|
||||
'dateTo' => $this->stringToDate($node->attr('bis')),
|
||||
'hotels' => [],
|
||||
'file' => $file->getRealPath(),
|
||||
];
|
||||
|
||||
$node->filterXPath('//hotel')
|
||||
->each(function (Crawler $hotelNode) use (&$mapping, $hotels, $travelId) {
|
||||
$hotelId = (int) $hotelNode->attr('idbuspro');
|
||||
|
||||
$mapping[$travelId]['hotels'][$hotelId] = [
|
||||
'id' => $hotelId,
|
||||
'code' => $hotelNode->attr('code'),
|
||||
'label' => $hotels[$hotelId]->name,
|
||||
];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
});
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public function mapCodeToId(string $travelCode): ?int
|
||||
{
|
||||
$mapping = $this->generateFilesMap();
|
||||
|
||||
$travelCodes = array_column($mapping, 'code', 'id');
|
||||
|
||||
if (false === $travelId = array_search($travelCode, $travelCodes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travelId;
|
||||
}
|
||||
|
||||
public function loadById(int $travelId, ?int $hotelId = null, ?string $filename = null): ?Travel
|
||||
{
|
||||
if (null !== $filename) {
|
||||
return $this->loadXml($travelId, $hotelId, $filename);
|
||||
}
|
||||
|
||||
$mapping = $this->generateFilesMap();
|
||||
|
||||
if (false === isset($mapping[$travelId])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$filename = $mapping[$travelId]['file'];
|
||||
|
||||
return $this->loadXml($travelId, $hotelId, $filename);
|
||||
}
|
||||
|
||||
private function loadXml(int $id, ?int $hotelId, string $filename): ?Travel
|
||||
{
|
||||
$xml = file_get_contents($filename);
|
||||
$crawler = new Crawler($xml);
|
||||
|
||||
$travelNode = $crawler->filterXPath(sprintf('//reise/termin[@idbuspro="%d"]', $id));
|
||||
|
||||
if (0 === $travelNode->count()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->parseXml($travelNode->first(), $hotelId);
|
||||
}
|
||||
|
||||
public function parseXml(Crawler $node, ?int $hotelId): Travel
|
||||
{
|
||||
$hotelNode = $this->getHotelNode($node, $hotelId);
|
||||
|
||||
$travel = new Travel();
|
||||
$travel->id = (int) $node->attr('idbuspro');
|
||||
$travel->hotelId = $hotelId;
|
||||
$travel->label = $this->getStringOrNullValue($node->filterXPath('//text'));
|
||||
$travel->dateFrom = $this->stringToDate($node->attr('termin'));
|
||||
$travel->dateTo = $this->stringToDate($node->attr('bis'));
|
||||
$travel->code = $node->attr('code');
|
||||
$travel->type = $node->attr('reiseart');
|
||||
$travel->priceFrom = $this->stringToFloat($this->getStringOrNullValue($node->filterXPath('//abpreis')));
|
||||
$travel->selectionGroups = $this->getSelectionGroups($node->filterXPath('//selektionsgruppe'));
|
||||
$travel->additionalServices = $this
|
||||
->getAdditionalServices($node->filterXPath('//lei_sonstiges/leistung'));
|
||||
$travel->transportationServices = $this
|
||||
->getTransportationServices($node->filterXPath('//lei_befoerderung/leistung'));
|
||||
$travel->rooms = $this->getRooms($hotelNode);
|
||||
$travel->pickups = $this->getPickups($node->filterXPath('//zustiege/zustieg'));
|
||||
|
||||
return $travel;
|
||||
}
|
||||
|
||||
public function getSelectionGroups(Crawler $node): array
|
||||
{
|
||||
$selectionGroups = [];
|
||||
|
||||
$node->each(function (Crawler $groupNode) use (&$selectionGroups) {
|
||||
$groupId = (int) $groupNode->attr('idbuspro');
|
||||
$selectionGroup = new CrmSelectionGroup();
|
||||
$selectionGroup->id = $groupId;
|
||||
$selectionGroup->label = $groupNode->attr('bezeichnung');
|
||||
|
||||
$groupNode
|
||||
->filterXPath('//selektion')
|
||||
->each(function (Crawler $selectionNode) use (&$selectionGroups, &$selectionGroup, $groupId) {
|
||||
$selectionId = (int) $selectionNode->attr('idbuspro');
|
||||
$selection = new CrmSelection();
|
||||
$selection->id = $selectionId;
|
||||
$selection->label = $selectionNode->attr('bezeichnung');
|
||||
$selectionGroups[$groupId]['selections'][$selectionId] = $selectionNode->attr('bezeichnung');
|
||||
$selectionGroup->selections[] = $selection;
|
||||
})
|
||||
;
|
||||
|
||||
$selectionGroups[$groupId] = $selectionGroup;
|
||||
});
|
||||
|
||||
return $selectionGroups;
|
||||
}
|
||||
|
||||
public function getAdditionalServices(Crawler $node): array
|
||||
{
|
||||
$additionalServices = [];
|
||||
|
||||
$node->each(function (Crawler $serviceNode) use (&$additionalServices) {
|
||||
$serviceId = (int) $serviceNode->attr('idbuspro');
|
||||
|
||||
$service = new Service();
|
||||
$service->source = Service::SOURCE_TRAVEL;
|
||||
$service->category = Service::CATEGORY_ADDITIONAL;
|
||||
$service->id = $serviceId;
|
||||
$service->subType = $serviceNode->attr('unterart');
|
||||
$service->mandatory = $this->stringToBool($serviceNode->attr('pflicht'));
|
||||
$service->dateFrom = $this->stringToDate($serviceNode->attr('termin'));
|
||||
$service->dateTo = $this->stringToDate($serviceNode->attr('bis'));
|
||||
$service->label = $this->getStringOrNullValue($serviceNode->filterXPath('//text'));
|
||||
$service->price = $this
|
||||
->stringToFloat($this->getStringOrNullValue($serviceNode->filterXPath('//preis')));
|
||||
$service->status = $this->getStringOrNullValue($serviceNode->filterXPath('//status'));
|
||||
|
||||
$additionalServices[$serviceId] = $service;
|
||||
});
|
||||
|
||||
return $additionalServices;
|
||||
}
|
||||
|
||||
public function getGuideForTransportationService(\SimpleXMLElement $xmlTransportationService): ?Guide
|
||||
{
|
||||
if (null === $xmlTransportationService->reiseleiter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$guide = new Guide();
|
||||
$guide->name = $xmlTransportationService->reiseleiter->name;
|
||||
$guide->phone = $xmlTransportationService->reiseleiter->telefon;
|
||||
|
||||
return $guide;
|
||||
}
|
||||
|
||||
public function getTransportationServices(Crawler $node): array
|
||||
{
|
||||
$transportationServices = [];
|
||||
|
||||
$node->each(function (Crawler $serviceNode) use (&$transportationServices) {
|
||||
$serviceId = (int) $serviceNode->attr('idbuspro');
|
||||
|
||||
$service = new Service();
|
||||
$service->source = Service::SOURCE_TRAVEL;
|
||||
$service->category = Service::CATEGORY_TRANSPORTATION;
|
||||
$service->id = $serviceId;
|
||||
$service->subType = $serviceNode->attr('unterart');
|
||||
$service->dateFrom = $this->stringToDate($serviceNode->attr('termin'));
|
||||
$service->dateTo = $this->stringToDate($serviceNode->attr('bis'));
|
||||
$service->label = $this->getStringOrNullValue($serviceNode->filterXPath('//text'));
|
||||
$service->direction = $this->getStringOrNullValue($serviceNode->filterXPath('//richtung'));
|
||||
|
||||
$transportationServices[$serviceId] = $service;
|
||||
});
|
||||
|
||||
return $transportationServices;
|
||||
}
|
||||
|
||||
public function getPickups(Crawler $node): array
|
||||
{
|
||||
$pickups = [];
|
||||
|
||||
$node->each(function (Crawler $pickupNode) use (&$pickups) {
|
||||
$pickupId = (int) $pickupNode->attr('idbuspro');
|
||||
|
||||
$pickup = new Pickup();
|
||||
$pickup->id = $pickupId;
|
||||
$pickup->time = $this->stringToDateTime($pickupNode->attr('zeit'));
|
||||
$pickup->price = $pickupNode->attr('preis') ?
|
||||
$this->stringToFloat($pickupNode->attr('preis')) : null;
|
||||
|
||||
$pickups[$pickupId] = $pickup;
|
||||
});
|
||||
|
||||
return $pickups;
|
||||
}
|
||||
|
||||
public function getHotelNode(Crawler $node, ?int $hotelId): Crawler
|
||||
{
|
||||
// In case not hotel id is provided, take the first hotel node (which is most probably the only one)
|
||||
if (null === $hotelId) {
|
||||
return $node->filterXPath('//hotel')->first();
|
||||
}
|
||||
|
||||
$hotelNode = $node->filterXPath(sprintf('//hotel[@idbuspro="%d"]', $hotelId));
|
||||
|
||||
return $hotelNode->first();
|
||||
}
|
||||
|
||||
public function getRooms(Crawler $node): array
|
||||
{
|
||||
$roomNodes = $node->filterXPath('//zimmer/preis');
|
||||
|
||||
if (0 === $roomNodes->count()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rooms = [];
|
||||
|
||||
$roomNodes->each(function (Crawler $roomNode) use (&$rooms) {
|
||||
$roomId = (int) $roomNode->attr('idbuspro_zimmer');
|
||||
|
||||
$room = new Room();
|
||||
$room->id = $roomId;
|
||||
$room->code = $roomNode->attr('zimmercode');
|
||||
$room->category = $roomNode->attr('kat');
|
||||
$room->boardId = (int) $roomNode->attr('idbuspro_vp');
|
||||
$room->label = $roomNode->attr('zimmertext');
|
||||
$room->minPax = (int) $roomNode->attr('MinPax');
|
||||
$room->maxPax = (int) $roomNode->attr('MaxPax');
|
||||
$room->nights = (int) $roomNode->attr('naechte');
|
||||
$room->price = $roomNode->attr('preis') ?
|
||||
$this->stringToFloat($roomNode->attr('preis')) : null;
|
||||
$room->status = $this->getStringOrNullValue($roomNode->filterXPath('//status'));
|
||||
$room->available = (int) $roomNode->attr('verfuegbar');
|
||||
|
||||
$rooms[$roomId] = $room;
|
||||
});
|
||||
|
||||
return $rooms;
|
||||
}
|
||||
|
||||
public function patchMutability(Travel $travel, BaseData $mutableData): void
|
||||
{
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_ADDITIONAL_SERVICES)) {
|
||||
$travel->additionalServicesMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_TRANSPORTATION)) {
|
||||
$travel->transportationServicesMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_PICKUP)) {
|
||||
$travel->pickupsMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_ACCOMMODATION)) {
|
||||
$travel->roomsMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_PARTICIPANT_COUNT)) {
|
||||
$travel->participantCountMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_PARTICIPANT_DATA)) {
|
||||
$travel->participantDataMutable = $item->mutable;
|
||||
}
|
||||
}
|
||||
|
||||
public function patchAvailabilities(Travel $travel, BaseData $availabilities): void
|
||||
{
|
||||
$serviceAvailabilities = $availabilities->getItems();
|
||||
|
||||
foreach ([...$travel->additionalServices, ...$travel->transportationServices] as $service) {
|
||||
if (array_key_exists($service->id, $serviceAvailabilities)) {
|
||||
$service->available = $serviceAvailabilities[$service->id]->available;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function patchBookings(BaseData $bookings): void
|
||||
{
|
||||
foreach ($bookings->getItems() as $booking) {
|
||||
if (null === $travelId = $booking->travelId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$booking->travelData = $this->loadById($travelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,338 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlLoader;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\CrmSelection;
|
||||
use App\BusProNet\Model\CrmSelectionGroup;
|
||||
use App\BusProNet\Model\Guide;
|
||||
use App\BusProNet\Model\MutableData;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use App\BusProNet\Model\Room;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
|
||||
class TravelXmlLoader extends AbstractXmlLoader
|
||||
{
|
||||
public function __construct(
|
||||
private readonly HotelXmlLoader $hotelDataLoader,
|
||||
CacheInterface $cache,
|
||||
?string $xmlPath = null
|
||||
) {
|
||||
parent::__construct($cache, $xmlPath);
|
||||
}
|
||||
|
||||
public function generateFilesMap(): array
|
||||
{
|
||||
return $this->cache->get('bpn_travels_mapping', function (ItemInterface $item) {
|
||||
$item->expiresAfter(3600);
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->files()->in($this->xmlPath)->name('Ziel_*.xml');
|
||||
|
||||
$mapping = [];
|
||||
$hotels = $this->hotelDataLoader->loadAll();
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$xml = simplexml_load_file($file->getRealPath());
|
||||
|
||||
foreach ($xml->reise->termin as $travelXml) {
|
||||
$attributes = $travelXml->attributes();
|
||||
|
||||
$travelId = (int) $attributes['idbuspro'];
|
||||
|
||||
$mapping[$travelId] = [
|
||||
'id' => (int) $attributes['idbuspro'],
|
||||
'code' => (string) $attributes['code'],
|
||||
'label' => (string) $travelXml->text,
|
||||
'dateFrom' => $this->stringToDate((string) $attributes['termin']),
|
||||
'dateTo' => $this->stringToDate((string) $attributes['bis']),
|
||||
'hotels' => [],
|
||||
'file' => $file->getRealPath(),
|
||||
];
|
||||
|
||||
foreach ($travelXml->hotel as $hotelXml) {
|
||||
$hotelId = (int) $hotelXml->attributes()['idbuspro'];
|
||||
|
||||
$mapping[$travelId]['hotels'][$hotelId] = [
|
||||
'id' => $hotelId,
|
||||
'code' => (string) $hotelXml->attributes()['code'],
|
||||
'label' => $hotels[$hotelId]->name,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
});
|
||||
}
|
||||
|
||||
public function mapCodeToId(string $travelCode): ?int
|
||||
{
|
||||
$mapping = $this->generateFilesMap();
|
||||
|
||||
$travelCodes = array_column($mapping, 'code', 'id');
|
||||
|
||||
if (false === $travelId = array_search($travelCode, $travelCodes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travelId;
|
||||
}
|
||||
|
||||
public function loadById(int $travelId, ?int $hotelId = null, ?string $filename = null): ?Travel
|
||||
{
|
||||
if (null !== $filename) {
|
||||
return $this->loadXml($travelId, $hotelId, $filename);
|
||||
}
|
||||
|
||||
$mapping = $this->generateFilesMap();
|
||||
|
||||
if (false === isset($mapping[$travelId])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$filename = $mapping[$travelId]['file'];
|
||||
|
||||
return $this->loadXml($travelId, $hotelId, $filename);
|
||||
}
|
||||
|
||||
private function loadXml(int $id, ?int $hotelId, string $filename): ?Travel
|
||||
{
|
||||
$xml = simplexml_load_file($filename);
|
||||
|
||||
$travelXml = $xml->xpath(sprintf('//reise/termin[@idbuspro="%d"]', $id));
|
||||
|
||||
if (0 === count($travelXml)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->parseXml($travelXml[0], $hotelId);
|
||||
}
|
||||
|
||||
public function parseXml(\SimpleXMLElement $xml, ?int $hotelId): Travel
|
||||
{
|
||||
$attributes = $xml->attributes();
|
||||
$hotelXml = $this->getHotelXml($xml, $hotelId);
|
||||
|
||||
$travel = new Travel();
|
||||
$travel->id = (int) $attributes['idbuspro'];
|
||||
$travel->hotelId = $hotelId;
|
||||
$travel->label = (string) $xml->text;
|
||||
$travel->dateFrom = $this->stringToDate((string) $attributes['termin']);
|
||||
$travel->dateTo = $this->stringToDate((string) $attributes['bis']);
|
||||
$travel->code = (string) $attributes['code'];
|
||||
$travel->type = (string) $attributes['reiseart'];
|
||||
$travel->priceFrom = $this->stringToFloat((string) $xml->abpreis);
|
||||
$travel->selectionGroups = $this->getSelectionGroups($xml);
|
||||
$travel->additionalServices = $this->getAdditionalServices($xml);
|
||||
$travel->transportationServices = $this->getTransportationServices($xml);
|
||||
$travel->rooms = $this->getRooms($hotelXml);
|
||||
$travel->pickups = $this->getPickups($xml);
|
||||
|
||||
return $travel;
|
||||
}
|
||||
|
||||
public function getSelectionGroups(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$selectionGroups = [];
|
||||
|
||||
foreach ($xml->selektiongruppe as $item) {
|
||||
$groupId = (int) $item->attributes()['idbuspro'];
|
||||
$selectionGroup = new CrmSelectionGroup();
|
||||
$selectionGroup->id = $groupId;
|
||||
$selectionGroup->label = (string) $item->attributes()['bezeichnung'];
|
||||
|
||||
foreach ($item->selektion as $subItem) {
|
||||
$selectionId = (int) $subItem->attributes()['idbuspro'];
|
||||
$selection = new CrmSelection();
|
||||
$selection->id = $selectionId;
|
||||
$selection->label = (string) $subItem->attributes()['bezeichnung'];
|
||||
$selectionGroups[$groupId]['selections'][$selectionId] = (string) $subItem->attributes()['bezeichnung'];
|
||||
$selectionGroup->selections[] = $selection;
|
||||
}
|
||||
|
||||
$selectionGroups[$groupId] = $selectionGroup;
|
||||
}
|
||||
|
||||
return $selectionGroups;
|
||||
}
|
||||
|
||||
public function getAdditionalServices(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$additionalServices = [];
|
||||
|
||||
foreach ($xml->lei_sonstiges->leistung as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$serviceId = (int) $attributes['idbuspro'];
|
||||
|
||||
$service = new Service();
|
||||
$service->source = Service::SOURCE_TRAVEL;
|
||||
$service->category = Service::CATEGORY_ADDITIONAL;
|
||||
$service->id = $serviceId;
|
||||
$service->subType = (string) $attributes['unterart'];
|
||||
$service->mandatory = $this->stringToBool((string) $attributes['pflicht']);
|
||||
$service->dateFrom = $this->stringToDate((string) $attributes['termin']);
|
||||
$service->dateTo = $this->stringToDate((string) $attributes['bis']);
|
||||
$service->label = (string) $item->text;
|
||||
$service->price = $this->stringToFloat((string) $item->preis);
|
||||
$service->status = (string) $item->status;
|
||||
|
||||
$additionalServices[$serviceId] = $service;
|
||||
}
|
||||
|
||||
return $additionalServices;
|
||||
}
|
||||
|
||||
public function getGuideForTransportationService(\SimpleXMLElement $xmlTransportationService): ?Guide
|
||||
{
|
||||
if (null === $xmlTransportationService->reiseleiter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$guide = new Guide();
|
||||
$guide->name = $xmlTransportationService->reiseleiter->name;
|
||||
$guide->phone = $xmlTransportationService->reiseleiter->telefon;
|
||||
|
||||
return $guide;
|
||||
}
|
||||
|
||||
public function getTransportationServices(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$transportationServices = [];
|
||||
|
||||
foreach ($xml->lei_befoerderung->leistung as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$serviceId = (int) $attributes['idbuspro'];
|
||||
|
||||
$service = new Service();
|
||||
$service->source = Service::SOURCE_TRAVEL;
|
||||
$service->category = Service::CATEGORY_TRANSPORTATION;
|
||||
$service->id = $serviceId;
|
||||
$service->subType = (string) $attributes['unterart'];
|
||||
$service->dateFrom = $this->stringToDate((string) $attributes['termin']);
|
||||
$service->dateTo = $this->stringToDate((string) $attributes['bis']);
|
||||
$service->label = (string) $item->text;
|
||||
$service->price = $this->stringToFloat((string) $item->preis);
|
||||
$service->direction = (string) $item->richtung;
|
||||
|
||||
$transportationServices[$serviceId] = $service;
|
||||
}
|
||||
|
||||
return $transportationServices;
|
||||
}
|
||||
|
||||
public function getPickups(\SimpleXMLElement $xml): array
|
||||
{
|
||||
$pickups = [];
|
||||
|
||||
foreach ($xml->zustiege->zustieg as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$pickupId = (int) $attributes['idbuspro'];
|
||||
|
||||
$pickup = new Pickup();
|
||||
$pickup->id = $pickupId;
|
||||
$pickup->time = $this->stringToDateTime((string) $attributes['zeit']);
|
||||
$pickup->price = $attributes['preis'] ? $this->stringToFloat((string) $attributes['preis']) : null;
|
||||
|
||||
$pickups[$pickupId] = $pickup;
|
||||
}
|
||||
|
||||
return $pickups;
|
||||
}
|
||||
|
||||
public function getHotelXml(\SimpleXMLElement $xml, ?int $hotelId): ?\SimpleXMLElement
|
||||
{
|
||||
// In case not hotel id is provided, take the first hotel node (which is most probably the only one)
|
||||
if (null === $hotelId) {
|
||||
return $xml->hotel;
|
||||
}
|
||||
|
||||
$hotelXml = $xml->xpath(sprintf('//hotel[@idbuspro="%d"]', $hotelId));
|
||||
|
||||
return $hotelXml[0] ?? null;
|
||||
}
|
||||
|
||||
public function getRooms(\SimpleXMLElement $xml): array
|
||||
{
|
||||
if (false === isset($xml->zimmer)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rooms = [];
|
||||
|
||||
foreach ($xml->zimmer->preis as $item) {
|
||||
$attributes = $item->attributes();
|
||||
$roomId = (int) $attributes['idbuspro_zimmer'];
|
||||
|
||||
$room = new Room();
|
||||
$room->id = $roomId;
|
||||
$room->code = (string) $attributes['zimmercode'];
|
||||
$room->category = (string) $attributes['kat'];
|
||||
$room->boardId = (int) $attributes['idbuspro_vp'];
|
||||
$room->label = (string) $attributes['zimmertext'];
|
||||
$room->minPax = (int) $attributes['MinPax'];
|
||||
$room->maxPax = (int) $attributes['MaxPax'];
|
||||
$room->nights = (int) $attributes['naechte'];
|
||||
$room->price = $attributes['preis'] ? $this->stringToFloat((string) $attributes['preis']) : null;
|
||||
$room->status = (string) $item->status;
|
||||
$room->available = (int) $attributes['verfuegbar'];
|
||||
|
||||
$rooms[$roomId] = $room;
|
||||
}
|
||||
|
||||
return $rooms;
|
||||
}
|
||||
|
||||
public function patchMutability(Travel $travel, BaseData $mutableData): void
|
||||
{
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_ADDITIONAL_SERVICES)) {
|
||||
$travel->additionalServicesMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_TRANSPORTATION)) {
|
||||
$travel->transportationServicesMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_PICKUP)) {
|
||||
$travel->pickupsMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_ACCOMMODATION)) {
|
||||
$travel->roomsMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_PARTICIPANT_COUNT)) {
|
||||
$travel->participantCountMutable = $item->mutable;
|
||||
}
|
||||
|
||||
if (null !== $item = $mutableData->getItemByKey(MutableData::CATEGORY_PARTICIPANT_DATA)) {
|
||||
$travel->participantDataMutable = $item->mutable;
|
||||
}
|
||||
}
|
||||
|
||||
public function patchAvailabilities(Travel $travel, BaseData $availabilities): void
|
||||
{
|
||||
$serviceAvailabilities = $availabilities->getItems();
|
||||
|
||||
foreach ([...$travel->additionalServices, ...$travel->transportationServices] as $service) {
|
||||
if (array_key_exists($service->id, $serviceAvailabilities)) {
|
||||
$service->available = $serviceAvailabilities[$service->id]->available;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function patchBookings(BaseData $bookings): void
|
||||
{
|
||||
foreach ($bookings->getItems() as $booking) {
|
||||
if (null === $travelId = $booking->travelId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$booking->travelData = $this->loadById($travelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
abstract class AbstractParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
protected function getStringOrNullValue(Crawler $node): ?string
|
||||
{
|
||||
return 0 < $node->count() ? $node->text() : null;
|
||||
}
|
||||
|
||||
protected function getIntOrNullValue(Crawler $node): ?int
|
||||
{
|
||||
return 0 < $node->count() ? (int) $node->text() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\Exception\ResponseParserException;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class ApiResponseParser extends AbstractParser
|
||||
{
|
||||
/**
|
||||
* @throws ResponseParserException
|
||||
*/
|
||||
public function parseXmlString(string $type, string $xml): mixed
|
||||
{
|
||||
$crawler = new Crawler($xml);
|
||||
|
||||
if (0 === $crawler->count()) {
|
||||
throw new ResponseParserException('Empty response received from server');
|
||||
}
|
||||
|
||||
// Override type when present in XML to catch error responses
|
||||
$responseType = $this
|
||||
->getStringOrNullValue($crawler->filterXPath('//ergebnis/satz/@typ')) ?? $type;
|
||||
|
||||
$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();
|
||||
|
||||
switch ($subType) {
|
||||
case 'Adressdaten':
|
||||
case 'Adressdaten_Ändern':
|
||||
case 'Newsletter':
|
||||
return (new PersonalDataParser())->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())->parse($resultNode);
|
||||
case ApiClient::TYPE_BOOKING_UPDATE:
|
||||
return (new BookingUpdateParser())->parse($resultNode);
|
||||
}
|
||||
|
||||
throw new ResponseParserException('Unable to parse XML response');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Availability;
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class AvailabilitiesParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): BaseData
|
||||
{
|
||||
$availabilities = [];
|
||||
|
||||
$result
|
||||
->filterXPath('//leistungen/leistung')
|
||||
->each(function (Crawler $node) use (&$availabilities) {
|
||||
$availability = new Availability();
|
||||
$availability->serviceId = (int) $node->attr('id');
|
||||
$availability->status = $node->attr('status');
|
||||
$availability->available = (int) $node->attr('frei');
|
||||
$availability->price = $this->stringToFloat($node->attr('preis'));
|
||||
|
||||
$availabilities[$availability->serviceId] = $availability;
|
||||
})
|
||||
;
|
||||
|
||||
return new BaseData($availabilities);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Address;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\Communication;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\BusProNet\Model\Service;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class BookingParser extends AbstractParser
|
||||
{
|
||||
private readonly ServicesParser $servicesParser;
|
||||
private readonly RoomsParser $roomsParser;
|
||||
private readonly PickupsParser $pickupsParser;
|
||||
private readonly SurchargesParser $surchargesParser;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->servicesParser = new ServicesParser();
|
||||
$this->roomsParser = new RoomsParser();
|
||||
$this->pickupsParser = new PickupsParser();
|
||||
$this->surchargesParser = new SurchargesParser();
|
||||
}
|
||||
|
||||
public function parse(Crawler $node): Booking
|
||||
{
|
||||
$booking = new Booking();
|
||||
|
||||
$booking->id = $this->getIntOrNullValue($node->filterXPath('//idbuchung'));
|
||||
$booking->agencyId = $this->getIntOrNullValue($node->filterXPath('//idagentur'));
|
||||
$booking->bookingNumber = $this->getIntOrNullValue($node->filterXPath('//vorgang'));
|
||||
$booking->invoiceNumber = $this->getIntOrNullValue($node->filterXPath('//zahlungsdaten/rechnung'));
|
||||
$booking->totalPrice = $this
|
||||
->stringToFloat($this->getStringOrNullValue($node->filterXPath('//zahlungsdaten/gesamtbetrag')));
|
||||
$booking->status = $this->getStringOrNullValue($node->filterXPath('//status'));
|
||||
|
||||
$travelData = $node->filterXPath('//reise');
|
||||
|
||||
$booking->travel = $travelData->attr('bezeichnung');
|
||||
$booking->travelId = $this->getIntOrNullValue($node->filterXPath('//idreise'));
|
||||
$booking->travelCode = $travelData->attr('code');
|
||||
$booking->travelDate = $this->stringToDate($travelData->attr('termin'));
|
||||
|
||||
$booking->hotelId = $this->getIntOrNullValue($node->filterXPath('//idpartner'));
|
||||
$booking->hotelName = $this->getStringOrNullValue($node->filterXPath('//partner'));
|
||||
|
||||
$booking->applicant = $this->parsePersonalData($node->filterXPath('//anmelder'));
|
||||
|
||||
$participantsStatus = $this
|
||||
->stringToArray($this->getStringOrNullValue($node->filterXPath('//status_teilnehmer')), '/');
|
||||
$booking->participantsStatus = array_combine(range(1, count($participantsStatus)), $participantsStatus);
|
||||
|
||||
$booking->participants = $this->parseParticipants($node->filterXPath('//teilnehmerliste/teilnehmer'));
|
||||
|
||||
$paymentData = $node->filterXPath('//zahlung');
|
||||
$booking->paymentId = (int) $paymentData->attr('idzahlungsart');
|
||||
$booking->paymentLabel = $paymentData->attr('bezeichnung');
|
||||
$booking->paymentType = $paymentData->attr('art');
|
||||
|
||||
$transportationData = $node->filterXPath('//beförderungen/beförderung');
|
||||
if (0 < $transportationData->count()) {
|
||||
$booking->transportationServices = $this
|
||||
->servicesParser
|
||||
->parse($transportationData, Service::CATEGORY_TRANSPORTATION, Service::SOURCE_BOOKING);
|
||||
}
|
||||
|
||||
$additionalServicesData = $node->filterXPath('//zusatzleistungen/zusatzleistung');
|
||||
if (0 < $additionalServicesData->count()) {
|
||||
$booking->additionalServices = $this
|
||||
->servicesParser
|
||||
->parse($additionalServicesData, Service::CATEGORY_ADDITIONAL, Service::SOURCE_BOOKING);
|
||||
}
|
||||
|
||||
$roomsData = $node->filterXPath('//ferienzielunterbringungen/ferienzielunterbringung');
|
||||
if (0 < $roomsData->count()) {
|
||||
$booking->rooms = $this->roomsParser->parse($roomsData);
|
||||
}
|
||||
|
||||
$pickupsData = $node->filterXPath('//zustiege/zustieg');
|
||||
if (0 < $pickupsData->count()) {
|
||||
$booking->pickups = $this->pickupsParser->parse($pickupsData);
|
||||
}
|
||||
|
||||
$surchargesData = $node->filterXPath('//zuschlaege/zuschlag');
|
||||
if (0 < $surchargesData->count()) {
|
||||
$booking->surcharges = $this->surchargesParser->parse($surchargesData);
|
||||
}
|
||||
|
||||
return $booking;
|
||||
}
|
||||
|
||||
private function parseParticipants(Crawler $node): array
|
||||
{
|
||||
$participants = [];
|
||||
|
||||
$node->each(function (Crawler $node) use (&$participants) {
|
||||
$id = (int) $node->attr('id');
|
||||
$participants[$id] = $this->parsePersonalData($node);
|
||||
});
|
||||
|
||||
return $participants;
|
||||
}
|
||||
|
||||
private function parsePersonalData(Crawler $node): PersonalData
|
||||
{
|
||||
$personalData = new PersonalData();
|
||||
|
||||
$personalData->addressId = $this->getIntOrNullValue($node->filterXPath('//idadresse'));
|
||||
$personalData->personId = $this->getIntOrNullValue($node->filterXPath('//idadresseperson'));
|
||||
|
||||
$dateString = $this->getStringOrNullValue($node->filterXPath('//geburtsdatum'));
|
||||
$personalData->dateOfBirth = null !== $dateString
|
||||
? \DateTimeImmutable::createFromFormat('d.m.Y', $dateString) : null;
|
||||
|
||||
$personalData->firstName = $this->getStringOrNullValue($node->filterXPath('//vorname'));
|
||||
$personalData->name = $this->getStringOrNullValue($node->filterXPath('//name'));
|
||||
$personalData->salutation = $this->getStringOrNullValue($node->filterXPath('//anrede'));
|
||||
$personalData->title = $this->getStringOrNullValue($node->filterXPath('//titel'));
|
||||
$genderValue = $this->getStringOrNullValue($node->filterXPath('//geschlecht'));
|
||||
$personalData->gender = null !== $genderValue ? strtoupper($genderValue) : null;
|
||||
|
||||
$personalData->height = $this->getStringOrNullValue($node->filterXPath('//sonstiges1'));
|
||||
$personalData->weight = $this->getStringOrNullValue($node->filterXPath('//sonstiges2'));
|
||||
$personalData->shoeSize = $this->getStringOrNullValue($node->filterXPath('//sonstiges3'));
|
||||
|
||||
$addressNode = $node->filterXPath('//anschrift');
|
||||
|
||||
if (0 < $addressNode->count()) {
|
||||
$address = new Address();
|
||||
$address->street = $this->getStringOrNullValue($addressNode->filterXPath('//strasse'));
|
||||
$address->postCode = $this->getStringOrNullValue($addressNode->filterXPath('//plz'));
|
||||
$address->city = $this->getStringOrNullValue($addressNode->filterXPath('//ort'));
|
||||
$address->country = $this->getStringOrNullValue($addressNode->filterXPath('//land'));
|
||||
|
||||
$personalData->address = $address;
|
||||
}
|
||||
|
||||
$contactNode = $node->filterXPath('//kommunikation');
|
||||
|
||||
if (0 < $contactNode->count()) {
|
||||
$communication = new Communication();
|
||||
$communication->phone = $this->getStringOrNullValue($contactNode->filterXPath('//telefonprivat'));
|
||||
$communication->mobile = $this->getStringOrNullValue($contactNode->filterXPath('//telefonmobil'));
|
||||
$communication->email = $this->getStringOrNullValue($contactNode->filterXPath('//email'));
|
||||
$communication->newsletter = $this
|
||||
->stringToBool($contactNode->filterXPath('//newsletter')->text('False'));
|
||||
|
||||
$personalData->communication = $communication;
|
||||
}
|
||||
|
||||
return $personalData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\BookingUpdate;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class BookingUpdateParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $node): BookingUpdate
|
||||
{
|
||||
$bookingUpdate = new BookingUpdate();
|
||||
$bookingUpdate->valid = 'möglich' === $node->filterXPath('//aenderung')->text();
|
||||
$bookingUpdate->totalPrice = $this->stringToFloat($node->filterXPath('//gesamtpreis')->text());
|
||||
|
||||
return $bookingUpdate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class BookingsParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): BaseData
|
||||
{
|
||||
$bookings = [];
|
||||
$items = $result->filterXPath('//vorgaenge/vorgang');
|
||||
|
||||
if (0 === $items->count()) {
|
||||
return new BaseData($bookings);
|
||||
}
|
||||
|
||||
$items->each(function (Crawler $node) use (&$bookings) {
|
||||
$booking = new Booking();
|
||||
|
||||
$booking->id = $this->getIntOrNullValue($node->filterXPath('//id'));
|
||||
$booking->bookingNumber = $this->getIntOrNullValue($node->filterXPath('//vorgangsnummer'));
|
||||
$booking->status = $this->getStringOrNullValue($node->filterXPath('//status'));
|
||||
$booking->participantCount = $this->getIntOrNullValue($node->filterXPath('//personen'));
|
||||
$booking->price = $this->stringToFloat($this->getStringOrNullValue($node->filterXPath('//preis')));
|
||||
$booking->bookingDate = $this
|
||||
->stringToDateTime($this->getStringOrNullValue($node->filterXPath('//buchungsdatum')));
|
||||
$booking->travel = $this->getStringOrNullValue($node->filterXPath('//reise'));
|
||||
$booking->travelId = $this->getIntOrNullValue($node->filterXPath('//idreise'));
|
||||
$booking->travelDate = $this
|
||||
->stringToDate($this->getStringOrNullValue($node->filterXPath('//reisedatum')));
|
||||
$booking->document = $this
|
||||
->stringToBool($this->getStringOrNullValue($node->filterXPath('//reisedokument')));
|
||||
$booking->payment = $this
|
||||
->stringToFloat($this->getStringOrNullValue($node->filterXPath('//zahlung')));
|
||||
|
||||
$bookings[] = $booking;
|
||||
});
|
||||
|
||||
return new BaseData($bookings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\Country;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class CountriesParser
|
||||
{
|
||||
public function parse(Crawler $result): BaseData
|
||||
{
|
||||
$countries = [];
|
||||
|
||||
$result
|
||||
->filterXPath('//laender/land')
|
||||
->each(function (Crawler $node) use (&$countries) {
|
||||
$country = new Country();
|
||||
$country->id = (int) $node->attr('id');
|
||||
$country->name = $node->attr('bezeichnung');
|
||||
$country->token = $node->attr('kuerzel');
|
||||
$country->nationality = $node->attr('nationalitaet');
|
||||
|
||||
$countries[$country->token] = $country;
|
||||
})
|
||||
;
|
||||
|
||||
return new BaseData($countries);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\CrmAction;
|
||||
use App\BusProNet\Model\CrmAttributes;
|
||||
use App\BusProNet\Model\CrmSelection;
|
||||
use App\BusProNet\Model\CrmSelectionGroup;
|
||||
use App\BusProNet\TypeConversionTrait;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class CrmAttributesResponseParser
|
||||
{
|
||||
use TypeConversionTrait;
|
||||
|
||||
private const BPN_CRM_ID_ADMIN = 1292;
|
||||
private const BPN_CRM_ID_MANAGER = 1293;
|
||||
private const BPN_CRM_ID_TEAMER = 1070;
|
||||
|
||||
public function parse(Crawler $result): CrmAttributes
|
||||
{
|
||||
$groups = [];
|
||||
$actions = [];
|
||||
$roles = [];
|
||||
$hotelCode = null;
|
||||
|
||||
$result
|
||||
->filterXPath('//selektionsmerkmale/selektionsgruppe')
|
||||
->each(function (Crawler $node) use (&$groups, &$roles, &$hotelCode) {
|
||||
$group = new CrmSelectionGroup();
|
||||
$group->id = (int) $node->attr('id');
|
||||
$group->label = $node->attr('bezeichnung');
|
||||
|
||||
$attributes = [];
|
||||
|
||||
$node
|
||||
->filterXPath('//selektion')
|
||||
->each(function (Crawler $node) use (&$attributes, &$roles, &$hotelCode) {
|
||||
$attribute = new CrmSelection();
|
||||
$attribute->id = (int) $node->attr('id');
|
||||
$attribute->label = $node->attr('bezeichnung');
|
||||
$attribute->mutable = $this->stringToBool($node->attr('aenderbar'));
|
||||
$attribute->selected = $this->stringToBool($node->attr('auswahl'));
|
||||
|
||||
if (1 === preg_match('/^Hausleitung ([A-Z0-9]+)$/', $attribute->label, $matches) && true === $attribute->selected) {
|
||||
$roles[] = 'ROLE_HOUSE_MANAGER';
|
||||
$hotelCode = $matches[1];
|
||||
}
|
||||
if (static::BPN_CRM_ID_ADMIN === $attribute->id && true === $attribute->selected) {
|
||||
$roles[] = 'ROLE_ADMIN';
|
||||
}
|
||||
if (static::BPN_CRM_ID_MANAGER === $attribute->id && true === $attribute->selected) {
|
||||
$roles[] = 'ROLE_MANAGER';
|
||||
}
|
||||
if (static::BPN_CRM_ID_TEAMER === $attribute->id && true === $attribute->selected) {
|
||||
$roles[] = 'ROLE_TEAMER';
|
||||
}
|
||||
|
||||
$attributes[] = $attribute;
|
||||
})
|
||||
;
|
||||
|
||||
$group->selections = $attributes;
|
||||
$groups[] = $group;
|
||||
})
|
||||
;
|
||||
|
||||
$result
|
||||
->filterXPath('//crmaktionen/crmaktion')
|
||||
->each(function (Crawler $node) use (&$actions) {
|
||||
$crmAction = new CrmAction();
|
||||
|
||||
$crmAction->id = (int) $node->attr('id');
|
||||
$crmAction->code = $node->attr('code');
|
||||
$crmAction->label = $node->attr('bezeichnung');
|
||||
$crmAction->mutable = $this->stringToBool($node->attr('aenderbar'));
|
||||
$crmAction->selected = $this->stringToBool($node->attr('auswahl'));
|
||||
|
||||
$actions[] = $crmAction;
|
||||
})
|
||||
;
|
||||
|
||||
$response = new CrmAttributes();
|
||||
$response->selectionGroups = $groups;
|
||||
$response->crmActions = $actions;
|
||||
$response->roles = $roles;
|
||||
$response->admin = in_array('ROLE_ADMIN', $roles);
|
||||
$response->manager = in_array('ROLE_MANAGER', $roles);
|
||||
$response->houseManager = in_array('ROLE_HOUSE_MANAGER', $roles);
|
||||
$response->teamer = in_array('ROLE_TEAMER', $roles);
|
||||
$response->hotelCode = $hotelCode;
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\File;
|
||||
use PhpZip\Exception\ZipException;
|
||||
use PhpZip\ZipFile;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class DocumentsParser
|
||||
{
|
||||
public function parseConfirmation(Crawler $result): ?File
|
||||
{
|
||||
$pdfData = $this->decode($result->filterXPath('//bestaetigungpdf'));
|
||||
|
||||
return new File('bestaetigung.pdf', $pdfData, 'application/pdf');
|
||||
}
|
||||
|
||||
public function parseDocuments(Crawler $result): ?File
|
||||
{
|
||||
$documents = $result->filterXPath('//reisedokumente/reisedokument');
|
||||
|
||||
if (1 === $documents->count()) {
|
||||
$node = $documents->first();
|
||||
[$filename, $pdfData] = $this->getFileInfo($node);
|
||||
|
||||
return new File($filename.'.pdf', $pdfData, 'application/pdf');
|
||||
}
|
||||
|
||||
// In case of multiple documents create ZIP file
|
||||
try {
|
||||
$zip = new ZipFile();
|
||||
|
||||
$documents->each(function (Crawler $node) use (&$zip) {
|
||||
[$filename, $pdfData] = $this->getFileInfo($node);
|
||||
$zip->addFromString($filename.'.pdf', $pdfData);
|
||||
});
|
||||
|
||||
return new File('reisedokumente.zip', $zip->outputAsString(), 'application/zip');
|
||||
}
|
||||
catch (ZipException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function decode(Crawler $node): string
|
||||
{
|
||||
[, $pdfData] = explode(',', $node->text());
|
||||
|
||||
return base64_decode($pdfData);
|
||||
}
|
||||
|
||||
private function getFileInfo(Crawler $node): array
|
||||
{
|
||||
$pdfData = $this->decode($node->filterXPath('//pdf'));
|
||||
$filename = $node->filterXPath('//datei')->text();
|
||||
|
||||
return [$filename, $pdfData];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\BaseData;
|
||||
use App\BusProNet\Model\MutableData;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class MutableDataParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): BaseData
|
||||
{
|
||||
$mutableFields = [];
|
||||
|
||||
$result
|
||||
->filterXPath('//änderungen/änderung')
|
||||
->each(function (Crawler $node) use (&$mutableFields) {
|
||||
$category = match ($node->attr('art')) {
|
||||
'anzahl_teilnehmer' => MutableData::CATEGORY_PARTICIPANT_COUNT,
|
||||
'beförderung' => MutableData::CATEGORY_TRANSPORTATION,
|
||||
'zustieg' => MutableData::CATEGORY_PICKUP,
|
||||
'unterbringung' => MutableData::CATEGORY_ACCOMMODATION,
|
||||
'zusatzleistung' => MutableData::CATEGORY_ADDITIONAL_SERVICES,
|
||||
'teilnehmerdaten' => MutableData::CATEGORY_PARTICIPANT_DATA,
|
||||
default => null,
|
||||
};
|
||||
|
||||
if (null !== $category) {
|
||||
$mutableField = new MutableData($category, $this->stringToBool($node->attr('möglich')));
|
||||
|
||||
if (null !== $until = $node->attr('möglichbiszum')) {
|
||||
$mutableField->mutableBefore = $this->stringToDate($until);
|
||||
}
|
||||
|
||||
$mutableFields[$category] = $mutableField;
|
||||
}
|
||||
})
|
||||
;
|
||||
|
||||
return new BaseData($mutableFields);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Notification;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class NotificationParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): Notification
|
||||
{
|
||||
$number = $this->getIntOrNullValue($result->filterXPath('//satz/nr'));
|
||||
$text = $this->getStringOrNullValue($result->filterXPath('//satz/text'));
|
||||
|
||||
return new Notification($number, $text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Address;
|
||||
use App\BusProNet\Model\Communication;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use voku\helper\AntiXSS;
|
||||
|
||||
class PersonalDataParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $node): PersonalData
|
||||
{
|
||||
$personalData = new PersonalData();
|
||||
|
||||
$personalData->addressId = $this->getIntOrNullValue($node->filterXPath('//idadresse'));
|
||||
$personalData->personId = $this->getIntOrNullValue($node->filterXPath('//idperson'));
|
||||
|
||||
$addressDataNode = $node->filterXPath('//adressdaten');
|
||||
|
||||
$dateString = $this->getStringOrNullValue($addressDataNode->filterXPath('//geburtsdatum'));
|
||||
$personalData->dateOfBirth = null !== $dateString ?
|
||||
\DateTimeImmutable::createFromFormat('d.m.Y', $dateString) : null;
|
||||
|
||||
$personalData->firstName = $this->getStringOrNullValue($addressDataNode->filterXPath('//vorname'));
|
||||
$personalData->name = $this->getStringOrNullValue($addressDataNode->filterXPath('//name'));
|
||||
$personalData->salutation = $this->getStringOrNullValue($addressDataNode->filterXPath('//anrede'));
|
||||
$personalData->title = $this->getStringOrNullValue($addressDataNode->filterXPath('//titel'));
|
||||
$personalData->gender = strtoupper($this->getStringOrNullValue($addressDataNode->filterXPath('//geschlecht')));
|
||||
|
||||
$personalData->height = $this->getStringOrNullValue($addressDataNode->filterXPath('//sonstiges1'));
|
||||
$personalData->weight = $this->getStringOrNullValue($addressDataNode->filterXPath('//sonstiges2'));
|
||||
$personalData->shoeSize = $this->getStringOrNullValue($addressDataNode->filterXPath('//sonstiges3'));
|
||||
|
||||
$addressNode = $addressDataNode->filterXPath('//anschrift');
|
||||
|
||||
if (0 < $addressNode->count()) {
|
||||
$address = new Address();
|
||||
$address->street = $this->getStringOrNullValue($addressNode->filterXPath('//strasse'));
|
||||
$address->postCode = $this->getStringOrNullValue($addressNode->filterXPath('//plz'));
|
||||
$address->city = $this->getStringOrNullValue($addressNode->filterXPath('//ort')) ;
|
||||
$address->country = $this->getStringOrNullValue($addressNode->filterXPath('//land')) ;
|
||||
|
||||
$personalData->address = $address;
|
||||
}
|
||||
|
||||
$contactDataNode = $addressDataNode->filterXPath('//kommunikation');
|
||||
|
||||
if (0 < $contactDataNode->count()) {
|
||||
$communication = new Communication();
|
||||
$communication->phone = $this->getStringOrNullValue($contactDataNode->filterXPath('//telefonprivat'));
|
||||
$communication->mobile = $this->getStringOrNullValue($contactDataNode->filterXPath('//telefonmobil'));
|
||||
$communication->email = $this->getStringOrNullValue($contactDataNode->filterXPath('//email'));
|
||||
$communication->newsletter = $this
|
||||
->stringToBool($this->getStringOrNullValue($contactDataNode->filterXPath('//newsletter')));
|
||||
|
||||
$personalData->communication = $communication;
|
||||
}
|
||||
|
||||
$remarksNode = $addressDataNode->filterXPath('//bemerkung');
|
||||
|
||||
if (0 < $remarksNode->count()) {
|
||||
$antiXss = new AntiXSS();
|
||||
$personalData->remarks = $antiXss->xss_clean($remarksNode->text());
|
||||
}
|
||||
|
||||
return $personalData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class PickupsParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): array
|
||||
{
|
||||
$pickups = [];
|
||||
|
||||
$result->each(function (Crawler $node) use (&$pickups) {
|
||||
$pickupId = (int) $node->attr('idzustieg');
|
||||
$pickupDate = $node->attr('datum');
|
||||
$pickupTime = $node->attr('zeit');
|
||||
$price = $node->attr('preis') ? $this->stringToFloat($node->attr('preis')) : null;
|
||||
|
||||
$pickup = new Pickup();
|
||||
$pickup->id = $pickupId;
|
||||
$pickup->code = $node->attr('code');
|
||||
$pickup->city = $this->getStringOrNullValue($node->filterXPath('//ort'));
|
||||
$pickup->postalCode = $this->getStringOrNullValue($node->filterXPath('//plz'));
|
||||
$pickup->street = $this->getStringOrNullValue($node->filterXPath('//strasse'));
|
||||
$pickup->time = $this->stringToDateTime($pickupDate.' '.$pickupTime);
|
||||
$pickup->price = $price;
|
||||
$mapping = $this->stringToArray($node->attr('zuordnung'));
|
||||
$pickup->mapping = array_map('intval', $mapping);
|
||||
|
||||
$pickups[$pickupId] = $pickup;
|
||||
});
|
||||
|
||||
return $pickups;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Room;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class RoomsParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): array
|
||||
{
|
||||
$rooms = [];
|
||||
|
||||
$result->each(function (Crawler $node) use (&$rooms) {
|
||||
$room = new Room();
|
||||
$room->id = (int) $node->attr('idzimmer');;
|
||||
$room->label = $node->attr('zimmer');
|
||||
$room->category = $node->attr('kategorie');
|
||||
$room->boardId = (int) $node->attr('idverpflegung');
|
||||
$room->dateFrom = $node->attr('anreise') ?
|
||||
$this->stringToDate($node->attr('anreise')) : null;
|
||||
$room->dateTo = $node->attr('abreise') ?
|
||||
$this->stringToDate($node->attr('abreise')) : null;
|
||||
$room->totalCount = (int) $node->attr('anzahl');
|
||||
$room->minPax = (int) $node->attr('minpax');
|
||||
$room->maxPax = (int) $node->attr('maxpax');
|
||||
$room->board = $node->attr('verpflegung');
|
||||
$mapping = $this->stringToArray($node->attr('zuordnung'));
|
||||
$room->mapping = array_map('intval', $mapping);
|
||||
$room->totalPrice = $this->stringToFloat($node->attr('gesamtpreis'));
|
||||
$individualPrices = array_map(
|
||||
function ($price) {
|
||||
return $this->stringToFloat($price);
|
||||
}, $this->stringToArray($node->attr('einzelpreis', ''), '/')
|
||||
);
|
||||
$room->individualPrice = array_combine($mapping, $individualPrices);
|
||||
|
||||
$rooms[$room->id] = $room;
|
||||
});
|
||||
|
||||
return $rooms;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Service;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class ServicesParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result, string $category, string $source): array
|
||||
{
|
||||
$services = [];
|
||||
|
||||
$result->each(function (Crawler $node) use (&$services, $category, $source) {
|
||||
$service = new Service();
|
||||
$service->id = (int) $node->attr('idleistung');
|
||||
$service->category = $category;
|
||||
$service->source = $source;
|
||||
$service->label = $node->attr('leistung');
|
||||
$service->dateFrom = $node->attr('termin') ?
|
||||
$this->stringToDate($node->attr('termin')) : null;
|
||||
$service->dateTo = $node->attr('terminbis') ?
|
||||
$this->stringToDate($node->attr('terminbis')) : null;
|
||||
$service->subType = $node->attr('unterart');
|
||||
$service->totalCount = $node->attr('anzahl') ? (int) $node->attr('anzahl') : null;
|
||||
$mapping = $this->stringToArray($node->attr('zuordnung'));
|
||||
$service->mapping = array_map('intval', $mapping);
|
||||
$service->totalPrice = $this->stringToFloat($node->attr('gesamtpreis'));
|
||||
$individualPrices = array_map(
|
||||
function ($price) {
|
||||
return $this->stringToFloat($price);
|
||||
}, $this->stringToArray($node->attr('einzelpreis', ''), '/')
|
||||
);
|
||||
$service->individualPrice = array_combine($mapping, $individualPrices);
|
||||
if (Service::CATEGORY_TRANSPORTATION === $category) {
|
||||
$service->direction = $node->attr('richtung');
|
||||
}
|
||||
|
||||
$services[$service->id] = $service;
|
||||
});
|
||||
|
||||
return $services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet\XmlParser;
|
||||
|
||||
use App\BusProNet\Model\Surcharge;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
class SurchargesParser extends AbstractParser
|
||||
{
|
||||
public function parse(Crawler $result): array
|
||||
{
|
||||
$surcharges = [];
|
||||
|
||||
$result->each(function (Crawler $node) use (&$surcharges) {
|
||||
$surcharge = new Surcharge();
|
||||
$surchargeLabel = $node->attr('bezeichnung');
|
||||
$surcharge->label = empty($surchargeLabel) ? 'unbekannt' : $surchargeLabel;
|
||||
$surcharge->totalPrice = $this->stringToFloat($node->attr('gesamtpreis'));
|
||||
$mapping = $this->stringToArray($node->attr('zuordnung'));
|
||||
$surcharge->mapping = array_map('intval', $mapping);
|
||||
$individualPrices = array_map(
|
||||
function ($price) {
|
||||
return $this->stringToFloat($price);
|
||||
}, $this->stringToArray($node->attr('einzelpreis', ''), '/')
|
||||
);
|
||||
$surcharge->individualPrice = array_combine($mapping, $individualPrices);
|
||||
|
||||
$surcharges[] = $surcharge;
|
||||
});
|
||||
|
||||
return $surcharges;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\BusProNet;
|
||||
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
trait XmlParserTrait
|
||||
{
|
||||
protected function getStringOrNullValue(Crawler $node): ?string
|
||||
{
|
||||
return 0 < $node->count() ? $node->text() : null;
|
||||
}
|
||||
|
||||
protected function getIntOrNullValue(Crawler $node): ?int
|
||||
{
|
||||
return 0 < $node->count() ? (int) $node->text() : null;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\BusProNet\XmlLoader\HotelXmlLoader;
|
||||
use App\BusProNet\XmlLoader\HotelLoader;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -11,7 +11,7 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||
#[Route('/api')]
|
||||
class HotelController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly HotelXmlLoader $xmlLoader)
|
||||
public function __construct(private readonly HotelLoader $xmlLoader)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\BusProNet\XmlLoader\PickupXmlLoader;
|
||||
use App\BusProNet\XmlLoader\PickupLoader;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -11,7 +11,7 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||
#[Route('/api')]
|
||||
class PickupController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly PickupXmlLoader $xmlLoader)
|
||||
public function __construct(private readonly PickupLoader $xmlLoader)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
namespace App\Controller\Api;
|
||||
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\XmlLoader\HotelXmlLoader;
|
||||
use App\BusProNet\XmlLoader\PickupXmlLoader;
|
||||
use App\BusProNet\XmlLoader\TravelXmlLoader;
|
||||
use App\BusProNet\XmlLoader\HotelLoader;
|
||||
use App\BusProNet\XmlLoader\PickupLoader;
|
||||
use App\BusProNet\XmlLoader\TravelLoader;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
@@ -18,9 +18,9 @@ use Symfony\Contracts\Cache\ItemInterface;
|
||||
class TravelController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TravelXmlLoader $travelXmlLoader,
|
||||
private readonly HotelXmlLoader $hotelXmlLoader,
|
||||
private readonly PickupXmlLoader $pickupXmlLoader,
|
||||
private readonly TravelLoader $travelXmlLoader,
|
||||
private readonly HotelLoader $hotelXmlLoader,
|
||||
private readonly PickupLoader $pickupXmlLoader,
|
||||
private readonly CacheInterface $cache,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use function Symfony\Component\String\u;
|
||||
@@ -60,7 +61,9 @@ class DownloadController extends AbstractController
|
||||
|
||||
$filename = u($file->filename)->ascii();
|
||||
|
||||
$response = new Response($file->content);
|
||||
$response = new StreamedResponse(function () use ($file) {
|
||||
echo $file->content;
|
||||
});
|
||||
|
||||
$disposition = $response->headers->makeDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Controller\Booking;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\XmlLoader\PickupXmlLoader;
|
||||
use App\BusProNet\XmlLoader\TravelXmlLoader;
|
||||
use App\BusProNet\XmlLoader\PickupLoader;
|
||||
use App\BusProNet\XmlLoader\TravelLoader;
|
||||
use App\Form\BookingType;
|
||||
use App\Form\Model\BookingData;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
@@ -20,11 +20,11 @@ use Symfony\Contracts\Cache\ItemInterface;
|
||||
class EditController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ApiClient $apiClient,
|
||||
private readonly TravelXmlLoader $travelDataLoader,
|
||||
private readonly PickupXmlLoader $pickupDataLoader,
|
||||
private readonly ApiClient $apiClient,
|
||||
private readonly TravelLoader $travelDataLoader,
|
||||
private readonly PickupLoader $pickupDataLoader,
|
||||
private readonly CacheInterface $cache,
|
||||
private readonly Security $security,
|
||||
private readonly Security $security,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class EditController extends AbstractController
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->apiClient->updateBooking($formData, false);
|
||||
$this->apiClient->updateBooking($formData);
|
||||
|
||||
try {
|
||||
$this->cache->delete($cacheKeySingle);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace App\Controller\Booking;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\XmlLoader\TravelXmlLoader;
|
||||
use App\BusProNet\XmlLoader\TravelLoader;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
@@ -17,10 +17,10 @@ use Symfony\Contracts\Cache\ItemInterface;
|
||||
class IndexController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ApiClient $apiClient,
|
||||
private readonly TravelXmlLoader $travelDataLoader,
|
||||
private readonly ApiClient $apiClient,
|
||||
private readonly TravelLoader $travelDataLoader,
|
||||
private readonly CacheInterface $cache,
|
||||
private readonly Security $security,
|
||||
private readonly Security $security,
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
@@ -69,13 +69,11 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{{ path('app_booking_confirmation', { 'id': booking.id }) }}"
|
||||
class="button bg-button button--small"
|
||||
target="_blank">
|
||||
class="button bg-button button--small">
|
||||
Bestätigung
|
||||
</a>
|
||||
<a href="{{ path('app_booking_documents', { 'id': booking.id }) }}"
|
||||
class="button bg-button button--small"
|
||||
target="_blank">
|
||||
class="button bg-button button--small">
|
||||
Reisedokumente
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Tests\BusProNet\DataLoader;
|
||||
|
||||
use App\BusProNet\XmlLoader\HotelXmlLoader;
|
||||
use App\BusProNet\XmlLoader\HotelLoader;
|
||||
use App\BusProNet\Model\Hotel;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@@ -10,7 +10,7 @@ class HotelDataLoaderTest extends TestCase
|
||||
{
|
||||
public function testParse(): void
|
||||
{
|
||||
$loader = new HotelXmlLoader(__DIR__.'/../../Resources');
|
||||
$loader = new HotelLoader(__DIR__.'/../../Resources');
|
||||
$hotelId = 163113;
|
||||
|
||||
$xml = $loader->loadById($hotelId, 'hotels_data.xml');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Tests\BusProNet\DataLoader;
|
||||
|
||||
use App\BusProNet\XmlLoader\PickupXmlLoader;
|
||||
use App\BusProNet\XmlLoader\PickupLoader;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@@ -10,7 +10,7 @@ class PickupDataLoaderTest extends TestCase
|
||||
{
|
||||
public function testParse(): void
|
||||
{
|
||||
$loader = new PickupXmlLoader();
|
||||
$loader = new PickupLoader();
|
||||
$pickupId = 1;
|
||||
|
||||
$xml = $loader->loadById($pickupId, 'pickups_data.xml');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Tests\BusProNet\DataLoader;
|
||||
|
||||
use App\BusProNet\XmlLoader\TravelXmlLoader;
|
||||
use App\BusProNet\XmlLoader\TravelLoader;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@@ -10,7 +10,7 @@ class TravelDataLoaderTest extends TestCase
|
||||
{
|
||||
public function testParse(): void
|
||||
{
|
||||
$loader = new TravelXmlLoader('');
|
||||
$loader = new TravelLoader('');
|
||||
$filename = __DIR__.'/../../Resources/travel_data.xml';
|
||||
$travelId = 11478;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user