feat: api endpoints

This commit is contained in:
Björn Fromme committed 2024-12-04 14:18:47 +01:00
1 parent 7379f5ac93
commit 231aaaac9b
26 files changed
+606 -43

No files matched your search

@@ -0,0 +1,15 @@
<?php
namespace App\BusProNet\XmlLoader;
use App\BusProNet\TypeConversionTrait;
use Symfony\Contracts\Cache\CacheInterface;
abstract class AbstractXmlLoader
{
use TypeConversionTrait;
public function __construct(protected readonly CacheInterface $cache, protected readonly ?string $xmlPath = null)
{
}
}
@@ -0,0 +1,83 @@
<?php
namespace App\BusProNet\XmlLoader;
use App\BusProNet\Model\Hotel;
use App\BusProNet\Model\Travel;
use Psr\Cache\InvalidArgumentException;
use Symfony\Contracts\Cache\ItemInterface;
class HotelXmlLoader extends AbstractXmlLoader
{
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);
$hotels = [];
foreach ($xml->hotel as $hotel) {
$id = (int)$hotel->attributes()['idbuspro'];
$hotels[$id] = $this->parseXml($hotel);
}
return $hotels;
});
} catch (InvalidArgumentException $e) {
return [];
}
}
public function loadById(int $id, ?string $filename = 'hotel.xml'): ?Hotel
{
$hotels = $this->loadAll($filename);
return $hotels[$id] ?? null;
}
public function loadByCode(string $code, ?string $filename = 'hotel.xml'): ?Hotel
{
$hotels = $this->loadAll($filename);
foreach ($hotels as $hotel) {
if ($code === $hotel->code) {
return $hotel;
}
}
return null;
}
private function loadXml(?string $filename = 'hotel.xml'): \SimpleXMLElement
{
$filepath = $this->xmlPath.'/'.$filename;
return simplexml_load_file($filepath);
}
public function parseXml(\SimpleXMLElement $xml): 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;
return $hotel;
}
public function patchHotelDetails(Travel $travel): void
{
$hotelId = $travel->hotelId;
$hotel = $this->loadById($hotelId);
$travel->hotel = $hotel;
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\BusProNet\XmlLoader;
use App\BusProNet\Model\Pickup;
use App\BusProNet\Model\Travel;
use Psr\Cache\InvalidArgumentException;
use Symfony\Contracts\Cache\ItemInterface;
class PickupXmlLoader extends AbstractXmlLoader
{
public function loadAll(?string $filename = 'zustiege.xml'): array
{
try {
return $this->cache->get('bpn_pickups', function (ItemInterface $item) use ($filename) {
$item->expiresAfter(3600);
$xml = simplexml_load_file($this->xmlPath . '/' . $filename);
$pickups = [];
foreach ($xml->zustieg as $pickup) {
$id = (int)$pickup->attributes()['idbuspro'];
$pickups[$id] = $this->parseXml($pickup);
}
return $pickups;
});
} catch (InvalidArgumentException $e) {
return [];
}
}
public function loadById(int $id, ?string $filename = 'zustiege.xml'): ?Pickup
{
$pickups = $this->loadAll($filename);
return $pickups[$id] ?? null;
}
public function parseXml(\SimpleXMLElement $xml): 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;
return $pickup;
}
public function patchPickupsDetails(Travel $travel): void
{
foreach ($travel->pickups as $pickupId => $pickup) {
$pickupData = $this->loadById($pickupId);
$pickup->code = $pickupData->code;
$pickup->postalCode = $pickupData->postalCode;
$pickup->city = $pickupData->city;
$pickup->street = $pickupData->street;
}
}
}
+306
View File
@@ -0,0 +1,306 @@
<?php
namespace App\BusProNet\XmlLoader;
use App\BusProNet\Model\BaseData;
use App\BusProNet\Model\CrmSelection;
use App\BusProNet\Model\CrmSelectionGroup;
use App\BusProNet\Model\MutableData;
use App\BusProNet\Model\Pickup;
use App\BusProNet\Model\Room;
use App\BusProNet\Model\Service;
use App\BusProNet\Model\Travel;
use Symfony\Component\Finder\Finder;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
class TravelXmlLoader extends AbstractXmlLoader
{
public function __construct(
private readonly HotelXmlLoader $hotelDataLoader,
CacheInterface $cache,
?string $xmlPath = null
) {
parent::__construct($cache, $xmlPath);
}
public function generateMapping(): array
{
return $this->cache->get('bpn_travels_mapping', function (ItemInterface $item) {
$item->expiresAfter(3600);
$finder = new Finder();
$finder->files()->in($this->xmlPath)->name('Ziel_*.xml');
$mapping = [];
$hotels = $this->hotelDataLoader->loadAll();
foreach ($finder as $file) {
$xml = simplexml_load_file($file->getRealPath());
foreach ($xml->reise->termin as $travelXml) {
$attributes = $travelXml->attributes();
$travelId = (int) $attributes['idbuspro'];
$mapping[$travelId] = [
'id' => (int) $attributes['idbuspro'],
'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,
'label' => $hotels[$hotelId]->name,
];
}
}
}
return $mapping;
});
}
public function loadById(int $travelId, ?int $hotelId = null, ?string $filename = null): ?Travel
{
if (null !== $filename) {
return $this->loadXml($travelId, $hotelId, $filename);
}
$mapping = $this->generateMapping();
if (false === isset($mapping[$travelId])) {
return null;
}
$file = $mapping[$travelId]['file'];
return $this->loadXml($travelId, $hotelId, $file);
}
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
{
$hotelXml = $this->getHotelXml($xml, $hotelId);
$attributes = $xml->attributes();
$travel = new Travel();
$travel->id = (int) $attributes['idbuspro'];
$travel->label = (string) $xml->text;
$travel->hotelId = $hotelId;
$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 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
{
$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);
}
}
}