diff --git a/composer.json b/composer.json index ba43bff..1a02cba 100644 --- a/composer.json +++ b/composer.json @@ -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", diff --git a/composer.lock b/composer.lock index c567a7f..e0c4d32 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "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": "fabien@symfony.com" + }, + { + "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": "technosophos@gmail.com" - }, - { - "name": "Matt Farina", - "email": "matt@mattfarina.com" - }, - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - } - ], - "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": "fabien@symfony.com" - }, - { - "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" diff --git a/src/BusProNet/ApiClient.php b/src/BusProNet/ApiClient.php index 0676ee0..abda90e 100644 --- a/src/BusProNet/ApiClient.php +++ b/src/BusProNet/ApiClient.php @@ -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, ]; diff --git a/src/BusProNet/ApiResponseParser/AvailabilitiesResponseParser.php b/src/BusProNet/ApiResponseParser/AvailabilitiesResponseParser.php deleted file mode 100644 index b6d2a9e..0000000 --- a/src/BusProNet/ApiResponseParser/AvailabilitiesResponseParser.php +++ /dev/null @@ -1,32 +0,0 @@ -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); - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/BookingResponseParser.php b/src/BusProNet/ApiResponseParser/BookingResponseParser.php deleted file mode 100644 index 8cb8e1d..0000000 --- a/src/BusProNet/ApiResponseParser/BookingResponseParser.php +++ /dev/null @@ -1,255 +0,0 @@ -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; - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/BookingUpdateResponseParser.php b/src/BusProNet/ApiResponseParser/BookingUpdateResponseParser.php deleted file mode 100644 index b860a95..0000000 --- a/src/BusProNet/ApiResponseParser/BookingUpdateResponseParser.php +++ /dev/null @@ -1,20 +0,0 @@ -valid = 'möglich' === (string) $xml->aenderung; - $bookingUpdate->totalPrice = $this->stringToFloat((string) $xml->gesamtpreis); - - return $bookingUpdate; - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/BookingsResponseParser.php b/src/BusProNet/ApiResponseParser/BookingsResponseParser.php deleted file mode 100644 index 2592cd0..0000000 --- a/src/BusProNet/ApiResponseParser/BookingsResponseParser.php +++ /dev/null @@ -1,37 +0,0 @@ -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); - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/CountriesResponseParser.php b/src/BusProNet/ApiResponseParser/CountriesResponseParser.php deleted file mode 100644 index f392979..0000000 --- a/src/BusProNet/ApiResponseParser/CountriesResponseParser.php +++ /dev/null @@ -1,28 +0,0 @@ -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); - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/CrmAttributesResponseParser.php b/src/BusProNet/ApiResponseParser/CrmAttributesResponseParser.php deleted file mode 100644 index 3e69954..0000000 --- a/src/BusProNet/ApiResponseParser/CrmAttributesResponseParser.php +++ /dev/null @@ -1,84 +0,0 @@ -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; - } -} diff --git a/src/BusProNet/ApiResponseParser/DocumentsResponseParser.php b/src/BusProNet/ApiResponseParser/DocumentsResponseParser.php deleted file mode 100644 index b024fde..0000000 --- a/src/BusProNet/ApiResponseParser/DocumentsResponseParser.php +++ /dev/null @@ -1,43 +0,0 @@ -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; - } - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/MutableDataResponseParser.php b/src/BusProNet/ApiResponseParser/MutableDataResponseParser.php deleted file mode 100644 index aee351e..0000000 --- a/src/BusProNet/ApiResponseParser/MutableDataResponseParser.php +++ /dev/null @@ -1,45 +0,0 @@ -ä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); - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/NotificationResponseParser.php b/src/BusProNet/ApiResponseParser/NotificationResponseParser.php deleted file mode 100644 index 29971b8..0000000 --- a/src/BusProNet/ApiResponseParser/NotificationResponseParser.php +++ /dev/null @@ -1,15 +0,0 @@ -satz; - - return new Notification((int) $recordXml->nr, (string) $recordXml->text); - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/PersonalDataResponseParser.php b/src/BusProNet/ApiResponseParser/PersonalDataResponseParser.php deleted file mode 100644 index 2253172..0000000 --- a/src/BusProNet/ApiResponseParser/PersonalDataResponseParser.php +++ /dev/null @@ -1,58 +0,0 @@ -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; - } -} \ No newline at end of file diff --git a/src/BusProNet/ApiResponseParser/ResponseParser.php b/src/BusProNet/ApiResponseParser/ResponseParser.php deleted file mode 100644 index 50df4e7..0000000 --- a/src/BusProNet/ApiResponseParser/ResponseParser.php +++ /dev/null @@ -1,63 +0,0 @@ -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'); - } -} \ No newline at end of file diff --git a/src/BusProNet/DataProvider/CountryDataProvider.php b/src/BusProNet/DataProvider/CountryDataProvider.php index ee999b5..210f02b 100644 --- a/src/BusProNet/DataProvider/CountryDataProvider.php +++ b/src/BusProNet/DataProvider/CountryDataProvider.php @@ -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 diff --git a/src/BusProNet/Model/CrmAttributes.php b/src/BusProNet/Model/CrmAttributes.php index da4ff0f..69bfefe 100644 --- a/src/BusProNet/Model/CrmAttributes.php +++ b/src/BusProNet/Model/CrmAttributes.php @@ -11,4 +11,5 @@ class CrmAttributes public bool $houseManager = false; public bool $teamer = false; public ?string $hotelCode = null; + public array $roles = []; } \ No newline at end of file diff --git a/src/BusProNet/TypeConversionTrait.php b/src/BusProNet/TypeConversionTrait.php index 098ace7..8c59fd0 100644 --- a/src/BusProNet/TypeConversionTrait.php +++ b/src/BusProNet/TypeConversionTrait.php @@ -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(); diff --git a/src/BusProNet/XmlLoader/AbstractXmlLoader.php b/src/BusProNet/XmlLoader/AbstractLoader.php similarity index 76% rename from src/BusProNet/XmlLoader/AbstractXmlLoader.php rename to src/BusProNet/XmlLoader/AbstractLoader.php index 5997658..4e849f4 100644 --- a/src/BusProNet/XmlLoader/AbstractXmlLoader.php +++ b/src/BusProNet/XmlLoader/AbstractLoader.php @@ -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) { diff --git a/src/BusProNet/XmlLoader/HotelXmlLoader.php b/src/BusProNet/XmlLoader/HotelLoader.php similarity index 53% rename from src/BusProNet/XmlLoader/HotelXmlLoader.php rename to src/BusProNet/XmlLoader/HotelLoader.php index c94a20e..0ea14bb 100644 --- a/src/BusProNet/XmlLoader/HotelXmlLoader.php +++ b/src/BusProNet/XmlLoader/HotelLoader.php @@ -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; } diff --git a/src/BusProNet/XmlLoader/PickupXmlLoader.php b/src/BusProNet/XmlLoader/PickupLoader.php similarity index 56% rename from src/BusProNet/XmlLoader/PickupXmlLoader.php rename to src/BusProNet/XmlLoader/PickupLoader.php index 8424960..4224fbe 100644 --- a/src/BusProNet/XmlLoader/PickupXmlLoader.php +++ b/src/BusProNet/XmlLoader/PickupLoader.php @@ -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; } diff --git a/src/BusProNet/XmlLoader/TravelLoader.php b/src/BusProNet/XmlLoader/TravelLoader.php new file mode 100644 index 0000000..32f2517 --- /dev/null +++ b/src/BusProNet/XmlLoader/TravelLoader.php @@ -0,0 +1,350 @@ +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); + } + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlLoader/TravelXmlLoader.php b/src/BusProNet/XmlLoader/TravelXmlLoader.php deleted file mode 100644 index 7484a9a..0000000 --- a/src/BusProNet/XmlLoader/TravelXmlLoader.php +++ /dev/null @@ -1,338 +0,0 @@ -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); - } - } -} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/AbstractParser.php b/src/BusProNet/XmlParser/AbstractParser.php new file mode 100644 index 0000000..9280151 --- /dev/null +++ b/src/BusProNet/XmlParser/AbstractParser.php @@ -0,0 +1,21 @@ +count() ? $node->text() : null; + } + + protected function getIntOrNullValue(Crawler $node): ?int + { + return 0 < $node->count() ? (int) $node->text() : null; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/ApiResponseParser.php b/src/BusProNet/XmlParser/ApiResponseParser.php new file mode 100644 index 0000000..4c1cd1e --- /dev/null +++ b/src/BusProNet/XmlParser/ApiResponseParser.php @@ -0,0 +1,64 @@ +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'); + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/AvailabilitiesParser.php b/src/BusProNet/XmlParser/AvailabilitiesParser.php new file mode 100644 index 0000000..f25d898 --- /dev/null +++ b/src/BusProNet/XmlParser/AvailabilitiesParser.php @@ -0,0 +1,30 @@ +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); + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/BookingParser.php b/src/BusProNet/XmlParser/BookingParser.php new file mode 100644 index 0000000..234f8bd --- /dev/null +++ b/src/BusProNet/XmlParser/BookingParser.php @@ -0,0 +1,155 @@ +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; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/BookingUpdateParser.php b/src/BusProNet/XmlParser/BookingUpdateParser.php new file mode 100644 index 0000000..20b4350 --- /dev/null +++ b/src/BusProNet/XmlParser/BookingUpdateParser.php @@ -0,0 +1,18 @@ +valid = 'möglich' === $node->filterXPath('//aenderung')->text(); + $bookingUpdate->totalPrice = $this->stringToFloat($node->filterXPath('//gesamtpreis')->text()); + + return $bookingUpdate; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/BookingsParser.php b/src/BusProNet/XmlParser/BookingsParser.php new file mode 100644 index 0000000..7775fa8 --- /dev/null +++ b/src/BusProNet/XmlParser/BookingsParser.php @@ -0,0 +1,44 @@ +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); + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/CountriesParser.php b/src/BusProNet/XmlParser/CountriesParser.php new file mode 100644 index 0000000..123cc91 --- /dev/null +++ b/src/BusProNet/XmlParser/CountriesParser.php @@ -0,0 +1,30 @@ +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); + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/CrmAttributesResponseParser.php b/src/BusProNet/XmlParser/CrmAttributesResponseParser.php new file mode 100644 index 0000000..2d9f887 --- /dev/null +++ b/src/BusProNet/XmlParser/CrmAttributesResponseParser.php @@ -0,0 +1,95 @@ +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; + } +} diff --git a/src/BusProNet/XmlParser/DocumentsParser.php b/src/BusProNet/XmlParser/DocumentsParser.php new file mode 100644 index 0000000..455faac --- /dev/null +++ b/src/BusProNet/XmlParser/DocumentsParser.php @@ -0,0 +1,60 @@ +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]; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/MutableDataParser.php b/src/BusProNet/XmlParser/MutableDataParser.php new file mode 100644 index 0000000..6d39fe8 --- /dev/null +++ b/src/BusProNet/XmlParser/MutableDataParser.php @@ -0,0 +1,42 @@ +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); + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/NotificationParser.php b/src/BusProNet/XmlParser/NotificationParser.php new file mode 100644 index 0000000..c25ff4f --- /dev/null +++ b/src/BusProNet/XmlParser/NotificationParser.php @@ -0,0 +1,17 @@ +getIntOrNullValue($result->filterXPath('//satz/nr')); + $text = $this->getStringOrNullValue($result->filterXPath('//satz/text')); + + return new Notification($number, $text); + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/PersonalDataParser.php b/src/BusProNet/XmlParser/PersonalDataParser.php new file mode 100644 index 0000000..98ed9f0 --- /dev/null +++ b/src/BusProNet/XmlParser/PersonalDataParser.php @@ -0,0 +1,70 @@ +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; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/PickupsParser.php b/src/BusProNet/XmlParser/PickupsParser.php new file mode 100644 index 0000000..a985b80 --- /dev/null +++ b/src/BusProNet/XmlParser/PickupsParser.php @@ -0,0 +1,36 @@ +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; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/RoomsParser.php b/src/BusProNet/XmlParser/RoomsParser.php new file mode 100644 index 0000000..bc89ce8 --- /dev/null +++ b/src/BusProNet/XmlParser/RoomsParser.php @@ -0,0 +1,43 @@ +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; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/ServicesParser.php b/src/BusProNet/XmlParser/ServicesParser.php new file mode 100644 index 0000000..b077312 --- /dev/null +++ b/src/BusProNet/XmlParser/ServicesParser.php @@ -0,0 +1,44 @@ +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; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParser/SurchargesParser.php b/src/BusProNet/XmlParser/SurchargesParser.php new file mode 100644 index 0000000..b903232 --- /dev/null +++ b/src/BusProNet/XmlParser/SurchargesParser.php @@ -0,0 +1,33 @@ +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; + } +} \ No newline at end of file diff --git a/src/BusProNet/XmlParserTrait.php b/src/BusProNet/XmlParserTrait.php new file mode 100644 index 0000000..a357826 --- /dev/null +++ b/src/BusProNet/XmlParserTrait.php @@ -0,0 +1,18 @@ +count() ? $node->text() : null; + } + + protected function getIntOrNullValue(Crawler $node): ?int + { + return 0 < $node->count() ? (int) $node->text() : null; + } +} \ No newline at end of file diff --git a/src/Controller/Api/HotelController.php b/src/Controller/Api/HotelController.php index 28c6b8b..2fa3d83 100644 --- a/src/Controller/Api/HotelController.php +++ b/src/Controller/Api/HotelController.php @@ -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) { } diff --git a/src/Controller/Api/PickupController.php b/src/Controller/Api/PickupController.php index b22e64c..3d5374d 100644 --- a/src/Controller/Api/PickupController.php +++ b/src/Controller/Api/PickupController.php @@ -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) { } diff --git a/src/Controller/Api/TravelController.php b/src/Controller/Api/TravelController.php index 7373f66..1cd5822 100644 --- a/src/Controller/Api/TravelController.php +++ b/src/Controller/Api/TravelController.php @@ -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, ) { } diff --git a/src/Controller/Booking/DownloadController.php b/src/Controller/Booking/DownloadController.php index 3097c0b..18fc35b 100644 --- a/src/Controller/Booking/DownloadController.php +++ b/src/Controller/Booking/DownloadController.php @@ -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, diff --git a/src/Controller/Booking/EditController.php b/src/Controller/Booking/EditController.php index 97ed810..61b3a4f 100644 --- a/src/Controller/Booking/EditController.php +++ b/src/Controller/Booking/EditController.php @@ -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); diff --git a/src/Controller/Booking/IndexController.php b/src/Controller/Booking/IndexController.php index 35fe46d..d9ced13 100644 --- a/src/Controller/Booking/IndexController.php +++ b/src/Controller/Booking/IndexController.php @@ -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, ) { } diff --git a/templates/booking/index.html.twig b/templates/booking/index.html.twig index 56057e4..3ac67ca 100644 --- a/templates/booking/index.html.twig +++ b/templates/booking/index.html.twig @@ -69,13 +69,11 @@ {% endif %} + class="button bg-button button--small"> Bestätigung + class="button bg-button button--small"> Reisedokumente diff --git a/tests/BusProNet/DataLoader/HotelDataLoaderTest.php b/tests/BusProNet/DataLoader/HotelDataLoaderTest.php index 3e52189..19bc078 100644 --- a/tests/BusProNet/DataLoader/HotelDataLoaderTest.php +++ b/tests/BusProNet/DataLoader/HotelDataLoaderTest.php @@ -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'); diff --git a/tests/BusProNet/DataLoader/PickupDataLoaderTest.php b/tests/BusProNet/DataLoader/PickupDataLoaderTest.php index 608be5e..bdd933e 100644 --- a/tests/BusProNet/DataLoader/PickupDataLoaderTest.php +++ b/tests/BusProNet/DataLoader/PickupDataLoaderTest.php @@ -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'); diff --git a/tests/BusProNet/DataLoader/TravelDataLoaderTest.php b/tests/BusProNet/DataLoader/TravelDataLoaderTest.php index 97931dd..8ffc2f6 100644 --- a/tests/BusProNet/DataLoader/TravelDataLoaderTest.php +++ b/tests/BusProNet/DataLoader/TravelDataLoaderTest.php @@ -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;