wip: booking process, refactoring

This commit is contained in:
Björn Fromme
2025-07-16 19:37:17 +02:00
parent 47faa6b08e
commit eecea0abd1
43 changed files with 2269 additions and 366 deletions
+31 -17
View File
@@ -2,19 +2,20 @@
namespace App\Controller\Booking;
use App\Service\BookingService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use App\Form\BookingCreateStep1Type;
use App\Form\BookingCreateStep2Type;
use App\Form\Model\ParticipantDto;
use App\Service\BookingService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CreateController extends AbstractController
{
public function __construct(
private readonly BookingService $bookingCreateService,
) {
) {
}
#[Route('/bookings/create', name: 'app_booking_create_step_1')]
@@ -25,14 +26,16 @@ class CreateController extends AbstractController
// Validate step access - allow step 1 or redirect to current step
$this->validateStepAccess($bookingCreateDto, 1);
$form = $this->createForm(BookingCreateStep1Type::class, $bookingCreateDto);
$form = $this->createForm(BookingCreateStep1Type::class, $bookingCreateDto, [
'validation_groups' => ['booking_create_step_1'],
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$bookingCreateDto->currentStep = 2;
$this->bookingCreateService->saveBookingCreateDto($request, $bookingCreateDto);
return $this->redirectToRoute('app_booking_create_step_2');
}
@@ -46,18 +49,30 @@ class CreateController extends AbstractController
public function participants(Request $request): Response
{
$bookingCreateDto = $this->bookingCreateService->getOrCreateBookingCreateDto($request);
// Validate step access
$this->validateStepAccess($bookingCreateDto, 2);
$form = $this->createForm(BookingCreateStep2Type::class, $bookingCreateDto);
// Ensure correct number of participants
if ($bookingCreateDto->getParticipantsCount() !== count($bookingCreateDto->participants)) {
$participants = $bookingCreateDto->participants;
$bookingCreateDto->participants = [];
for ($i = 0; $i < $bookingCreateDto->getParticipantsCount(); ++$i) {
$bookingCreateDto->participants[] = $participants[$i] ?? new ParticipantDto();
}
}
$form = $this->createForm(BookingCreateStep2Type::class, $bookingCreateDto, [
'attr' => ['novalidate' => 'novalidate'],
'validation_groups' => ['booking_create_step_2'],
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$bookingCreateDto->currentStep = 3;
$this->bookingCreateService->saveBookingCreateDto($request, $bookingCreateDto);
return $this->redirectToRoute('app_booking_create_step_3');
}
@@ -74,7 +89,7 @@ class CreateController extends AbstractController
// Validate step access
$this->validateStepAccess($bookingCreateDto, 3);
return $this->render('booking/confirm.html.twig', [
'bookingCreateDto' => $bookingCreateDto,
]);
@@ -84,14 +99,13 @@ class CreateController extends AbstractController
* Validates step access and redirects if necessary.
*
* @param \App\Form\Model\BookingCreateDto $bookingCreateDto
* @param int $expectedStep
*/
private function validateStepAccess($bookingCreateDto, int $expectedStep): void
{
// Allow access to current step or any previous step
if ($expectedStep > $bookingCreateDto->currentStep) {
$this->addFlash('error', 'Bitte erst die vorherigen Schritte abschließen.');
$this->redirectToCurrentStep($bookingCreateDto);
}
}
@@ -102,17 +116,17 @@ class CreateController extends AbstractController
private function redirectToCurrentStep($bookingCreateDto): void
{
$routeParams = [
'travel_id' => $bookingCreateDto->travelData->id,
'date_id' => $bookingCreateDto->travelData->id,
'hotel_id' => $bookingCreateDto->travelData->hotelId,
];
$route = match ($bookingCreateDto->currentStep) {
1 => 'app_booking_create_step_1',
2 => 'app_booking_create_step_2',
2 => 'app_booking_create_step_2',
3 => 'app_booking_create_step_3',
default => 'app_booking_create_step_1',
};
$this->redirectToRoute($route, $routeParams);
}
}
}
@@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Cache\CacheInterface;
use function Symfony\Component\String\u;
class DownloadController extends AbstractController
+10 -18
View File
@@ -6,12 +6,12 @@ use App\BusProNet\ApiClient;
use App\BusProNet\Exception\ApiClientException;
use App\BusProNet\Model\Notification;
use App\BusProNet\XmlLoader\PickupLoader;
use App\BusProNet\XmlLoader\TravelLoader;
use App\Controller\Traits\BookingDataTrait;
use App\Entity\User;
use App\Form\BookingEditType;
use App\Form\Model\BookingEditDto;
use App\Security\Crypt;
use App\Service\TravelDataService;
use Psr\Cache\InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -28,7 +28,7 @@ class EditController extends AbstractController
public function __construct(
private readonly ApiClient $apiClient,
private readonly TravelLoader $travelDataLoader,
private readonly TravelDataService $travelDataService,
private readonly PickupLoader $pickupDataLoader,
private readonly CacheInterface $cache,
private readonly Security $security,
@@ -58,7 +58,7 @@ class EditController extends AbstractController
$this->denyAccessUnlessGranted('EDIT', $bookingData);
// Load according travel data
$travelData = $this->travelDataLoader->loadById($bookingData->travelId);
$travelData = $this->travelDataService->getTravelData($bookingData->dateId);
if (null === $travelData) {
$this->addFlash('error', 'Reisedaten nicht (mehr) verfügbar');
@@ -66,34 +66,26 @@ class EditController extends AbstractController
return $this->redirectToRoute('app_bookings');
}
// Fetch mutability information via API
try {
$mutableData = $this->apiClient->getMutableData($bookingData->travelId);
} catch (ApiClientException $e) {
$this->addFlash('error', 'Reisedaten nicht (mehr) verfügbar');
// Fetch mutability and availability information via service
$mutableData = $this->travelDataService->getMutabilityData($bookingData->dateId);
$availabilities = $this->travelDataService->getAvailabilityData($bookingData->dateId);
return $this->redirectToRoute('app_bookings');
}
// Fetch availability information via API
try {
$availabilities = $this->apiClient->getAvailabilities($bookingData->travelId);
} catch (ApiClientException $e) {
if (null === $mutableData || null === $availabilities) {
$this->addFlash('error', 'Reisedaten nicht (mehr) verfügbar');
return $this->redirectToRoute('app_bookings');
}
// Patch travel data with additional information from above
$this->travelDataLoader->patchAvailabilities($travelData, $availabilities);
$this->travelDataLoader->patchMutability($travelData, $mutableData);
$this->pickupDataLoader->patchPickupsDetails($travelData);
$this->travelDataService->patchAvailabilities($travelData, $availabilities);
$this->travelDataService->patchMutability($travelData, $mutableData);
// Create DTO for form
$formData = BookingEditDto::fromBooking($bookingData, $travelData);
$form = $this->createForm(BookingEditType::class, $formData, [
'attr' => ['novalidate' => 'novalidate'],
'validation_groups' => ['booking_edit'],
]);
$form->handleRequest($request);