accommodationId = 1; $session = new Session(new MockArraySessionStorage()); $request = Request::create('/groups/booking/step-1', 'POST', [ 'date_from' => '2026-08-03', 'date_to' => '2026-08-07', ]); $request->setSession($session); $sessionManager = new AccommodationSessionManager(); $sessionManager->save($request, $dto); $accommodation = (new Accommodation()) ->setName('Hotel') ->setCalendarCode('HOTEL') ->setMaxAdolescentAge(17); $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService ->method('applyDates') ->willReturnCallback(static function (AccommodationBookingDto $dto): void { $dto->dateFrom = new \DateTimeImmutable('2026-08-03'); $dto->dateTo = new \DateTimeImmutable('2026-08-07'); }); $bookingService ->method('loadAccommodation') ->with(1) ->willReturn($accommodation); $bookingService ->method('computeInitialPaxCount') ->willReturn(4); $controller = $this->makeController($bookingService, $sessionManager); $response = $controller->index($request); self::assertInstanceOf(RedirectResponse::class, $response); self::assertSame('/app_groups_booking_step_2', $response->headers->get('Location')); $savedDto = $sessionManager->getOrFail($request); self::assertSame(2, $savedDto->currentStep); self::assertSame(4, $savedDto->paxCount); self::assertNull($savedDto->selectedBoardServiceId); self::assertSame([], $savedDto->selectedAdditionalServiceIds); } public function testPostWithInvalidDatesRedirectsBackWithFlash(): void { $dto = new AccommodationBookingDto(); $dto->accommodationId = 1; $session = new Session(new MockArraySessionStorage()); $request = Request::create('/groups/booking/step-1', 'POST', [ 'date_from' => 'not-a-date', 'date_to' => '2026-08-07', ]); $request->setSession($session); $sessionManager = new AccommodationSessionManager(); $sessionManager->save($request, $dto); $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService ->method('applyDates') ->willThrowException(new \InvalidArgumentException('Ungültiges Datumsformat. Erwartet: YYYY-MM-DD.')); $controller = $this->makeController($bookingService, $sessionManager); $response = $controller->index($request); self::assertInstanceOf(RedirectResponse::class, $response); self::assertSame('/app_groups_booking_step_1', $response->headers->get('Location')); } private function makeController( AccommodationBookingService $bookingService, AccommodationSessionManager $sessionManager, ): TestableAccommodationStep1Controller { $priceRepository = $this->createMock(AccommodationPriceRepository::class); return new TestableAccommodationStep1Controller( $bookingService, $sessionManager, $this->createMock(ContingentsClient::class), $priceRepository, new PriceTimelineBuilder(), $this->createMock(CacheInterface::class), new CalendarGridBuilder(), new GroupsPriceCalculator(new PriceTimelineBuilder(), ['runningCostsEur' => 0, 'runningCostsChf' => 0, 'undersubscription30Eur' => 0, 'undersubscription30Chf' => 0, 'undersubscription40Eur' => 0, 'undersubscription40Chf' => 0]), new AccommodationPriceCoverage($priceRepository), ); } } final class TestableAccommodationStep1Controller extends Step1Controller { public function __construct( AccommodationBookingService $bookingService, AccommodationSessionManager $sessionManager, ContingentsClient $contingentsClient, AccommodationPriceRepository $priceRepository, PriceTimelineBuilder $priceTimelineBuilder, CacheInterface $cache, CalendarGridBuilder $calendarGridBuilder, GroupsPriceCalculator $priceCalculator, AccommodationPriceCoverage $priceCoverage, ) { parent::__construct( $bookingService, $sessionManager, $contingentsClient, $priceRepository, $priceTimelineBuilder, $cache, $calendarGridBuilder, $priceCalculator, $priceCoverage, ); } /** * @param array $parameters */ protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse { return new RedirectResponse('/'.$route, $status); } /** * @param array $parameters */ protected function render(string $view, array $parameters = [], ?Response $response = null): Response { throw new \LogicException('Render should not be called in this test.'); } protected function addFlash(string $type, mixed $message): void { } }