152 lines
5.0 KiB
PHP
152 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\BusProNet\XmlParser;
|
|
|
|
use Symfony\Component\DomCrawler\Crawler;
|
|
|
|
class ContingentParser extends AbstractParser
|
|
{
|
|
private const CONTROL_ROOM_CODE = 'BelKal';
|
|
|
|
/**
|
|
* @var array<string>
|
|
*/
|
|
private array $ignoredRoomCodes = [
|
|
'PDGS',
|
|
];
|
|
|
|
/**
|
|
* @return array{roomTypes: array<int, array<string, mixed>>, rows: array<int, array<string, mixed>>}
|
|
*/
|
|
public function parse(string $xml): array
|
|
{
|
|
$crawler = new Crawler($xml);
|
|
$roomTypes = $this->parseRoomTypes($crawler);
|
|
$rows = $this->parseRows($crawler, $roomTypes);
|
|
|
|
return [
|
|
'roomTypes' => $roomTypes,
|
|
'rows' => $rows,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
private function parseRoomTypes(Crawler $crawler): array
|
|
{
|
|
$roomTypes = [];
|
|
|
|
$crawler
|
|
->filterXPath('//unterbringungen/unterbringung')
|
|
->each(function (Crawler $node) use (&$roomTypes) {
|
|
$roomId = $this->getIntOrNullAttribute($node->attr('idbuspro'));
|
|
$code = $node->attr('code');
|
|
|
|
if (null === $roomId || null === $code) {
|
|
return;
|
|
}
|
|
|
|
if (true === in_array($code, $this->ignoredRoomCodes, true)) {
|
|
return;
|
|
}
|
|
|
|
$label = $node->attr('zimmerbezeichnung')
|
|
?? $this->getStringOrNullValue($node->filterXPath('.//text'))
|
|
?? $code;
|
|
|
|
$pax = $this->getIntOrNullAttribute($node->attr('pax_max')) ?? 0;
|
|
$link = $this->getIntOrNullAttribute($node->attr('idbuspro_kontingent_aus'));
|
|
|
|
$roomTypes[$roomId] = [
|
|
'idBusPro' => $roomId,
|
|
'code' => $code,
|
|
'pax' => $pax,
|
|
'label' => $label,
|
|
'isControlRoom' => self::CONTROL_ROOM_CODE === $code,
|
|
'link' => $link,
|
|
];
|
|
});
|
|
|
|
return $roomTypes;
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $roomTypes
|
|
*
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
private function parseRows(Crawler $crawler, array $roomTypes): array
|
|
{
|
|
$rows = [];
|
|
|
|
$crawler
|
|
->filterXPath('//kapazitaeten/kapazitaet')
|
|
->each(function (Crawler $dateNode) use (&$rows, $roomTypes) {
|
|
$date = $this->stringToDate($dateNode->attr('termin'));
|
|
|
|
if (null === $date) {
|
|
return;
|
|
}
|
|
|
|
foreach ($roomTypes as $roomType) {
|
|
$roomId = $roomType['link'] ?? $roomType['idBusPro'];
|
|
|
|
$roomNode = $this->findRoomNode($dateNode, $roomId);
|
|
if (null === $roomNode) {
|
|
continue;
|
|
}
|
|
|
|
$capacity = $this->getIntOrNullAttribute($roomNode->attr('kontingent')) ?? 0;
|
|
$free = $this->getIntOrNullAttribute($roomNode->attr('frei')) ?? 0;
|
|
$statusRaw = $roomNode->attr('status') ?? '';
|
|
|
|
$rows[] = [
|
|
'date' => $date,
|
|
'roomCode' => $roomType['code'],
|
|
'roomLabel' => $roomType['label'],
|
|
'pax' => $roomType['isControlRoom'] ? 0 : $capacity * (int) ($roomType['pax'] ?? 0),
|
|
'available' => $roomType['isControlRoom'] ? 0 : $free * (int) ($roomType['pax'] ?? 0),
|
|
'status' => $this->mapStatus($statusRaw),
|
|
'minPrice' => $this->stringToFloat($roomNode->attr('abpreis')),
|
|
'minNights' => $this->getIntOrNullAttribute($roomNode->attr('abpreis_naechte')),
|
|
'additionalNightMinPrice' => $this->stringToFloat($roomNode->attr('abpreis_verlaengerung')),
|
|
'additionalNightMinNights' => $this->getIntOrNullAttribute($roomNode->attr('abpreis_verlaengerung_naechte')),
|
|
'isControlRoom' => $roomType['isControlRoom'],
|
|
];
|
|
}
|
|
});
|
|
|
|
return $rows;
|
|
}
|
|
|
|
private function findRoomNode(Crawler $dateNode, int $roomId): ?Crawler
|
|
{
|
|
$roomNode = $dateNode->filterXPath(sprintf('.//zimmerliste/zimmer[@idbuspro="%d"]', $roomId));
|
|
if (0 < $roomNode->count()) {
|
|
return $roomNode->first();
|
|
}
|
|
|
|
$roomNode = $dateNode->filterXPath(sprintf('.//zimmerliste/zimmer[@id="%d"]', $roomId));
|
|
if (0 < $roomNode->count()) {
|
|
return $roomNode->first();
|
|
}
|
|
|
|
$roomNode = $dateNode->filterXPath(sprintf('.//zimmerliste/zimmer[@id_zimmer="%d"]', $roomId));
|
|
if (0 < $roomNode->count()) {
|
|
return $roomNode->first();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function mapStatus(?string $status): string
|
|
{
|
|
return match (strtoupper((string) $status)) {
|
|
'A' => 'ON_REQUEST',
|
|
'S' => 'BLOCKED',
|
|
default => 'OK',
|
|
};
|
|
}
|
|
}
|