diff --git a/src/BusProNet/DataProcessor/PersonalDataSynchronizer.php b/src/BusProNet/DataProcessor/PersonalDataSynchronizer.php index 633cc1f..fde530f 100644 --- a/src/BusProNet/DataProcessor/PersonalDataSynchronizer.php +++ b/src/BusProNet/DataProcessor/PersonalDataSynchronizer.php @@ -127,7 +127,7 @@ class PersonalDataSynchronizer * Ensures mandatory fields have sensible defaults before submission to the * BPN API. Currently handles nationality which defaults to 'D' (German). * - * @param \App\BusProNet\Model\PersonalData $participant The participant to fill defaults for + * @param PersonalData $participant The participant to fill defaults for */ private function fillMissingParticipantFields(PersonalData $participant): void { diff --git a/src/BusProNet/Model/PersonalData.php b/src/BusProNet/Model/PersonalData.php index 3e5a1bf..881fdcb 100644 --- a/src/BusProNet/Model/PersonalData.php +++ b/src/BusProNet/Model/PersonalData.php @@ -91,7 +91,7 @@ class PersonalData ]; if (true === $includeDateOfBirth) { - $dob = $this->dateOfBirth ?? new \DateTimeImmutable(self::DEFAULT_AGE_YEARS . ' years ago'); + $dob = $this->dateOfBirth ?? new \DateTimeImmutable(self::DEFAULT_AGE_YEARS.' years ago'); $payload['geburtsdatum'] = $dob->format('d.m.Y'); } diff --git a/src/Controller/Admin/BookingEditDraftCrudController.php b/src/Controller/Admin/BookingEditDraftCrudController.php index 1218c47..e1c5337 100644 --- a/src/Controller/Admin/BookingEditDraftCrudController.php +++ b/src/Controller/Admin/BookingEditDraftCrudController.php @@ -48,7 +48,7 @@ class BookingEditDraftCrudController extends AbstractCrudController ->remove(Crud::PAGE_INDEX, Action::NEW) ->remove(Crud::PAGE_INDEX, Action::EDIT) ->remove(Crud::PAGE_DETAIL, Action::EDIT) - ; + ; } #[Route('/admin/booking-draft/{id}/export', name: 'admin_booking_draft_export', requirements: ['id' => '\d+'])] @@ -68,7 +68,7 @@ class BookingEditDraftCrudController extends AbstractCrudController try { return $this->exportService->createExportResponse($draft); } catch (\RuntimeException $e) { - $this->addFlash('danger', 'Export fehlgeschlagen: ' . $e->getMessage()); + $this->addFlash('danger', 'Export fehlgeschlagen: '.$e->getMessage()); $url = $this->adminUrlGenerator ->setController(self::class) @@ -94,7 +94,7 @@ class BookingEditDraftCrudController extends AbstractCrudController AssociationField::new('user', 'Kundenaccount')->formatValue(fn (User $user) => $user->getEmail()), DateTimeField::new('createdAt', 'erstellt am'), DateTimeField::new('updatedAt', 'aktualisiert am'), - JsonDataField::new('formData', 'Daten')->onlyOnDetail() + JsonDataField::new('formData', 'Daten')->onlyOnDetail(), ]; } } diff --git a/src/Controller/Admin/DashboardController.php b/src/Controller/Admin/DashboardController.php index b26d6f1..6e3319f 100644 --- a/src/Controller/Admin/DashboardController.php +++ b/src/Controller/Admin/DashboardController.php @@ -34,7 +34,7 @@ class DashboardController extends AbstractDashboardController { return parent::configureUserMenu($user) ->addMenuItems([ - MenuItem::linkToRoute('MyE&P', 'fa fa-user', 'app_account') + MenuItem::linkToRoute('MyE&P', 'fa fa-user', 'app_account'), ]); } diff --git a/src/Controller/Admin/UserCrudController.php b/src/Controller/Admin/UserCrudController.php index e5fae35..77067a5 100644 --- a/src/Controller/Admin/UserCrudController.php +++ b/src/Controller/Admin/UserCrudController.php @@ -8,8 +8,6 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField; -use EasyCorp\Bundle\EasyAdminBundle\Field\IdField; -use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField; use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; class UserCrudController extends AbstractCrudController @@ -25,7 +23,7 @@ class UserCrudController extends AbstractCrudController ->remove(Crud::PAGE_INDEX, Action::NEW) ->remove(Crud::PAGE_INDEX, Action::EDIT) ->remove(Crud::PAGE_INDEX, Action::DELETE) - ; + ; } public function configureCrud(Crud $crud): Crud diff --git a/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php b/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php index 8eef76b..14f8cdc 100644 --- a/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php +++ b/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Form\Service\Abstract; +use App\BusProNet\Model\Booking; use App\BusProNet\Model\Service; use App\Form\Model\BookingDto; use App\Form\Service\Contract\ParticipantFieldHandlerInterface; @@ -83,7 +84,7 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle */ protected function isEditMode(BookingDto $bookingDto): bool { - return BookingDto::MODE_EDIT === $bookingDto->mode; + return BookingDto::MODE_EDIT === $bookingDto->getMode(); } /** @@ -95,7 +96,7 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle */ protected function isCreateMode(BookingDto $bookingDto): bool { - return BookingDto::MODE_CREATE === $bookingDto->mode; + return BookingDto::MODE_CREATE === $bookingDto->getMode(); } /** @@ -269,4 +270,65 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle return false; } + + /** + * Retrieves available services from travel data, merged with booked services in edit mode. + * + * In edit mode, services that were previously booked for the participant are included + * even if they're no longer available in travel data. This prevents booked services + * from being dropped during form validation when the travel catalog has changed. + * + * @param BookingDto $bookingDto The booking DTO containing travel and booking data + * @param int $participantIndex The participant index to retrieve booked services for + * @param mixed $serviceGroup The service group(s) to filter by (e.g., TOKEN_RENTALS) + * @param bool $filterByTravelDateRange Whether to filter travel services by date range + * + * @return Service[] Array of available services keyed by service ID + */ + protected function getAvailableServicesWithBooked( + BookingDto $bookingDto, + int $participantIndex, + mixed $serviceGroup, + bool $filterByTravelDateRange = false, + ): array { + $availableServices = $bookingDto->travel->getAdditionalServicesBySubTypes($serviceGroup, $filterByTravelDateRange); + + if ($this->isEditMode($bookingDto) && null !== $bookingDto->booking) { + $availableServices = $this->mergeBookedServices( + $availableServices, + $bookingDto->booking, + $participantIndex, + $serviceGroup + ); + } + + return $availableServices; + } + + /** + * Merges booked services into the available services array. + * + * @param Service[] $availableServices The services available from travel data + * @param Booking $booking The booking containing previously booked services + * @param int $participantIndex The participant index to retrieve booked services for + * @param mixed $serviceGroup The service group(s) to filter by + * + * @return Service[] Merged array of services keyed by service ID + */ + private function mergeBookedServices( + array $availableServices, + Booking $booking, + int $participantIndex, + mixed $serviceGroup, + ): array { + $bookedServices = $booking->getAdditionalServicesForParticipantByGroup($participantIndex, $serviceGroup); + + foreach ($bookedServices as $bookedService) { + if (false === isset($availableServices[$bookedService->id])) { + $availableServices[$bookedService->id] = $bookedService; + } + } + + return $availableServices; + } } diff --git a/src/Form/Service/ParticipantAdditionalServicesFieldHandler.php b/src/Form/Service/ParticipantAdditionalServicesFieldHandler.php index d6d4180..d94985c 100644 --- a/src/Form/Service/ParticipantAdditionalServicesFieldHandler.php +++ b/src/Form/Service/ParticipantAdditionalServicesFieldHandler.php @@ -99,8 +99,12 @@ class ParticipantAdditionalServicesFieldHandler extends AbstractParticipantField // Extract current service selections from submitted data $selectedServices = $this->getFieldValue($submittedData, $this->getFieldName()) ?? []; - // Get available additional services from travel data - $availableServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_ADDITIONAL); + // Get available additional services from travel data (includes booked services in edit mode) + $availableServices = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_ADDITIONAL + ); // Filter selections to keep only age-appropriate services $validSelections = $this->filterValidServiceSelections( diff --git a/src/Form/Service/ParticipantBoardFieldHandler.php b/src/Form/Service/ParticipantBoardFieldHandler.php index faac2f0..4bd88ab 100644 --- a/src/Form/Service/ParticipantBoardFieldHandler.php +++ b/src/Form/Service/ParticipantBoardFieldHandler.php @@ -58,7 +58,13 @@ class ParticipantBoardFieldHandler extends AbstractParticipantFieldHandler } $selectedBoard = $this->getFieldValue($submittedData, $this->getFieldName()) ?? []; - $availableBoard = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_BOARD); + + // Get available board options from travel data (includes booked options in edit mode) + $availableBoard = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_BOARD + ); $validSelections = $this->filterValidServiceSelections( $selectedBoard, diff --git a/src/Form/Service/ParticipantCoursesFieldHandler.php b/src/Form/Service/ParticipantCoursesFieldHandler.php index 7c521f9..d83ab82 100644 --- a/src/Form/Service/ParticipantCoursesFieldHandler.php +++ b/src/Form/Service/ParticipantCoursesFieldHandler.php @@ -92,8 +92,12 @@ class ParticipantCoursesFieldHandler extends AbstractParticipantFieldHandler // Extract current course selections from submitted data $selectedCourses = $this->getFieldValue($submittedData, $this->getFieldName()) ?? []; - // Get available courses from travel data - $availableCourses = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_COURSES); + // Get available courses from travel data (includes booked courses in edit mode) + $availableCourses = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_COURSES + ); // Filter selections to keep only age-appropriate courses $validSelections = $this->filterValidServiceSelections( diff --git a/src/Form/Service/ParticipantFieldOptionsProvider.php b/src/Form/Service/ParticipantFieldOptionsProvider.php index f88a485..18b4f12 100644 --- a/src/Form/Service/ParticipantFieldOptionsProvider.php +++ b/src/Form/Service/ParticipantFieldOptionsProvider.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Form\Service; use App\BusProNet\Constants; +use App\BusProNet\Model\Booking; use App\BusProNet\Model\Insurance; use App\BusProNet\Model\Pickup; use App\BusProNet\Model\Room; @@ -122,7 +123,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Returns empty array when no courses available $this->fieldOptionProviders['courses'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array { $choices = $this->filterServicesByAgeConstraints( - $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_COURSES), + $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_COURSES), $bookingDto, $participantIndex ); @@ -166,7 +167,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Returns empty array when no additional services available $this->fieldOptionProviders['additionalServices'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array { $choices = $this->filterServicesByAgeConstraints( - $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_ADDITIONAL), + $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_ADDITIONAL), $bookingDto, $participantIndex ); @@ -217,7 +218,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Returns empty array when no board options available $this->fieldOptionProviders['board'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array { $choices = $this->filterServicesByAgeConstraints( - $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_BOARD), + $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_BOARD), $bookingDto, $participantIndex ); @@ -261,7 +262,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Returns empty array when no dietary options available $this->fieldOptionProviders['veg'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array { $choices = $this->filterServicesByAgeConstraints( - $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_VEG, true), + $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_VEG, true), $bookingDto, $participantIndex ); @@ -316,7 +317,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider $this->fieldOptionProviders['rentals'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array { $choices = $this->filterServicesByAgeConstraints( $this->filterRentalsBySkiPassDuration( - $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true), + $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_RENTALS, true), $bookingDto, $participantIndex ), @@ -386,7 +387,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Returns empty array when no skipass options available $this->fieldOptionProviders['skiPass'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array { $choices = $this->filterSkiPassChoices( - $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true), + $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_SKI_PASS, true), $bookingDto, $participantIndex ); @@ -557,7 +558,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Simple checkbox since there's only ever one parking type // Returns empty array when no parking services exist to prevent field from rendering $this->fieldOptionProviders['parking'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array { - $parkingServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING); + $parkingServices = $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_PARKING); if (true === empty($parkingServices)) { return []; } @@ -1255,4 +1256,65 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Fallback: return all services if we don't have the expected discount/regular pair return [...$otherServices, ...$pkwServices]; } + + /** + * Retrieves available services from travel data, merged with booked services in edit mode. + * + * In edit mode, services that were previously booked for the participant are included + * even if they're no longer available in travel data. This ensures form checkboxes + * appear for booked services, allowing users to keep or deselect them. + * + * @param BookingDto $bookingDto The booking DTO containing travel and booking data + * @param int $participantIndex The participant index to retrieve booked services for + * @param mixed $serviceGroup The service group(s) to filter by (e.g., TOKEN_RENTALS) + * @param bool $filterByTravelDateRange Whether to filter travel services by date range + * + * @return Service[] Array of available services keyed by service ID + */ + private function getServicesWithBooked( + BookingDto $bookingDto, + int $participantIndex, + mixed $serviceGroup, + bool $filterByTravelDateRange = false, + ): array { + $availableServices = $bookingDto->travel->getAdditionalServicesBySubTypes($serviceGroup, $filterByTravelDateRange); + + if (BookingDto::MODE_EDIT === $bookingDto->getMode() && null !== $bookingDto->booking) { + $availableServices = $this->mergeBookedServices( + $availableServices, + $bookingDto->booking, + $participantIndex, + $serviceGroup + ); + } + + return $availableServices; + } + + /** + * Merges booked services into the available services array. + * + * @param Service[] $availableServices The services available from travel data + * @param Booking $booking The booking containing previously booked services + * @param int $participantIndex The participant index to retrieve booked services for + * @param mixed $serviceGroup The service group(s) to filter by + * + * @return Service[] Merged array of services keyed by service ID + */ + private function mergeBookedServices( + array $availableServices, + Booking $booking, + int $participantIndex, + mixed $serviceGroup, + ): array { + $bookedServices = $booking->getAdditionalServicesForParticipantByGroup($participantIndex, $serviceGroup); + + foreach ($bookedServices as $bookedService) { + if (false === isset($availableServices[$bookedService->id])) { + $availableServices[$bookedService->id] = $bookedService; + } + } + + return $availableServices; + } } diff --git a/src/Form/Service/ParticipantParkingFieldHandler.php b/src/Form/Service/ParticipantParkingFieldHandler.php index 7121cb8..8a46876 100644 --- a/src/Form/Service/ParticipantParkingFieldHandler.php +++ b/src/Form/Service/ParticipantParkingFieldHandler.php @@ -73,7 +73,7 @@ class ParticipantParkingFieldHandler extends AbstractParticipantFieldHandler // Store parking service object for pricing calculation if (true === $isParkingSelected) { - $participant->parkingService = $this->findParkingService($bookingDto); + $participant->parkingService = $this->findParkingService($bookingDto, $participantIndex); } else { $participant->parkingService = null; } @@ -112,13 +112,19 @@ class ParticipantParkingFieldHandler extends AbstractParticipantFieldHandler * Gets the first (and typically only) parking service for pricing calculation. * Returns null if no parking services are available. * - * @param BookingDto $bookingDto The booking DTO containing travel data + * @param BookingDto $bookingDto The booking DTO containing travel data + * @param int $participantIndex The participant index for booked services lookup * * @return Service|null The parking service object, or null if not found */ - private function findParkingService(BookingDto $bookingDto): ?Service + private function findParkingService(BookingDto $bookingDto, int $participantIndex): ?Service { - $parkingServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING); + // Get available parking services (includes booked parking in edit mode) + $parkingServices = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_PARKING + ); if (empty($parkingServices)) { return null; diff --git a/src/Form/Service/ParticipantRentalInsuranceFieldHandler.php b/src/Form/Service/ParticipantRentalInsuranceFieldHandler.php index 9f65bcf..79848a7 100644 --- a/src/Form/Service/ParticipantRentalInsuranceFieldHandler.php +++ b/src/Form/Service/ParticipantRentalInsuranceFieldHandler.php @@ -107,7 +107,7 @@ class ParticipantRentalInsuranceFieldHandler extends AbstractParticipantFieldHan // Store service object based on checkbox state for pricing calculations if (true === $isRentalInsuranceSelected) { - $participant->rentalInsurance = $this->findRentalInsuranceService($bookingDto); + $participant->rentalInsurance = $this->findRentalInsuranceService($bookingDto, $participantIndex); } else { $participant->rentalInsurance = null; } @@ -119,13 +119,20 @@ class ParticipantRentalInsuranceFieldHandler extends AbstractParticipantFieldHan * Gets the first (and typically only) rental insurance service. * Returns null if no rental insurance services are available. * - * @param BookingDto $bookingDto The booking DTO containing travel data + * @param BookingDto $bookingDto The booking DTO containing travel data + * @param int $participantIndex The participant index for booked services lookup * * @return Service|null The rental insurance service object, or null if not found */ - private function findRentalInsuranceService(BookingDto $bookingDto): ?Service + private function findRentalInsuranceService(BookingDto $bookingDto, int $participantIndex): ?Service { - $rentalInsuranceServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true); + // Get available rental insurance services (includes booked insurance in edit mode) + $rentalInsuranceServices = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_RENTAL_INSURANCE, + true + ); if (empty($rentalInsuranceServices)) { return null; diff --git a/src/Form/Service/ParticipantRentalsFieldHandler.php b/src/Form/Service/ParticipantRentalsFieldHandler.php index ff0c58f..b62b1fb 100644 --- a/src/Form/Service/ParticipantRentalsFieldHandler.php +++ b/src/Form/Service/ParticipantRentalsFieldHandler.php @@ -83,7 +83,14 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler } $selectedRentals = $this->getFieldValue($submittedData, $this->getFieldName()) ?? []; - $availableRentals = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true); + + // Get available rentals from travel data (includes booked rentals in edit mode) + $availableRentals = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_RENTALS, + true + ); // Filter rentals by skipass duration to ensure only matching rentals are available $durationFilteredRentals = $this->filterRentalsBySkiPassDuration($availableRentals, $participant); diff --git a/src/Form/Service/ParticipantSkiPassFieldHandler.php b/src/Form/Service/ParticipantSkiPassFieldHandler.php index 56ced3a..731ef57 100644 --- a/src/Form/Service/ParticipantSkiPassFieldHandler.php +++ b/src/Form/Service/ParticipantSkiPassFieldHandler.php @@ -94,8 +94,13 @@ class ParticipantSkiPassFieldHandler extends AbstractParticipantFieldHandler // Extract current skipass selection from submitted data $selectedSkiPass = $this->getFieldValue($submittedData, $this->getFieldName()); - // Get all skipasses from travel data (with date filtering) - $availableSkipasses = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true); + // Get all skipasses from travel data (includes booked skipasses in edit mode) + $availableSkipasses = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_SKI_PASS, + true + ); // For single selection, validate the selected skipass and convert ID to Service object $validSelection = null; diff --git a/src/Form/Service/ParticipantVegFieldHandler.php b/src/Form/Service/ParticipantVegFieldHandler.php index 2389545..ec30873 100644 --- a/src/Form/Service/ParticipantVegFieldHandler.php +++ b/src/Form/Service/ParticipantVegFieldHandler.php @@ -84,7 +84,13 @@ class ParticipantVegFieldHandler extends AbstractParticipantFieldHandler $selectedVeg = $this->getFieldValue($submittedData, $this->getFieldName()); - $availableVegOptions = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_VEG, true); + // Get available veg options from travel data (includes booked options in edit mode) + $availableVegOptions = $this->getAvailableServicesWithBooked( + $bookingDto, + $participantIndex, + Constants::TOKEN_VEG, + true + ); $validSelection = null; if (null !== $selectedVeg) { diff --git a/src/Service/BookingExportService.php b/src/Service/BookingExportService.php index 7425e42..97dc889 100644 --- a/src/Service/BookingExportService.php +++ b/src/Service/BookingExportService.php @@ -178,7 +178,7 @@ class BookingExportService ], ]; $lastColumn = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex(count(self::COLUMN_HEADERS)); - $sheet->getStyle('A1:' . $lastColumn . '1')->applyFromArray($headerStyle); + $sheet->getStyle('A1:'.$lastColumn.'1')->applyFromArray($headerStyle); // Write participant data $formData = $draft->getFormData(); @@ -206,7 +206,7 @@ class BookingExportService \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet, int $row, array $participant, - array $lookups + array $lookups, ): void { $personal = $participant['personalData'] ?? []; $address = $participant['address'] ?? [];