diff --git a/src/Controller/Booking/CreateStep1Controller.php b/src/Controller/Booking/CreateStep1Controller.php
index f225675..d9fb319 100644
--- a/src/Controller/Booking/CreateStep1Controller.php
+++ b/src/Controller/Booking/CreateStep1Controller.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller\Booking;
+use App\Exception\NoRoomsAvailableException;
use App\Form\BookingCreateStep1Type;
use App\Service\BookingService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -32,7 +33,13 @@ class CreateStep1Controller extends AbstractController
#[Route('/bookings/create', name: 'app_booking_create_step_1')]
public function index(Request $request): Response
{
- $bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
+ try {
+ $bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
+ } catch (NoRoomsAvailableException $e) {
+ $this->addFlash('error', 'Leider sind für diese Reise aktuell keine Zimmer verfügbar.');
+ // TODO: Redirect to travel listing or hotel details page
+ throw $this->createNotFoundException('No rooms available for this travel.');
+ }
// Get or create baseline snapshot for change detection
$oldRoomSelectionSnapshot = $this->bookingService->getOrCreateBaselineSnapshot($request, $bookingCreateDto);
@@ -83,7 +90,12 @@ class CreateStep1Controller extends AbstractController
#[Route('/bookings/create/room-summary', name: 'app_booking_create_step_1_room_summary', methods: ['POST'])]
public function roomSummary(Request $request): Response
{
- $bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
+ try {
+ $bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
+ } catch (NoRoomsAvailableException $e) {
+ // For HTMX requests, return a simple error message
+ return new Response('
Keine Zimmer verfügbar
', 400);
+ }
// Process the form to update the DTO with the latest room selection
$form = $this->createForm(BookingCreateStep1Type::class, $bookingCreateDto, [
diff --git a/src/Controller/Booking/CreateStep2Controller.php b/src/Controller/Booking/CreateStep2Controller.php
index 1269772..b095a70 100644
--- a/src/Controller/Booking/CreateStep2Controller.php
+++ b/src/Controller/Booking/CreateStep2Controller.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Controller\Booking;
use App\Controller\Traits\HtmxControllerTrait;
+use App\Exception\NoRoomsAvailableException;
use App\Form\BookingCreateStep2Type;
use App\Form\Model\BookingCreateDto;
use App\Form\Model\ParticipantDto;
@@ -38,9 +39,15 @@ class CreateStep2Controller extends AbstractController
#[Route('/bookings/create/participants', name: 'app_booking_create_step_2')]
public function participants(Request $request): Response
{
- $bookingCreateDto = $this
- ->bookingService
- ->getOrCreateBookingCreateDto($request);
+ try {
+ $bookingCreateDto = $this
+ ->bookingService
+ ->getOrCreateBookingCreateDto($request);
+ } catch (NoRoomsAvailableException $e) {
+ $this->addFlash('error', 'Leider sind für diese Reise aktuell keine Zimmer verfügbar.');
+ // TODO: Redirect to travel listing or hotel details page
+ throw $this->createNotFoundException('No rooms available for this travel.');
+ }
// Enrich with fresh availability data
$this->enrichWithFreshAvailabilities($bookingCreateDto);
@@ -93,7 +100,12 @@ class CreateStep2Controller extends AbstractController
#[Route('/bookings/create/participants/refresh', name: 'app_booking_create_step_2_refresh', methods: ['POST'])]
public function refreshParticipantForm(Request $request): Response
{
- $bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
+ try {
+ $bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
+ } catch (NoRoomsAvailableException $e) {
+ // For HTMX requests, return a simple error message
+ return new Response('Keine Zimmer verfügbar
', 400);
+ }
// Enrich with fresh availability data
$this->enrichWithFreshAvailabilities($bookingCreateDto);
diff --git a/src/Controller/Booking/CreateStep3Controller.php b/src/Controller/Booking/CreateStep3Controller.php
index 28189f6..065e19f 100644
--- a/src/Controller/Booking/CreateStep3Controller.php
+++ b/src/Controller/Booking/CreateStep3Controller.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller\Booking;
+use App\Exception\NoRoomsAvailableException;
use App\Service\BookingService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
@@ -31,7 +32,13 @@ class CreateStep3Controller extends AbstractController
#[Route('/bookings/create/confirm', name: 'app_booking_create_step_3')]
public function confirm(Request $request): Response
{
- $bookingCreateDto = $this->bookingCreateService->getOrCreateBookingCreateDto($request);
+ try {
+ $bookingCreateDto = $this->bookingCreateService->getOrCreateBookingCreateDto($request);
+ } catch (NoRoomsAvailableException $e) {
+ $this->addFlash('error', 'Leider sind für diese Reise aktuell keine Zimmer verfügbar.');
+ // TODO: Redirect to travel listing or hotel details page
+ throw $this->createNotFoundException('No rooms available for this travel.');
+ }
// Validate step access
$this->validateStepAccess($bookingCreateDto, 3);
diff --git a/src/Exception/NoRoomsAvailableException.php b/src/Exception/NoRoomsAvailableException.php
new file mode 100644
index 0000000..9d8a012
--- /dev/null
+++ b/src/Exception/NoRoomsAvailableException.php
@@ -0,0 +1,27 @@
+processRoomQuantities($request);
$availableRooms = $travelData->getAvailableRooms();
+ // Prevent booking flow entry when no rooms are available
+ if (empty($availableRooms)) {
+ throw new NoRoomsAvailableException($dateId, $hotelId);
+ }
+
$roomSelections = array_map(
fn (Room $room) => $this->createRoomSelection($room, $roomsIdsAndQuantities),
$availableRooms