feat: fetch additional content from cms via api

This commit is contained in:
Björn Fromme
2026-03-16 11:59:11 +01:00
parent fc05350ae4
commit a8c0a1aa61
18 changed files with 107 additions and 124 deletions
+1
View File
@@ -103,3 +103,4 @@ services:
App\Service\CmsDataService: App\Service\CmsDataService:
arguments: arguments:
$httpClient: '@typo3.client' $httpClient: '@typo3.client'
$apiKey: 'AbcAbc123'# dummy key, not yet implemented
+3
View File
@@ -26,6 +26,9 @@ class Travel
#[Groups(['api:list', 'api:single'])] #[Groups(['api:list', 'api:single'])]
public ?string $code = null; public ?string $code = null;
#[Groups(['api:list', 'api:single'])]
public ?string $productCode = null;
#[Groups(['api:list', 'api:single'])] #[Groups(['api:list', 'api:single'])]
public ?string $label = null; public ?string $label = null;
+7
View File
@@ -54,6 +54,13 @@ class TravelParser extends AbstractParser
$travel->dateFrom = $dateFrom; $travel->dateFrom = $dateFrom;
$travel->dateTo = $dateTo; $travel->dateTo = $dateTo;
$travel->code = $node->attr('code'); $travel->code = $node->attr('code');
// Parse product code from parent reise node using DOM
$domNode = $node->getNode(0);
if (null !== $domNode && null !== $domNode->parentNode) {
$travel->productCode = $domNode->parentNode->getAttribute('code');
}
$travel->type = $node->attr('reiseart'); $travel->type = $node->attr('reiseart');
$travel->status = $this->getStringOrNullValue($node->filterXPath('//status_hin')); $travel->status = $this->getStringOrNullValue($node->filterXPath('//status_hin'));
$travel->priceFrom = $this->stringToFloat($this->getStringOrNullValue($node->filterXPath('//abpreis'))); $travel->priceFrom = $this->stringToFloat($this->getStringOrNullValue($node->filterXPath('//abpreis')));
@@ -9,6 +9,7 @@ use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
use App\Form\BookingCreateStep1Type; use App\Form\BookingCreateStep1Type;
use App\Htmx\HxTrait; use App\Htmx\HxTrait;
use App\Service\BookingService; use App\Service\BookingService;
use App\Service\BookingSummaryDataService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@@ -28,6 +29,7 @@ class Step1Controller extends AbstractController
public function __construct( public function __construct(
private readonly BookingService $bookingService, private readonly BookingService $bookingService,
private readonly BookingSummaryDataService $summaryDataService,
) { ) {
} }
@@ -46,8 +48,6 @@ class Step1Controller extends AbstractController
// Get or create baseline snapshot for change detection // Get or create baseline snapshot for change detection
$oldRoomSelectionSnapshot = $this->bookingService->getOrCreateBaselineSnapshot($request, $bookingCreateDto); $oldRoomSelectionSnapshot = $this->bookingService->getOrCreateBaselineSnapshot($request, $bookingCreateDto);
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto);
// Validate step access - allow step 1 or redirect to current step // Validate step access - allow step 1 or redirect to current step
if ($redirect = $this->validateStepAccess($bookingCreateDto, 1)) { if ($redirect = $this->validateStepAccess($bookingCreateDto, 1)) {
return $redirect; return $redirect;
@@ -79,6 +79,9 @@ class Step1Controller extends AbstractController
return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2')); return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2'));
} }
// Get complete summary data (pricing, rooms, CMS data)
$summary = $this->summaryDataService->getSummaryData($bookingCreateDto);
$availableRooms = $bookingCreateDto->travel->getAvailableRooms(); $availableRooms = $bookingCreateDto->travel->getAvailableRooms();
$groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms); $groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms);
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms); $groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms);
@@ -87,7 +90,8 @@ class Step1Controller extends AbstractController
'bookingCreateDto' => $bookingCreateDto, 'bookingCreateDto' => $bookingCreateDto,
'roomSummary' => $summary['selectedRooms'], 'roomSummary' => $summary['selectedRooms'],
'participantCount' => $summary['participantCount'], 'participantCount' => $summary['participantCount'],
'pricingData' => $summary['pricing'], 'pricingData' => $summary['pricingData'],
'cmsData' => $summary['cmsData'],
'form' => $form->createView(), 'form' => $form->createView(),
'groupedRooms' => $groupedRooms, 'groupedRooms' => $groupedRooms,
'groupedSelectedRooms' => $groupedSelectedRooms, 'groupedSelectedRooms' => $groupedSelectedRooms,
@@ -115,7 +119,8 @@ class Step1Controller extends AbstractController
$this->bookingService->saveBookingCreateDto($request, $bookingCreateDto); $this->bookingService->saveBookingCreateDto($request, $bookingCreateDto);
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto); // Get complete summary data (pricing, rooms, CMS data)
$summary = $this->summaryDataService->getSummaryData($bookingCreateDto);
$availableRooms = $bookingCreateDto->travel->getAvailableRooms(); $availableRooms = $bookingCreateDto->travel->getAvailableRooms();
$groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms); $groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms);
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms); $groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms);
@@ -129,7 +134,8 @@ class Step1Controller extends AbstractController
'form' => $form->createView(), 'form' => $form->createView(),
'bookingCreateDto' => $bookingCreateDto, 'bookingCreateDto' => $bookingCreateDto,
'participantCount' => $summary['participantCount'], 'participantCount' => $summary['participantCount'],
'pricingData' => $summary['pricing'], 'pricingData' => $summary['pricingData'],
'cmsData' => $summary['cmsData'],
'groupedRooms' => $groupedRooms, 'groupedRooms' => $groupedRooms,
'groupedSelectedRooms' => $groupedSelectedRooms, 'groupedSelectedRooms' => $groupedSelectedRooms,
] ]
@@ -12,8 +12,8 @@ use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto; use App\Form\Model\ParticipantDto;
use App\Form\Service\ParticipantFieldOptionsProvider; use App\Form\Service\ParticipantFieldOptionsProvider;
use App\Htmx\HxTrait; use App\Htmx\HxTrait;
use App\Service\BookingPriceCalculatorService;
use App\Service\BookingService; use App\Service\BookingService;
use App\Service\BookingSummaryDataService;
use App\Service\ParticipantCardDataService; use App\Service\ParticipantCardDataService;
use App\Service\ParticipantPrepopulationService; use App\Service\ParticipantPrepopulationService;
use App\Service\RoomAssignmentService; use App\Service\RoomAssignmentService;
@@ -38,7 +38,7 @@ class Step2Controller extends AbstractController
public function __construct( public function __construct(
private readonly BookingService $bookingService, private readonly BookingService $bookingService,
private readonly BookingPriceCalculatorService $priceCalculator, private readonly BookingSummaryDataService $summaryDataService,
private readonly TravelDataService $travelDataService, private readonly TravelDataService $travelDataService,
private readonly RoomAssignmentService $roomAssignmentService, private readonly RoomAssignmentService $roomAssignmentService,
private readonly ParticipantCardDataService $participantCardService, private readonly ParticipantCardDataService $participantCardService,
@@ -99,18 +99,16 @@ class Step2Controller extends AbstractController
? $this->participantCardService->getAllCardsDataWithValidation($bookingCreateDto) ? $this->participantCardService->getAllCardsDataWithValidation($bookingCreateDto)
: $this->generateAllCardsData($bookingCreateDto); : $this->generateAllCardsData($bookingCreateDto);
// Calculate summary data // Get complete summary data (pricing, rooms, CMS data)
$summaryData = $this->calculateSummaryData($bookingCreateDto); $summaryData = $this->summaryDataService->getSummaryData($bookingCreateDto);
// Get detailed pricing data for summary sidebar
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto);
$templateData = [ $templateData = [
'form' => $form->createView(), 'form' => $form->createView(),
'bookingDto' => $bookingCreateDto, 'bookingDto' => $bookingCreateDto,
'cardsData' => $cardsData, 'cardsData' => $cardsData,
'summaryData' => $summaryData, 'summaryData' => $summaryData,
'pricingData' => $summary['pricing'], 'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
]; ];
// HTMX request: render blocks only // HTMX request: render blocks only
@@ -160,18 +158,16 @@ class Step2Controller extends AbstractController
return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2')); return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2'));
} }
// Calculate summary data for sidebar // Get complete summary data (pricing, rooms, CMS data)
$summaryData = $this->calculateSummaryData($bookingDto); $summaryData = $this->summaryDataService->getSummaryData($bookingDto);
// Get detailed pricing data for summary sidebar
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
$templateData = [ $templateData = [
'form' => $form->createView(), 'form' => $form->createView(),
'participantIndex' => $index, 'participantIndex' => $index,
'bookingDto' => $bookingDto, 'bookingDto' => $bookingDto,
'summaryData' => $summaryData, 'summaryData' => $summaryData,
'pricingData' => $summary['pricing'], 'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
'refreshRouteName' => 'app_booking_create_step_2_participant_refresh', 'refreshRouteName' => 'app_booking_create_step_2_participant_refresh',
'submitRouteName' => 'app_booking_create_step_2_participant', 'submitRouteName' => 'app_booking_create_step_2_participant',
]; ];
@@ -12,8 +12,8 @@ use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
use App\Form\BookingCreateStep3Type; use App\Form\BookingCreateStep3Type;
use App\Form\Model\BookingDto; use App\Form\Model\BookingDto;
use App\Htmx\HxTrait; use App\Htmx\HxTrait;
use App\Service\BookingPriceCalculatorService;
use App\Service\BookingService; use App\Service\BookingService;
use App\Service\BookingSummaryDataService;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
@@ -32,8 +32,8 @@ class Step3Controller extends AbstractController
public function __construct( public function __construct(
private readonly BookingService $bookingService, private readonly BookingService $bookingService,
private readonly BookingSummaryDataService $summaryDataService,
private readonly ApiClient $apiClient, private readonly ApiClient $apiClient,
private readonly BookingPriceCalculatorService $priceCalculator,
private readonly LoggerInterface $logger, private readonly LoggerInterface $logger,
) { ) {
} }
@@ -172,10 +172,19 @@ class Step3Controller extends AbstractController
*/ */
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
{ {
// Get complete summary data (pricing, rooms, CMS data)
$summaryData = $this->summaryDataService->getSummaryData($bookingCreateDto);
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summaryData['selectedRooms'], $availableRooms);
return $this->render('booking/create/step_3.html.twig', [ return $this->render('booking/create/step_3.html.twig', [
'bookingCreateDto' => $bookingCreateDto, 'bookingCreateDto' => $bookingCreateDto,
'form' => $form->createView(), 'form' => $form->createView(),
...$this->getSummaryVariables($bookingCreateDto), 'participantCount' => $summaryData['participantCount'],
'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
'assignmentCounts' => $summaryData['assignmentCounts'],
'groupedSelectedRooms' => $groupedSelectedRooms,
]); ]);
} }
} }
@@ -14,6 +14,7 @@ use App\Form\Model\BookingDto;
use App\Htmx\HxTrait; use App\Htmx\HxTrait;
use App\Service\BookingPriceCalculatorService; use App\Service\BookingPriceCalculatorService;
use App\Service\BookingService; use App\Service\BookingService;
use App\Service\BookingSummaryDataService;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
@@ -32,6 +33,7 @@ class Step4Controller extends AbstractController
public function __construct( public function __construct(
private readonly BookingService $bookingService, private readonly BookingService $bookingService,
private readonly BookingSummaryDataService $summaryDataService,
private readonly BookingPriceCalculatorService $priceCalculator, private readonly BookingPriceCalculatorService $priceCalculator,
private readonly ApiClient $apiClient, private readonly ApiClient $apiClient,
private readonly LoggerInterface $logger, private readonly LoggerInterface $logger,
@@ -128,10 +130,19 @@ class Step4Controller extends AbstractController
*/ */
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
{ {
// Get complete summary data (pricing, rooms, CMS data)
$summaryData = $this->summaryDataService->getSummaryData($bookingCreateDto);
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summaryData['selectedRooms'], $availableRooms);
return $this->render('booking/create/step_4.html.twig', [ return $this->render('booking/create/step_4.html.twig', [
'bookingCreateDto' => $bookingCreateDto, 'bookingCreateDto' => $bookingCreateDto,
'form' => $form->createView(), 'form' => $form->createView(),
...$this->getSummaryVariables($bookingCreateDto), 'participantCount' => $summaryData['participantCount'],
'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
'assignmentCounts' => $summaryData['assignmentCounts'],
'groupedSelectedRooms' => $groupedSelectedRooms,
'participantPrices' => $this->priceCalculator->calculateAllParticipantIndividualPrices($bookingCreateDto), 'participantPrices' => $this->priceCalculator->calculateAllParticipantIndividualPrices($bookingCreateDto),
]); ]);
} }
+15 -15
View File
@@ -21,8 +21,8 @@ use App\Form\Service\ParticipantFieldHandlerRegistry;
use App\Htmx\HxTrait; use App\Htmx\HxTrait;
use App\Security\Crypt; use App\Security\Crypt;
use App\Service\BookingFingerprintService; use App\Service\BookingFingerprintService;
use App\Service\BookingPriceCalculatorService;
use App\Service\BookingService; use App\Service\BookingService;
use App\Service\BookingSummaryDataService;
use App\Service\ParticipantCardDataService; use App\Service\ParticipantCardDataService;
use App\Service\TravelDataService; use App\Service\TravelDataService;
use Psr\Cache\InvalidArgumentException; use Psr\Cache\InvalidArgumentException;
@@ -57,7 +57,7 @@ class IndexController extends AbstractController
private readonly TravelDataService $travelDataService, private readonly TravelDataService $travelDataService,
private readonly BookingService $bookingService, private readonly BookingService $bookingService,
private readonly BookingFingerprintService $fingerprintService, private readonly BookingFingerprintService $fingerprintService,
private readonly BookingPriceCalculatorService $priceCalculator, private readonly BookingSummaryDataService $summaryDataService,
private readonly ParticipantCardDataService $participantCardService, private readonly ParticipantCardDataService $participantCardService,
private readonly ParticipantFieldHandlerRegistry $fieldHandlerRegistry, private readonly ParticipantFieldHandlerRegistry $fieldHandlerRegistry,
private readonly CacheInterface $cache, private readonly CacheInterface $cache,
@@ -166,9 +166,8 @@ class IndexController extends AbstractController
? $this->participantCardService->getAllCardsDataWithValidation($bookingDto) ? $this->participantCardService->getAllCardsDataWithValidation($bookingDto)
: $this->participantCardService->getAllCardsData($bookingDto); : $this->participantCardService->getAllCardsData($bookingDto);
// Calculate summary data for sidebar // Get complete summary data (pricing, rooms, CMS data)
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto); $summaryData = $this->summaryDataService->getSummaryData($bookingDto);
$roomAssignmentCounts = $this->bookingService->getRoomAssignmentCounts($bookingDto);
// Group selected rooms for summary display // Group selected rooms for summary display
$availableRooms = $bookingDto->travel->getAvailableRooms(); $availableRooms = $bookingDto->travel->getAvailableRooms();
@@ -184,9 +183,10 @@ class IndexController extends AbstractController
'mutableData' => $mutableData, 'mutableData' => $mutableData,
'cardsData' => $cardsData, 'cardsData' => $cardsData,
'participantsCount' => count($bookingDto->participants), 'participantsCount' => count($bookingDto->participants),
'pricingData' => $summary['pricing'], 'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
'groupedSelectedRooms' => $groupedSelectedRooms, 'groupedSelectedRooms' => $groupedSelectedRooms,
'assignmentCounts' => $roomAssignmentCounts, 'assignmentCounts' => $summaryData['assignmentCounts'],
'isDirty' => $this->fingerprintService->isDirty($bookingDto), 'isDirty' => $this->fingerprintService->isDirty($bookingDto),
'hasValidationErrors' => $form->isSubmitted() && false === $form->isValid(), 'hasValidationErrors' => $form->isSubmitted() && false === $form->isValid(),
]; ];
@@ -275,9 +275,8 @@ class IndexController extends AbstractController
return $this->hxRedirect($request, $this->generateUrl('app_booking_edit', ['id' => $id])); return $this->hxRedirect($request, $this->generateUrl('app_booking_edit', ['id' => $id]));
} }
// Calculate summary data using trait helper // Get complete summary data (pricing, rooms, CMS data)
$summaryData = $this->calculateSummaryData($bookingDto); $summaryData = $this->summaryDataService->getSummaryData($bookingDto);
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
// Fetch mutable data for form constraints // Fetch mutable data for form constraints
$mutableData = $this->travelDataService->getMutabilityData($bookingData->dateId); $mutableData = $this->travelDataService->getMutabilityData($bookingData->dateId);
@@ -289,7 +288,8 @@ class IndexController extends AbstractController
'bookingData' => $bookingData, 'bookingData' => $bookingData,
'mutableData' => $mutableData, 'mutableData' => $mutableData,
'summaryData' => $summaryData, 'summaryData' => $summaryData,
'pricingData' => $summary['pricing'], 'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
'refreshRouteName' => 'app_booking_edit_participant_refresh', 'refreshRouteName' => 'app_booking_edit_participant_refresh',
'refreshRouteParams' => ['id' => $id, 'index' => $index], 'refreshRouteParams' => ['id' => $id, 'index' => $index],
'submitRouteName' => 'app_booking_edit_participant', 'submitRouteName' => 'app_booking_edit_participant',
@@ -374,9 +374,8 @@ class IndexController extends AbstractController
$participant->notifications = []; $participant->notifications = [];
} }
// Calculate summary data using trait helper // Get complete summary data (pricing, rooms, CMS data)
$summaryData = $this->calculateSummaryData($bookingDto); $summaryData = $this->summaryDataService->getSummaryData($bookingDto);
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
// Render form + sidebar using htmxOobResponse // Render form + sidebar using htmxOobResponse
$response = $this->htmxOobResponse( $response = $this->htmxOobResponse(
@@ -389,7 +388,8 @@ class IndexController extends AbstractController
'bookingData' => $bookingData, 'bookingData' => $bookingData,
'mutableData' => $mutableData, 'mutableData' => $mutableData,
'summaryData' => $summaryData, 'summaryData' => $summaryData,
'pricingData' => $summary['pricing'], 'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
'refreshRouteName' => 'app_booking_edit_participant_refresh', 'refreshRouteName' => 'app_booking_edit_participant_refresh',
'refreshRouteParams' => ['id' => $id, 'index' => $index], 'refreshRouteParams' => ['id' => $id, 'index' => $index],
'submitRouteName' => 'app_booking_edit_participant', 'submitRouteName' => 'app_booking_edit_participant',
@@ -76,52 +76,6 @@ trait ParticipantCardFlowTrait
return $this->createForm(BookingParticipantType::class, $wrapper, $formOptions); return $this->createForm(BookingParticipantType::class, $wrapper, $formOptions);
} }
/**
* Calculate summary data (pricing, room counts, etc.).
*
* @return array{
* participantsCount: int,
* totalPrice: string,
* groupedSelectedRooms: array,
* assignmentCounts: array
* }
*/
private function calculateSummaryData(BookingDto $bookingDto): array
{
// Calculate individual prices for all participants
$participantPrices = $this->priceCalculator->calculateAllParticipantIndividualPrices($bookingDto);
// Calculate total price
$totalPrice = array_sum($participantPrices);
// Get room assignment counts
$roomCounts = [];
foreach ($bookingDto->participants as $participant) {
if (null !== $participant->assignedRoomId) {
$roomCounts[$participant->assignedRoomId] = ($roomCounts[$participant->assignedRoomId] ?? 0) + 1;
}
}
// Group selected rooms with counts
$groupedSelectedRooms = [];
foreach ($roomCounts as $roomId => $count) {
$room = $bookingDto->travel->getRoomById($roomId);
if (null !== $room) {
$groupedSelectedRooms[] = [
'room' => $room,
'count' => $count,
];
}
}
return [
'participantsCount' => count($bookingDto->participants),
'totalPrice' => number_format($totalPrice, 2, ',', '.').' €',
'groupedSelectedRooms' => $groupedSelectedRooms,
'assignmentCounts' => $roomCounts,
];
}
/** /**
* Process single participant form refresh. * Process single participant form refresh.
* *
@@ -155,11 +109,8 @@ trait ParticipantCardFlowTrait
// Save updated booking data to session (after collecting & clearing notifications) // Save updated booking data to session (after collecting & clearing notifications)
$this->bookingService->saveBookingDto($request, $bookingDto, $bookingDto->getMode()); $this->bookingService->saveBookingDto($request, $bookingDto, $bookingDto->getMode());
// Calculate summary data for sidebar // Get complete summary data (pricing, rooms, CMS data)
$summaryData = $this->calculateSummaryData($bookingDto); $summaryData = $this->summaryDataService->getSummaryData($bookingDto);
// Get detailed pricing data for summary sidebar
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
// Render form and sidebar with OOB swap using htmxOobResponse // Render form and sidebar with OOB swap using htmxOobResponse
// This renders ONLY the specific blocks, not the entire template // This renders ONLY the specific blocks, not the entire template
@@ -171,7 +122,8 @@ trait ParticipantCardFlowTrait
'participantIndex' => $index, 'participantIndex' => $index,
'bookingDto' => $bookingDto, 'bookingDto' => $bookingDto,
'summaryData' => $summaryData, 'summaryData' => $summaryData,
'pricingData' => $summary['pricing'], 'pricingData' => $summaryData['pricingData'],
'cmsData' => $summaryData['cmsData'],
'refreshRouteName' => $refreshRouteName, 'refreshRouteName' => $refreshRouteName,
'submitRouteName' => $submitRouteName, 'submitRouteName' => $submitRouteName,
] ]
@@ -193,7 +145,7 @@ trait ParticipantCardFlowTrait
* Controllers using this trait must have the following properties: * Controllers using this trait must have the following properties:
* - BookingService $bookingService * - BookingService $bookingService
* - ParticipantCardDataService $participantCardService * - ParticipantCardDataService $participantCardService
* - BookingPriceCalculatorService $priceCalculator * - BookingSummaryDataService $summaryDataService
*/ */
abstract private function createForm(string $type, $data = null, array $options = []): FormInterface; abstract private function createForm(string $type, $data = null, array $options = []): FormInterface;
+6 -24
View File
@@ -7,36 +7,18 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
class CmsDataService class CmsDataService
{ {
public const MODE_PRODUCT = 'product'; public function __construct(private readonly HttpClientInterface $httpClient, private readonly string $apiKey)
public const MODE_HOTEL = 'hotel';
public function __construct(private readonly HttpClientInterface $httpClient)
{ {
} }
public function getProductDetails(string $code): array public function getProductDetails(string $productCode, ?string $hotelCode = null): array
{ {
return $this->makeApiCall(static::MODE_PRODUCT, $code);
}
public function getHotelDetails(string $code): array
{
return $this->makeApiCall(static::MODE_HOTEL, $code);
}
public function makeApiCall(string $mode, string $code): array
{
if (false === in_array($mode, [self::MODE_PRODUCT, self::MODE_HOTEL])) {
throw new \InvalidArgumentException('Invalid mode provided');
}
try { try {
$request = $this->httpClient->request('GET', '/', [ $request = $this->httpClient->request('GET', 'api/product', [
'query' => [ 'query' => [
'type' => 1720, 'product' => $productCode,
'tx_epproducts_api[code]' => $code, 'hotel' => $hotelCode,
'tx_epproducts_api[action]' => $mode, 'key' => $this->apiKey,
'tx_epproducts_api[controller]' => 'Api',
], ],
]); ]);
} catch (ExceptionInterface $e) { } catch (ExceptionInterface $e) {
+10 -1
View File
@@ -45,7 +45,16 @@
{# Travel Information #} {# Travel Information #}
<div class="mb-6 pb-4 border-b border-gray-200"> <div class="mb-6 pb-4 border-b border-gray-200">
<h4 class="font-semibold text-lg mb-3 text-gray-800">Reiseinformationen</h4> {% if cmsData.hotel.images is defined %}
<img src="{{ cmsData.hotel.images.resized.l[0].url }}" alt="{{ cmsData.hotel.images.resized.s[0].alt }}" class="w-full rounded mb-4">
{% endif %}
{% if cmsData.hotel.address is defined %}
<address>
{{ cmsData.hotel.name }}
<br>
{{ cmsData.hotel.address | nl2br }}
</address>
{% endif %}
<div class="space-y-2 text-sm text-gray-600"> <div class="space-y-2 text-sm text-gray-600">
<div><span class="font-medium">Reise:</span> {{ bookingCreateDto.travel.label }}</div> <div><span class="font-medium">Reise:</span> {{ bookingCreateDto.travel.label }}</div>
<div><span class="font-medium">Zeitraum:</span> {{ bookingCreateDto.travel.dateFrom|date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo|date('d.m.Y') }}</div> <div><span class="font-medium">Zeitraum:</span> {{ bookingCreateDto.travel.dateFrom|date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo|date('d.m.Y') }}</div>
@@ -69,6 +69,7 @@
'bookingCreateDto': bookingCreateDto, 'bookingCreateDto': bookingCreateDto,
'participantCount': participantCount, 'participantCount': participantCount,
'pricingData': pricingData, 'pricingData': pricingData,
'cmsData': cmsData,
'groupedSelectedRooms': groupedSelectedRooms, 'groupedSelectedRooms': groupedSelectedRooms,
'assignmentCounts': [] 'assignmentCounts': []
} %} } %}
+3 -2
View File
@@ -64,10 +64,11 @@
<div id="booking-summary"{% if htmx_oob_swap|default(false) %} hx-swap-oob="true"{% endif %}> <div id="booking-summary"{% if htmx_oob_swap|default(false) %} hx-swap-oob="true"{% endif %}>
{% include 'booking/_summary.html.twig' with { {% include 'booking/_summary.html.twig' with {
'bookingCreateDto': bookingDto, 'bookingCreateDto': bookingDto,
'participantCount': summaryData.participantsCount, 'participantCount': summaryData.participantCount,
'groupedSelectedRooms': summaryData.groupedSelectedRooms, 'groupedSelectedRooms': summaryData.groupedSelectedRooms,
'assignmentCounts': summaryData.assignmentCounts, 'assignmentCounts': summaryData.assignmentCounts,
'pricingData': pricingData 'pricingData': pricingData,
'cmsData': cmsData
} %} } %}
</div> </div>
{% endblock %} {% endblock %}
@@ -14,10 +14,11 @@
<div id="booking-summary"> <div id="booking-summary">
{% include 'booking/_summary.html.twig' with { {% include 'booking/_summary.html.twig' with {
'bookingCreateDto': bookingDto, 'bookingCreateDto': bookingDto,
'participantCount': summaryData.participantsCount, 'participantCount': summaryData.participantCount,
'groupedSelectedRooms': summaryData.groupedSelectedRooms, 'groupedSelectedRooms': summaryData.groupedSelectedRooms,
'assignmentCounts': summaryData.assignmentCounts, 'assignmentCounts': summaryData.assignmentCounts,
'pricingData': pricingData 'pricingData': pricingData,
'cmsData': cmsData
} %} } %}
</div> </div>
</div> </div>
+3 -1
View File
@@ -59,7 +59,9 @@
<div id="booking-summary"> <div id="booking-summary">
{% include 'booking/_summary.html.twig' with { {% include 'booking/_summary.html.twig' with {
'bookingCreateDto': bookingCreateDto, 'bookingCreateDto': bookingCreateDto,
'participantCount': participantsCount, 'participantCount': participantCount,
'pricingData': pricingData,
'cmsData': cmsData,
'groupedSelectedRooms': groupedSelectedRooms, 'groupedSelectedRooms': groupedSelectedRooms,
'assignmentCounts': assignmentCounts 'assignmentCounts': assignmentCounts
} %} } %}
+1 -1
View File
@@ -98,7 +98,7 @@
{# Participants Summary #} {# Participants Summary #}
<div class="mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200"> <div class="mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200">
<h3 class="text-xl font-semibold mb-4">Teilnehmer ({{ participantsCount }})</h3> <h3 class="text-xl font-semibold mb-4">Teilnehmer ({{ participantCount }})</h3>
{% for participant in bookingCreateDto.participants %} {% for participant in bookingCreateDto.participants %}
<div class="mb-6 pb-6 {% if not loop.last %}border-b border-gray-300{% endif %}"> <div class="mb-6 pb-6 {% if not loop.last %}border-b border-gray-300{% endif %}">
<div class="flex justify-between items-start mb-3"> <div class="flex justify-between items-start mb-3">
+1
View File
@@ -102,6 +102,7 @@
'bookingCreateDto': bookingDto, 'bookingCreateDto': bookingDto,
'participantCount': participantsCount, 'participantCount': participantsCount,
'pricingData': pricingData, 'pricingData': pricingData,
'cmsData': cmsData,
'groupedSelectedRooms': groupedSelectedRooms, 'groupedSelectedRooms': groupedSelectedRooms,
'assignmentCounts': assignmentCounts, 'assignmentCounts': assignmentCounts,
'mutableData': mutableData|default(null) 'mutableData': mutableData|default(null)
+3 -2
View File
@@ -14,10 +14,11 @@
<div id="booking-summary"> <div id="booking-summary">
{% include 'booking/_summary.html.twig' with { {% include 'booking/_summary.html.twig' with {
'bookingCreateDto': bookingDto, 'bookingCreateDto': bookingDto,
'participantCount': summaryData.participantsCount, 'participantCount': summaryData.participantCount,
'groupedSelectedRooms': summaryData.groupedSelectedRooms, 'groupedSelectedRooms': summaryData.groupedSelectedRooms,
'assignmentCounts': summaryData.assignmentCounts, 'assignmentCounts': summaryData.assignmentCounts,
'pricingData': pricingData 'pricingData': pricingData,
'cmsData': cmsData
} %} } %}
</div> </div>
</div> </div>