feat: API lists the calendar hotels for the contingent sync of MyE&P
GET /api/calendar-hotels returns the calendar hotel of every visible product, with the products using it and their season, behind the same API key as /api/hotel and /api/product. MyE&P only syncs contingent snapshots for its accommodations, so hotels that are only offered in winter (e.g. DKI, DWW, ASCGR) have no availability for the iCal feed and the availability calendar. With this list MyE&P can sync every hotel code TYPO3 actually uses, without a second list to maintain. The products and seasons are for a status overview of which hotel supports iCal, availability and prices. Hidden hotels are left out, as on the website (e.g. ASB). Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
5d41660a9a
commit
bf9afd143d
1 file changed
+49
@@ -43,6 +43,10 @@ class ApiMiddleware implements MiddlewareInterface
|
||||
return $this->handleProductRequest($request);
|
||||
}
|
||||
|
||||
if ('/api/calendar-hotels' === $path) {
|
||||
return $this->handleCalendarHotelsRequest($request);
|
||||
}
|
||||
|
||||
if (str_starts_with($path, ContentFeedApi::PATH_PREFIX)) {
|
||||
return $this->contentFeedApi->handle($request);
|
||||
}
|
||||
@@ -97,6 +101,51 @@ class ApiMiddleware implements MiddlewareInterface
|
||||
return new JsonResponse($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The calendar hotels of all visible products, for the contingent sync of MyE&P: their
|
||||
* availability is needed for the iCal feed and the availability calendar, whether or not
|
||||
* MyE&P has an accommodation with prices for them.
|
||||
*/
|
||||
private function handleCalendarHotelsRequest(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
if (!$this->authenticator->isAuthorized($request)) {
|
||||
return new JsonResponse(['message' => 'Invalid or missing api key'], 403);
|
||||
}
|
||||
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tx_epproducts_domain_model_product');
|
||||
|
||||
$rows = $queryBuilder
|
||||
->select('hotel.code', 'hotel.name AS hotelName', 'product.uid', 'product.name', 'product.season')
|
||||
->from('tx_epproducts_domain_model_product', 'product')
|
||||
->join('product', 'tx_epproducts_domain_model_hotel', 'hotel', 'hotel.uid = product.calendar_hotel')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('product.sys_language_uid', 0),
|
||||
$queryBuilder->expr()->neq('hotel.code', $queryBuilder->createNamedParameter('')),
|
||||
)
|
||||
->orderBy('hotel.code')
|
||||
->addOrderBy('product.uid')
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
$hotels = [];
|
||||
foreach ($rows as $row) {
|
||||
$code = trim((string)$row['code']);
|
||||
$hotels[$code] ??= [
|
||||
'code' => $code,
|
||||
'name' => trim((string)preg_replace('/\s+/', ' ', (string)$row['hotelName'])),
|
||||
'products' => [],
|
||||
];
|
||||
$hotels[$code]['products'][] = [
|
||||
'uid' => (int)$row['uid'],
|
||||
'name' => trim((string)preg_replace('/\s+/', ' ', (string)$row['name'])),
|
||||
'season' => '' !== (string)$row['season'] ? (string)$row['season'] : null,
|
||||
];
|
||||
}
|
||||
|
||||
return new JsonResponse(array_values($hotels));
|
||||
}
|
||||
|
||||
private function fetchProductData(string $productCode): ?array
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
|
||||
Reference in new issue
Block a user