Files
myep/src/Service/BookingSummaryDataService.php
T

155 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Service;
use App\Form\Model\BookingDto;
use App\Form\Model\BookingSummaryDto;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
/**
* Consolidates all booking summary data for display in sidebars.
*
* Provides pricing breakdowns, room assignments, participant counts,
* and CMS product information in a single service.
*/
class BookingSummaryDataService
{
public function __construct(
private readonly BookingPriceCalculatorService $priceCalculator,
private readonly CmsDataService $cmsDataService,
private readonly CacheInterface $cache,
private readonly LoggerInterface $logger,
) {
}
/**
* Get complete summary data for booking sidebar.
*/
public function getSummaryData(BookingDto $bookingDto): BookingSummaryDto
{
// Get selected rooms (for Step1 controller compatibility)
$selectedRooms = $bookingDto->getSelectedRooms();
// 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 (for display)
$groupedSelectedRooms = [];
foreach ($roomCounts as $roomId => $count) {
$room = $bookingDto->travel->getRoomById($roomId);
if (null !== $room) {
$groupedSelectedRooms[] = [
'room' => $room,
'count' => $count,
];
}
}
// Get detailed pricing breakdown
$pricingData = $this->priceCalculator->getPricingBreakdown($bookingDto);
// Fetch CMS data (images, etc.)
$cmsData = $this->getCmsData($bookingDto);
// Calculate participant count from room capacity (source of truth)
$participantCount = $this->calculateParticipantCountFromRooms($bookingDto);
return new BookingSummaryDto(
selectedRooms: $selectedRooms,
participantCount: $participantCount,
totalPrice: number_format($totalPrice, 2, ',', '.').' €',
groupedSelectedRooms: $groupedSelectedRooms,
assignmentCounts: $roomCounts,
pricingData: $pricingData,
cmsData: $cmsData,
);
}
/**
* Calculates participant count from room selections.
*
* This is the source of truth for participant count, calculated by
* multiplying each selected room's quantity by its maximum capacity (maxPax).
*/
private function calculateParticipantCountFromRooms(BookingDto $bookingDto): int
{
$totalCapacity = 0;
$availableRooms = $bookingDto->travel->getAvailableRooms();
foreach ($bookingDto->roomSelections as $selection) {
if ($selection->quantity > 0 && isset($availableRooms[$selection->roomId])) {
$room = $availableRooms[$selection->roomId];
$totalCapacity += $selection->quantity * ($room->maxPax ?? 0);
}
}
return $totalCapacity;
}
/**
* Fetches CMS data for the product and hotel in the booking.
*
* Data is cached for 1 hour as it rarely changes. Returns null
* if the API call fails or if product/hotel codes are not available.
*/
private function getCmsData(BookingDto $bookingDto): ?array
{
$productCode = $bookingDto->travel->productCode;
$hotelCode = $bookingDto->travel->hotel?->code;
if (null === $productCode) {
$this->logger->debug('Cannot fetch CMS data: product code is not available', [
'travel_id' => $bookingDto->travel->id,
]);
return null;
}
$cacheKey = sprintf('cms_data.%s.%s', $productCode, $hotelCode ?? 'none');
try {
return $this->cache->get($cacheKey, function (ItemInterface $item) use ($productCode, $hotelCode) {
$item->expiresAfter(3600); // 1 hour
$result = $this->cmsDataService->getProductDetails($productCode, $hotelCode);
// Return null if API call failed
if (true === isset($result['success']) && false === $result['success']) {
$this->logger->warning('CMS API call failed', [
'product_code' => $productCode,
'hotel_code' => $hotelCode,
'message' => $result['message'] ?? 'Unknown error',
]);
return null;
}
return $result;
});
} catch (\Throwable $e) {
$this->logger->error('Failed to fetch CMS data', [
'product_code' => $productCode,
'hotel_code' => $hotelCode,
'exception' => $e->getMessage(),
]);
return null;
}
}
}