fix: allow hotel-less travel data
addresses #869ckkwh7
This commit is contained in:
@@ -91,6 +91,12 @@ class HotelLoader extends AbstractLoader
|
|||||||
public function patchHotelDetails(Travel $travel): void
|
public function patchHotelDetails(Travel $travel): void
|
||||||
{
|
{
|
||||||
$hotelId = $travel->hotelId;
|
$hotelId = $travel->hotelId;
|
||||||
|
if (null === $hotelId) {
|
||||||
|
$travel->hotel = null;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$hotel = $this->loadById($hotelId);
|
$hotel = $this->loadById($hotelId);
|
||||||
$travel->hotel = $hotel;
|
$travel->hotel = $hotel;
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ class TravelParser extends AbstractParser
|
|||||||
|
|
||||||
$travel = new Travel();
|
$travel = new Travel();
|
||||||
$travel->id = (int) $this->getRequiredAttrValue($node, 'idbuspro', 'travel termin node');
|
$travel->id = (int) $this->getRequiredAttrValue($node, 'idbuspro', 'travel termin node');
|
||||||
$travel->hotelId = (int) $this->getRequiredAttrValue($hotelNode, 'idbuspro', 'travel hotel node');
|
$travel->hotelId = null !== $hotelNode
|
||||||
|
? (int) $this->getRequiredAttrValue($hotelNode, 'idbuspro', 'travel hotel node')
|
||||||
|
: null;
|
||||||
$travel->label = $this->getStringOrNullValue($node->filterXPath('.//text'));
|
$travel->label = $this->getStringOrNullValue($node->filterXPath('.//text'));
|
||||||
$travel->dateFrom = $dateFrom;
|
$travel->dateFrom = $dateFrom;
|
||||||
$travel->dateTo = $dateTo;
|
$travel->dateTo = $dateTo;
|
||||||
@@ -80,7 +82,7 @@ class TravelParser extends AbstractParser
|
|||||||
->getAdditionalServices($node->filterXPath('.//lei_sonstiges[not(ancestor::hotel)]/leistung'));
|
->getAdditionalServices($node->filterXPath('.//lei_sonstiges[not(ancestor::hotel)]/leistung'));
|
||||||
$travel->transportationServices = $this
|
$travel->transportationServices = $this
|
||||||
->getTransportationServices($node->filterXPath('.//lei_befoerderung/leistung'));
|
->getTransportationServices($node->filterXPath('.//lei_befoerderung/leistung'));
|
||||||
$travel->rooms = $this->getRooms($hotelNode);
|
$travel->rooms = null !== $hotelNode ? $this->getRooms($hotelNode) : [];
|
||||||
$travel->pickups = $this->getPickups($node->filterXPath('.//zustiege/zustieg'), $dateFrom, true);
|
$travel->pickups = $this->getPickups($node->filterXPath('.//zustiege/zustieg'), $dateFrom, true);
|
||||||
$travel->dropOffs = $this->getPickups($node->filterXPath('.//zustiege_rueck/zustieg_rueck'), $dateTo, false);
|
$travel->dropOffs = $this->getPickups($node->filterXPath('.//zustiege_rueck/zustieg_rueck'), $dateTo, false);
|
||||||
|
|
||||||
@@ -319,16 +321,16 @@ class TravelParser extends AbstractParser
|
|||||||
* @param Crawler $node The XML node containing hotel data
|
* @param Crawler $node The XML node containing hotel data
|
||||||
* @param int|null $hotelId Optional hotel ID to filter by
|
* @param int|null $hotelId Optional hotel ID to filter by
|
||||||
*
|
*
|
||||||
* @return Crawler The hotel XML node
|
* @return Crawler|null The hotel XML node or null if none exists and no specific hotel was requested
|
||||||
*/
|
*/
|
||||||
public function getHotelNode(Crawler $node, ?int $hotelId): Crawler
|
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)
|
// In case not hotel id is provided, take the first hotel node (which is most probably the only one)
|
||||||
if (null === $hotelId) {
|
if (null === $hotelId) {
|
||||||
$hotelNode = $node->filterXPath('.//hotel');
|
$hotelNode = $node->filterXPath('.//hotel');
|
||||||
|
|
||||||
if (0 === $hotelNode->count()) {
|
if (0 === $hotelNode->count()) {
|
||||||
throw new \InvalidArgumentException('No hotel node found in travel XML.');
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $hotelNode->first();
|
return $hotelNode->first();
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\BusProNet\XmlLoader;
|
||||||
|
|
||||||
|
use App\BusProNet\Model\Travel;
|
||||||
|
use App\BusProNet\XmlLoader\HotelLoader;
|
||||||
|
use League\Flysystem\FilesystemOperator;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||||
|
|
||||||
|
class HotelLoaderTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testPatchHotelDetailsSkipsWhenTravelHasNoHotelId(): void
|
||||||
|
{
|
||||||
|
$filesystem = $this->createMock(FilesystemOperator::class);
|
||||||
|
$filesystem
|
||||||
|
->expects($this->never())
|
||||||
|
->method('read');
|
||||||
|
|
||||||
|
$loader = new HotelLoader(new ArrayAdapter(), $filesystem);
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->hotelId = null;
|
||||||
|
$travel->hotel = null;
|
||||||
|
|
||||||
|
$loader->patchHotelDetails($travel);
|
||||||
|
|
||||||
|
$this->assertNull($travel->hotel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -184,6 +184,49 @@ class TravelParserTest extends TestCase
|
|||||||
$this->assertTrue($additionalServices[183660]->autoBook);
|
$this->assertTrue($additionalServices[183660]->autoBook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testParseTravelWithoutHotelNode(): void
|
||||||
|
{
|
||||||
|
$xmlContent = '<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<reisen>
|
||||||
|
<reise id="1" idbuspro="2293" code="">
|
||||||
|
<termin id="1" idbuspro="12162" idprodukt="2293" termin="28.03.2026" bis="04.04.2026" code="PGTSGI280326" reiseart="P">
|
||||||
|
<text>PG TSG Irlich</text>
|
||||||
|
<abpreis>-50,00</abpreis>
|
||||||
|
<lei_sonstiges>
|
||||||
|
<leistung id="1" idbuspro="188858" unterart="SON" termin="28.03.2026" bis="04.04.2026" automatisch_buchen="False" pflicht="False">
|
||||||
|
<text>7 Übernachtungen im 3* Posthotel</text>
|
||||||
|
<preis>999,00</preis>
|
||||||
|
<status>Frei</status>
|
||||||
|
</leistung>
|
||||||
|
</lei_sonstiges>
|
||||||
|
<lei_befoerderung>
|
||||||
|
<leistung id="1" idbuspro="188850" unterart="BUS" termin="27.03.2026" bis="28.03.2026" automatisch_buchen="False" pflicht="False">
|
||||||
|
<text>Bus-Hinfahrt</text>
|
||||||
|
<preis>5,00</preis>
|
||||||
|
<status>Frei</status>
|
||||||
|
<richtung>HIN</richtung>
|
||||||
|
</leistung>
|
||||||
|
</lei_befoerderung>
|
||||||
|
<zustiege>
|
||||||
|
<zustieg id="1" idbuspro="873" zeit="27.03.2026 21:30:00" />
|
||||||
|
</zustiege>
|
||||||
|
</termin>
|
||||||
|
</reise>
|
||||||
|
</reisen>';
|
||||||
|
|
||||||
|
$crawler = new Crawler($xmlContent);
|
||||||
|
$travelNode = $crawler->filterXPath('//reise/termin')->first();
|
||||||
|
$travel = $this->parser->parse($travelNode);
|
||||||
|
|
||||||
|
$this->assertSame(12162, $travel->id);
|
||||||
|
$this->assertSame('PGTSGI280326', $travel->code);
|
||||||
|
$this->assertNull($travel->hotelId);
|
||||||
|
$this->assertSame([], $travel->rooms);
|
||||||
|
$this->assertArrayHasKey(188858, $travel->additionalServices);
|
||||||
|
$this->assertArrayHasKey(188850, $travel->transportationServices);
|
||||||
|
$this->assertArrayHasKey(873, $travel->pickups);
|
||||||
|
}
|
||||||
|
|
||||||
public function testParseAdditionalServicesUsesTerminLevelOnly(): void
|
public function testParseAdditionalServicesUsesTerminLevelOnly(): void
|
||||||
{
|
{
|
||||||
$xmlContent = '<?xml version="1.0" encoding="utf-8"?>
|
$xmlContent = '<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|||||||
Reference in New Issue
Block a user