feat: improved error handling of xml parsers and loaders
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\BusProNet\XmlLoader;
|
||||
|
||||
use App\BusProNet\Model\Hotel;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\Exception\HotelNotFoundException;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
@@ -47,11 +48,15 @@ class HotelLoader extends AbstractLoader
|
||||
return null;
|
||||
}
|
||||
|
||||
public function loadById(int $id, ?string $filename = 'hotel.xml'): ?Hotel
|
||||
public function loadById(int $id, ?string $filename = 'hotel.xml'): Hotel
|
||||
{
|
||||
$hotels = $this->loadAll($filename);
|
||||
|
||||
return $hotels[$id] ?? null;
|
||||
if (false === isset($hotels[$id])) {
|
||||
throw new HotelNotFoundException($id);
|
||||
}
|
||||
|
||||
return $hotels[$id];
|
||||
}
|
||||
|
||||
private function loadXml(?string $filename = 'hotel.xml'): Crawler
|
||||
@@ -78,7 +83,13 @@ class HotelLoader extends AbstractLoader
|
||||
public function patchHotelDetails(Travel $travel): void
|
||||
{
|
||||
$hotelId = $travel->hotelId;
|
||||
$hotel = $this->loadById($hotelId);
|
||||
$travel->hotel = $hotel;
|
||||
try {
|
||||
$hotel = $this->loadById($hotelId);
|
||||
$travel->hotel = $hotel;
|
||||
} catch (HotelNotFoundException $e) {
|
||||
// If hotel details can't be loaded, leave travel->hotel as null
|
||||
// This allows the travel to be processed even if hotel details are missing
|
||||
$travel->hotel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ use App\BusProNet\Model\MutableData;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\Utility\DateCodeUtility;
|
||||
use App\BusProNet\XmlParser\TravelParser;
|
||||
use App\Exception\HotelNotInTravelException;
|
||||
use App\Exception\TravelNotFoundException;
|
||||
use League\Flysystem\FilesystemException;
|
||||
use League\Flysystem\FilesystemOperator;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
@@ -160,14 +162,18 @@ class TravelLoader extends AbstractLoader
|
||||
*
|
||||
* Retrieves travel data from XML exports. If filename is provided, loads directly
|
||||
* from that file. Otherwise, uses the cached mapping to find the appropriate file.
|
||||
* Validates that both travel and hotel (if specified) exist before attempting to parse.
|
||||
*
|
||||
* @param int $dateId The travel date ID to load
|
||||
* @param int|null $hotelId Optional hotel ID for specific hotel data
|
||||
* @param string|null $filename Optional filename to load from directly
|
||||
*
|
||||
* @return Travel|null The loaded travel object or null if not found
|
||||
* @return Travel The loaded travel object
|
||||
*
|
||||
* @throws TravelNotFoundException When travel ID is not found
|
||||
* @throws HotelNotInTravelException When hotel ID exists but not for this travel
|
||||
*/
|
||||
public function loadById(int $dateId, ?int $hotelId = null, ?string $filename = null): ?Travel
|
||||
public function loadById(int $dateId, ?int $hotelId = null, ?string $filename = null): Travel
|
||||
{
|
||||
if (null !== $filename) {
|
||||
return $this->loadXml($dateId, $hotelId, $filename);
|
||||
@@ -175,8 +181,14 @@ class TravelLoader extends AbstractLoader
|
||||
|
||||
$mapping = $this->generateFilesMap();
|
||||
|
||||
// Validate travel exists
|
||||
if (false === isset($mapping[$dateId])) {
|
||||
return null;
|
||||
throw new TravelNotFoundException($dateId);
|
||||
}
|
||||
|
||||
// Validate hotel exists in this travel if specified
|
||||
if (null !== $hotelId && false === isset($mapping[$dateId]['hotels'][$hotelId])) {
|
||||
throw new HotelNotInTravelException($dateId, $hotelId);
|
||||
}
|
||||
|
||||
$filename = $mapping[$dateId]['file'];
|
||||
@@ -194,9 +206,12 @@ class TravelLoader extends AbstractLoader
|
||||
* @param int|null $hotelId Optional hotel ID for specific hotel data
|
||||
* @param string $filename The XML filename to load from
|
||||
*
|
||||
* @return Travel|null The loaded travel object or null if not found
|
||||
* @return Travel The loaded travel object
|
||||
*
|
||||
* @throws TravelNotFoundException When travel ID is not found in XML
|
||||
* @throws HotelNotInTravelException When hotel ID is not found in travel XML
|
||||
*/
|
||||
private function loadXml(int $dateId, ?int $hotelId, string $filename): ?Travel
|
||||
private function loadXml(int $dateId, ?int $hotelId, string $filename): Travel
|
||||
{
|
||||
try {
|
||||
$xml = $this->xmlExport->read($filename);
|
||||
@@ -205,12 +220,20 @@ class TravelLoader extends AbstractLoader
|
||||
$travelNode = $crawler->filterXPath(sprintf('//reise/termin[@idbuspro="%d"]', $dateId));
|
||||
|
||||
if (0 === $travelNode->count()) {
|
||||
return null;
|
||||
throw new TravelNotFoundException($dateId);
|
||||
}
|
||||
|
||||
// Validate hotel exists in travel XML if specified
|
||||
if (null !== $hotelId) {
|
||||
$hotelNode = $travelNode->filterXPath(sprintf('.//hotel[@idbuspro="%d"]', $hotelId));
|
||||
if (0 === $hotelNode->count()) {
|
||||
throw new HotelNotInTravelException($dateId, $hotelId);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->travelParser->parse($travelNode->first(), $hotelId);
|
||||
} catch (FilesystemException $e) {
|
||||
return null;
|
||||
throw new TravelNotFoundException($dateId, $e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user