feat: extended api endpoint for hotel data consumed by myep

This commit is contained in:
Björn Fromme
2026-07-16 08:41:11 +02:00
parent 11fda126a8
commit 83b3cbea4d
4 changed files with 224 additions and 13 deletions
@@ -2,18 +2,58 @@
namespace EP\EpProducts\Middleware;
use EP\EpProducts\Service\HotelImageService;
use EP\EpProducts\Service\ProductImageService;
use EP\EpProducts\Service\MyEpImageService;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Http\JsonResponse;
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
class ProductApiMiddleware implements MiddlewareInterface
class ApiMiddleware implements MiddlewareInterface
{
/**
* @var MyEpImageService
*/
private $hotelImageService;
/**
* @var MyEpImageService
*/
private $productImageService;
/**
* @var MyEpImageService
*/
private $regionImageService;
/**
* @var FileRepository
*/
private $fileRepository;
/**
* @var ImageService
*/
private $imageService;
public function __construct(
MyEpImageService $hotelImageService,
MyEpImageService $productImageService,
MyEpImageService $regionImageService,
FileRepository $fileRepository,
ImageService $imageService
) {
$this->hotelImageService = $hotelImageService;
$this->productImageService = $productImageService;
$this->regionImageService = $regionImageService;
$this->fileRepository = $fileRepository;
$this->imageService = $imageService;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$path = $request->getUri()->getPath();
@@ -91,15 +131,15 @@ class ProductApiMiddleware implements MiddlewareInterface
$data = $queryBuilder
->select(
'product.uid as productUid',
'product.name as productName',
'product.code as productCode',
'product.region as regionUid',
'country.name as countryName',
'region.name as regionName',
'city.name as cityName',
)
->from('tx_epproducts_domain_model_product', 'product')
->leftJoin('product', 'tx_epproducts_domain_model_country', 'country', 'product.country = country.uid')
->leftJoin('product', 'tx_epproducts_domain_model_region', 'region', 'product.region = region.uid')
->leftJoin('product', 'tx_epproducts_domain_model_city', 'city', 'product.city = city.uid')
->leftJoin('product', 'tx_epproducts_domain_model_matchcode', 'matchcode', 'product.uid = matchcode.entity AND matchcode.entity_type="hotel"')
->where($queryBuilder->expr()->eq('product.code', $queryBuilder->createNamedParameter($productCode)))
@@ -113,8 +153,7 @@ class ProductApiMiddleware implements MiddlewareInterface
return null;
}
$images = GeneralUtility::makeInstance(ProductImageService::class)
->getImages((int) $data['uid']);
$images = $this->serializeImages($this->productImageService->getImages((int) $data['productUid']));
return [
'product' => [
@@ -125,9 +164,7 @@ class ProductApiMiddleware implements MiddlewareInterface
'country' => [
'name' => $data['countryName'],
],
'region' => [
'name' => $data['regionName'],
],
'region' => $this->fetchRegionData((int) $data['regionUid']),
'city' => [
'name' => $data['cityName'],
],
@@ -159,6 +196,7 @@ class ProductApiMiddleware implements MiddlewareInterface
'hotel.wifi',
'hotel.distance_bus',
'hotel.distance_lift',
'hotel.region',
)
->from('tx_epproducts_domain_model_hotel', 'hotel')
->leftJoin('hotel', 'tx_epproducts_domain_model_matchcode', 'alias', 'hotel.uid = alias.entity AND alias.entity_type="hotel"')
@@ -177,8 +215,7 @@ class ProductApiMiddleware implements MiddlewareInterface
return [];
}
$images = GeneralUtility::makeInstance(HotelImageService::class)
->getImages((int) $hotel['uid']);
$images = $this->serializeImages($this->hotelImageService->getImages((int) $hotel['uid']));
return [
'name' => $hotel['name'],
@@ -201,6 +238,89 @@ class ProductApiMiddleware implements MiddlewareInterface
'distanceBus' => $hotel['distance_bus'],
'distanceLift' => $hotel['distance_lift'],
],
'region' => $this->fetchRegionData((int) $hotel['region']),
];
}
private function fetchRegionData(int $regionUid): array
{
if (0 === $regionUid) {
return [];
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tx_epproducts_domain_model_region');
$region = $queryBuilder
->select(
'region.uid',
'region.name',
'region.latitude',
'region.longitude',
'region.ski_area',
'region.ski_area_extended',
'region.description',
'region.news',
'region.length',
'region.height',
'region.lifts',
'webcam.url as webcamUrl',
)
->from('tx_epproducts_domain_model_region', 'region')
->leftJoin('region', 'tx_epproducts_domain_model_webcam', 'webcam', 'region.webcam = webcam.uid')
->where($queryBuilder->expr()->eq('region.uid', $queryBuilder->createNamedParameter($regionUid, \PDO::PARAM_INT)))
->setMaxResults(1)
->execute()
->fetchAssociative()
;
if (false === $region) {
return [];
}
$images = $this->serializeImages($this->regionImageService->getImages((int) $region['uid']));
$regionMaps = $this->serializeFileReferences(
$this->fileRepository->findByRelation('tx_epproducts_domain_model_region', 'region_maps', (int) $region['uid'])
);
return [
'name' => $region['name'],
'latitude' => $region['latitude'],
'longitude' => $region['longitude'],
'webcam' => $region['webcamUrl'],
'ski_area' => $region['ski_area'],
'ski_area_extended' => $region['ski_area_extended'],
'description' => $region['description'],
'news' => $region['news'],
'length' => $region['length'],
'altitude' => $region['height'],
'lifts' => $region['lifts'],
'images' => $images,
'region_maps' => $regionMaps,
];
}
/**
* The 'original' entry of AbstractImageService::getImages() holds raw FileReference objects,
* which are needed by Fluid templates elsewhere but serialize to empty objects in JSON responses.
* We replace it with the same {url, alt, title} shape used for 'region_maps'.
*/
private function serializeImages(array $images): array
{
return [
'original' => $this->serializeFileReferences($images['original']),
'resized' => $images['resized'],
];
}
private function serializeFileReferences(array $files): array
{
return array_map(function ($file) {
return [
'url' => $this->imageService->getImageUri($file, true),
'alt' => $file->getProperty('alternative'),
'title' => $file->getProperty('title'),
];
}, $files);
}
}
@@ -0,0 +1,63 @@
<?php
namespace EP\EpProducts\Service;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Extbase\Service\ImageService;
class MyEpImageService extends AbstractImageService
{
/**
* @var string
*/
protected $field = 'images';
/**
* @var array
*/
protected $imageSizes = [
's' => [
'width' => '480',
'height' => '360c-100',
],
'm' => [
'width' => '768',
'height' => '576c-100',
],
'l' => [
'width' => '1280',
'height' => '960c-100',
]
];
public function __construct(FileRepository $fileRepository, ImageService $imageService, FrontendInterface $cache, string $table = 'tx_epproducts_domain_model_hotel')
{
parent::__construct($fileRepository, $imageService, $cache);
$this->table = $table;
}
}
@@ -12,7 +12,7 @@ return [
],
],
'ep/productapi' => [
'target' => \EP\EpProducts\Middleware\ProductApiMiddleware::class,
'target' => \EP\EpProducts\Middleware\ApiMiddleware::class,
'before' => [
'typo3/cms-frontend/page-resolver',
],
@@ -31,3 +31,31 @@ services:
EP\EpProducts\Controller\AjaxCalendarController:
arguments:
$cache: '@cache.ep_cache'
EP\EpProducts\Service\MyEpImageService:
arguments:
$cache: '@cache.ep_cache'
ep_products.image_service.hotel:
class: EP\EpProducts\Service\MyEpImageService
arguments:
$cache: '@cache.ep_cache'
$table: 'tx_epproducts_domain_model_hotel'
ep_products.image_service.product:
class: EP\EpProducts\Service\MyEpImageService
arguments:
$cache: '@cache.ep_cache'
$table: 'tx_epproducts_domain_model_product'
ep_products.image_service.region:
class: EP\EpProducts\Service\MyEpImageService
arguments:
$cache: '@cache.ep_cache'
$table: 'tx_epproducts_domain_model_region'
EP\EpProducts\Middleware\ApiMiddleware:
arguments:
$hotelImageService: '@ep_products.image_service.hotel'
$productImageService: '@ep_products.image_service.product'
$regionImageService: '@ep_products.image_service.region'