feat: travel data API endpoint for travelinfo pages in TYPO3
This commit is contained in:
@@ -49,7 +49,7 @@ Accept: application/json
|
|||||||
Authorization: Bearer {{$auth.token("oauth2_api")}}
|
Authorization: Bearer {{$auth.token("oauth2_api")}}
|
||||||
|
|
||||||
### API travel
|
### API travel
|
||||||
GET {{base_url}}/api/travels/DWWMP301125
|
GET {{base_url}}/api/travels/DPWBSP030229
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
Authorization: Bearer {{$auth.token("oauth2_api")}}
|
Authorization: Bearer {{$auth.token("oauth2_api")}}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,35 @@ trait TypeConversionTrait
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$dateTime = Carbon::createFromFormat('d.m.Y H:i', substr($string, 0, 16))->startOfDay();
|
$dateTime = Carbon::createFromFormat('d.m.Y H:i', substr($string, 0, 16));
|
||||||
|
|
||||||
|
return $dateTime->toDateTimeImmutable();
|
||||||
|
} catch (InvalidFormatException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is used primarily to parse pickup-times since data is
|
||||||
|
* either provided with date and time or time only. In this case a
|
||||||
|
* date has to be provided which defaults to a travel's start date.
|
||||||
|
*/
|
||||||
|
protected function stringToDateTimeFuzzy(?string $string, \DateTimeImmutable $defaultDate): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
if (true === empty($string)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (1 === preg_match('/^\d{2}:\d{2}$/', $string)) {
|
||||||
|
// time only provided
|
||||||
|
$dateTime = Carbon::createFromFormat('H:i', $string);
|
||||||
|
// assign default date
|
||||||
|
$dateTime->setDateFrom($defaultDate);
|
||||||
|
} else {
|
||||||
|
// date and time provided
|
||||||
|
$dateTime = Carbon::createFromFormat('d.m.Y H:i', substr($string, 0, 16));
|
||||||
|
}
|
||||||
|
|
||||||
return $dateTime->toDateTimeImmutable();
|
return $dateTime->toDateTimeImmutable();
|
||||||
} catch (InvalidFormatException $e) {
|
} catch (InvalidFormatException $e) {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Utility;
|
||||||
|
|
||||||
|
class TravelCodeUtility
|
||||||
|
{
|
||||||
|
public function sanitize(string $travelCode): string
|
||||||
|
{
|
||||||
|
return str_replace(['-', '/'], '', strtoupper($travelCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseCode(string $travelCode): string
|
||||||
|
{
|
||||||
|
return strtoupper(substr($travelCode, 0, -6));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDate(string $travelCode): \DateTimeImmutable
|
||||||
|
{
|
||||||
|
$datePart = substr($travelCode, -6);
|
||||||
|
|
||||||
|
return \DateTimeImmutable::createFromFormat('dmy', $datePart);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use App\BusProNet\Model\Pickup;
|
|||||||
use App\BusProNet\Model\Room;
|
use App\BusProNet\Model\Room;
|
||||||
use App\BusProNet\Model\Service;
|
use App\BusProNet\Model\Service;
|
||||||
use App\BusProNet\Model\Travel;
|
use App\BusProNet\Model\Travel;
|
||||||
|
use App\BusProNet\Utility\TravelCodeUtility;
|
||||||
use League\Flysystem\FilesystemOperator;
|
use League\Flysystem\FilesystemOperator;
|
||||||
use League\Flysystem\StorageAttributes;
|
use League\Flysystem\StorageAttributes;
|
||||||
use Psr\Cache\InvalidArgumentException;
|
use Psr\Cache\InvalidArgumentException;
|
||||||
@@ -130,11 +131,13 @@ class TravelLoader extends AbstractLoader
|
|||||||
{
|
{
|
||||||
$hotelNode = $this->getHotelNode($node, $hotelId);
|
$hotelNode = $this->getHotelNode($node, $hotelId);
|
||||||
|
|
||||||
|
$dateFrom = $this->stringToDate($node->attr('termin'));
|
||||||
|
|
||||||
$travel = new Travel();
|
$travel = new Travel();
|
||||||
$travel->id = (int) $node->attr('idbuspro');
|
$travel->id = (int) $node->attr('idbuspro');
|
||||||
$travel->hotelId = (int) $hotelNode->attr('idbuspro');
|
$travel->hotelId = (int) $hotelNode->attr('idbuspro');
|
||||||
$travel->label = $this->getStringOrNullValue($node->filterXPath('//text'));
|
$travel->label = $this->getStringOrNullValue($node->filterXPath('//text'));
|
||||||
$travel->dateFrom = $this->stringToDate($node->attr('termin'));
|
$travel->dateFrom = $dateFrom;
|
||||||
$travel->dateTo = $this->stringToDate($node->attr('bis'));
|
$travel->dateTo = $this->stringToDate($node->attr('bis'));
|
||||||
$travel->code = $node->attr('code');
|
$travel->code = $node->attr('code');
|
||||||
$travel->type = $node->attr('reiseart');
|
$travel->type = $node->attr('reiseart');
|
||||||
@@ -145,7 +148,7 @@ class TravelLoader extends AbstractLoader
|
|||||||
$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 = $this->getRooms($hotelNode);
|
||||||
$travel->pickupsTo = $this->getPickups($node->filterXPath('//zustiege/zustieg'));
|
$travel->pickupsTo = $this->getPickups($node->filterXPath('//zustiege/zustieg'), $dateFrom);
|
||||||
$travel->pickupsFro = $this->getPickups($node->filterXPath('//zustiege_rueck/zustieg_rueck'));
|
$travel->pickupsFro = $this->getPickups($node->filterXPath('//zustiege_rueck/zustieg_rueck'));
|
||||||
$travel->guide = $this->getGuide($node);
|
$travel->guide = $this->getGuide($node);
|
||||||
|
|
||||||
@@ -248,19 +251,23 @@ class TravelLoader extends AbstractLoader
|
|||||||
return $transportationServices;
|
return $transportationServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPickups(Crawler $node): array
|
public function getPickups(Crawler $node, ?\DateTimeImmutable $defaultDate = null): array
|
||||||
{
|
{
|
||||||
$pickups = [];
|
$pickups = [];
|
||||||
|
|
||||||
$node->each(function (Crawler $pickupNode) use (&$pickups) {
|
$node->each(function (Crawler $pickupNode) use (&$pickups, $defaultDate) {
|
||||||
$pickupId = (int) $pickupNode->attr('idbuspro');
|
$pickupId = (int) $pickupNode->attr('idbuspro');
|
||||||
|
|
||||||
$pickup = new Pickup();
|
$pickup = new Pickup();
|
||||||
$pickup->id = $pickupId;
|
$pickup->id = $pickupId;
|
||||||
$pickup->time = $this->stringToDateTime($pickupNode->attr('zeit'));
|
|
||||||
$pickup->price = $pickupNode->attr('preis') ?
|
$pickup->price = $pickupNode->attr('preis') ?
|
||||||
$this->stringToFloat($pickupNode->attr('preis')) : null;
|
$this->stringToFloat($pickupNode->attr('preis')) : null;
|
||||||
|
|
||||||
|
// parse date and time only for direction 'to' indicated by provided default date
|
||||||
|
if (null !== $defaultDate) {
|
||||||
|
$pickup->time = $this->stringToDateTimeFuzzy($pickupNode->attr('zeit'), $defaultDate);
|
||||||
|
}
|
||||||
|
|
||||||
$pickups[$pickupId] = $pickup;
|
$pickups[$pickupId] = $pickup;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -352,6 +359,8 @@ class TravelLoader extends AbstractLoader
|
|||||||
|
|
||||||
public function patchBookings(BaseData $bookings): void
|
public function patchBookings(BaseData $bookings): void
|
||||||
{
|
{
|
||||||
|
$travelCodeUtility = new TravelCodeUtility();
|
||||||
|
|
||||||
foreach ($bookings->getItems() as $booking) {
|
foreach ($bookings->getItems() as $booking) {
|
||||||
if (null === $travelId = $booking->travelId) {
|
if (null === $travelId = $booking->travelId) {
|
||||||
continue;
|
continue;
|
||||||
@@ -368,11 +377,12 @@ class TravelLoader extends AbstractLoader
|
|||||||
$travelDate = $travelData->dateFrom;
|
$travelDate = $travelData->dateFrom;
|
||||||
$travelCode = $travelData->code;
|
$travelCode = $travelData->code;
|
||||||
|
|
||||||
|
// generate url to travelinfo page five days before travel begins
|
||||||
if ($travelDate->modify('-5 days') < $now) {
|
if ($travelDate->modify('-5 days') < $now) {
|
||||||
$booking->travelInfoUrl = sprintf(
|
$booking->travelInfoUrl = sprintf(
|
||||||
'%s/%s',
|
'%s/%s',
|
||||||
rtrim($this->travelInfoBaseUrl, '/'),
|
rtrim($this->travelInfoBaseUrl, '/'),
|
||||||
str_replace('/', '-', $travelCode)
|
$travelCodeUtility->sanitize($travelCode)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Controller\Api;
|
namespace App\Controller\Api;
|
||||||
|
|
||||||
use App\BusProNet\Model\Travel;
|
use App\BusProNet\Model\Travel;
|
||||||
|
use App\BusProNet\Utility\TravelCodeUtility;
|
||||||
use App\BusProNet\XmlLoader\HotelLoader;
|
use App\BusProNet\XmlLoader\HotelLoader;
|
||||||
use App\BusProNet\XmlLoader\PickupLoader;
|
use App\BusProNet\XmlLoader\PickupLoader;
|
||||||
use App\BusProNet\XmlLoader\TravelLoader;
|
use App\BusProNet\XmlLoader\TravelLoader;
|
||||||
@@ -55,7 +56,8 @@ class TravelController extends AbstractController
|
|||||||
)]
|
)]
|
||||||
public function singleByCode(string $travelCode, ?string $hotelCode = null): JsonResponse
|
public function singleByCode(string $travelCode, ?string $hotelCode = null): JsonResponse
|
||||||
{
|
{
|
||||||
$travelCode = str_replace('-', '/', $travelCode);
|
// sanitize travel code by removing potential dividers
|
||||||
|
$travelCode = (new TravelCodeUtility())->sanitize($travelCode);
|
||||||
|
|
||||||
$travelId = $this->travelXmlLoader->mapCodeToId($travelCode);
|
$travelId = $this->travelXmlLoader->mapCodeToId($travelCode);
|
||||||
$hotelId = $hotelCode ? $this->hotelXmlLoader->mapCodeToId($travelCode) : null;
|
$hotelId = $hotelCode ? $this->hotelXmlLoader->mapCodeToId($travelCode) : null;
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BusProNet\Utility;
|
||||||
|
|
||||||
|
use App\BusProNet\Utility\TravelCodeUtility;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class TravelCodeUtilityTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testSanitizeCode(): void
|
||||||
|
{
|
||||||
|
$utility = new TravelCodeUtility();
|
||||||
|
|
||||||
|
$travelCode = 'ABCDEF/010125';
|
||||||
|
$sanitized = $utility->sanitize($travelCode);
|
||||||
|
$this->assertEquals('ABCDEF010125', $sanitized);
|
||||||
|
|
||||||
|
$travelCode = 'ABCDEF-010125';
|
||||||
|
$sanitized = $utility->sanitize($travelCode);
|
||||||
|
$this->assertEquals('ABCDEF010125', $sanitized);
|
||||||
|
|
||||||
|
$travelCode = 'abcdef/010125';
|
||||||
|
$sanitized = $utility->sanitize($travelCode);
|
||||||
|
$this->assertEquals('ABCDEF010125', $sanitized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetBaseCode(): void
|
||||||
|
{
|
||||||
|
$utility = new TravelCodeUtility();
|
||||||
|
|
||||||
|
$travelCode = 'ABCDEF010125';
|
||||||
|
$baseCode = $utility->getBaseCode($travelCode);
|
||||||
|
$this->assertEquals('ABCDEF', $baseCode);
|
||||||
|
|
||||||
|
$travelCode = 'abcdef010125';
|
||||||
|
$baseCode = $utility->getBaseCode($travelCode);
|
||||||
|
$this->assertEquals('ABCDEF', $baseCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetDate(): void
|
||||||
|
{
|
||||||
|
$utility = new TravelCodeUtility();
|
||||||
|
|
||||||
|
$travelCode = 'ABCDEF010125';
|
||||||
|
$date = $utility->getDate($travelCode);
|
||||||
|
$this->assertEquals('2025-01-01', $date->format('Y-m-d'));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user