wip: booking process, refactor participant room assignment logic
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Form\DataAdapters\ParticipantDataAdapter;
|
||||
use App\Form\Model\BookingCreateDto;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
@@ -29,49 +30,9 @@ class BookingCreateStep2Type extends AbstractType
|
||||
return;
|
||||
}
|
||||
|
||||
// Count participants assigned to each room
|
||||
$roomOccupancy = [];
|
||||
foreach ($bookingCreateDto->participants as $participant) {
|
||||
if (null !== $participant->assignedRoomId) {
|
||||
$roomOccupancy[$participant->assignedRoomId] = ($roomOccupancy[$participant->assignedRoomId] ?? 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate per-participant room choices
|
||||
$roomChoices = [];
|
||||
foreach ($bookingCreateDto->participants as $index => $participant) {
|
||||
$participantRoomChoices = [];
|
||||
|
||||
foreach ($bookingCreateDto->getSelectedRooms() as $roomSelection) {
|
||||
$currentOccupancy = $roomOccupancy[$roomSelection->roomId] ?? 0;
|
||||
|
||||
// If this participant is already assigned to this room, exclude them from occupancy count
|
||||
$adjustedOccupancy = $currentOccupancy;
|
||||
if ($participant->assignedRoomId === $roomSelection->roomId) {
|
||||
--$adjustedOccupancy;
|
||||
}
|
||||
|
||||
$remainingCapacity = $roomSelection->minPax - $adjustedOccupancy;
|
||||
|
||||
// Include room if it has capacity OR if it's the participant's current assignment
|
||||
if ($remainingCapacity > 0 || $participant->assignedRoomId === $roomSelection->roomId) {
|
||||
$participantRoomChoices[$roomSelection->roomLabel] = $roomSelection->roomId;
|
||||
}
|
||||
}
|
||||
|
||||
$roomChoices[$index] = $participantRoomChoices;
|
||||
}
|
||||
|
||||
// Create a custom form type that handles per-participant room choices
|
||||
$form->add('participants', CollectionType::class, [
|
||||
'entry_type' => BookingCreateParticipantType::class,
|
||||
'allow_add' => false,
|
||||
'allow_delete' => false,
|
||||
'by_reference' => false,
|
||||
'entry_options' => [
|
||||
'room_choices' => $roomChoices,
|
||||
],
|
||||
]);
|
||||
$adapter = new ParticipantDataAdapter($bookingCreateDto->participants);
|
||||
$roomChoices = $this->generateRoomChoices($adapter, $bookingCreateDto->getSelectedRooms());
|
||||
$this->addParticipantsField($form, $roomChoices);
|
||||
}
|
||||
|
||||
public function onPreSubmit(FormEvent $event): void
|
||||
@@ -81,20 +42,46 @@ class BookingCreateStep2Type extends AbstractType
|
||||
/** @var BookingCreateDto $bookingCreateDto */
|
||||
$bookingCreateDto = $form->getData();
|
||||
|
||||
$adapter = new ParticipantDataAdapter($data['participants']);
|
||||
$roomChoices = $this->generateRoomChoices($adapter, $bookingCreateDto->getSelectedRooms());
|
||||
$form->remove('participants');
|
||||
$this->addParticipantsField($form, $roomChoices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates room occupancy based on participant assignments.
|
||||
*
|
||||
* @return array<int, int>
|
||||
*/
|
||||
private function calculateRoomOccupancy(ParticipantDataAdapter $adapter): array
|
||||
{
|
||||
$roomOccupancy = [];
|
||||
foreach ($data['participants'] as $participant) {
|
||||
if (null !== $participant['assignedRoomId']) {
|
||||
$assignedRoomId = (int) $participant['assignedRoomId'];
|
||||
|
||||
foreach ($adapter->getParticipants() as $participant) {
|
||||
$assignedRoomId = $adapter->getAssignedRoomId($participant);
|
||||
if (null !== $assignedRoomId) {
|
||||
$roomOccupancy[$assignedRoomId] = ($roomOccupancy[$assignedRoomId] ?? 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
$roomChoices = [];
|
||||
foreach ($data['participants'] as $index => $participant) {
|
||||
$participantRoomChoices = [];
|
||||
$assignedRoomId = (int) $participant['assignedRoomId'];
|
||||
return $roomOccupancy;
|
||||
}
|
||||
|
||||
foreach ($bookingCreateDto->getSelectedRooms() as $roomSelection) {
|
||||
/**
|
||||
* Generates room choices for each participant based on availability and current assignments.
|
||||
*
|
||||
* @return array<int, array<string, int>>
|
||||
*/
|
||||
private function generateRoomChoices(ParticipantDataAdapter $adapter, array $selectedRooms): array
|
||||
{
|
||||
$roomOccupancy = $this->calculateRoomOccupancy($adapter);
|
||||
$roomChoices = [];
|
||||
|
||||
foreach ($adapter->getParticipants() as $index => $participant) {
|
||||
$participantRoomChoices = [];
|
||||
$assignedRoomId = $adapter->getAssignedRoomId($participant);
|
||||
|
||||
foreach ($selectedRooms as $roomSelection) {
|
||||
$currentOccupancy = $roomOccupancy[$roomSelection->roomId] ?? 0;
|
||||
|
||||
// If this participant is already assigned to this room, exclude them from occupancy count
|
||||
@@ -113,7 +100,17 @@ class BookingCreateStep2Type extends AbstractType
|
||||
|
||||
$roomChoices[$index] = $participantRoomChoices;
|
||||
}
|
||||
$form->remove('participants');
|
||||
|
||||
return $roomChoices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the participants collection field to the form with the given room choices.
|
||||
*
|
||||
* @param array<int, array<string, int>> $roomChoices
|
||||
*/
|
||||
private function addParticipantsField(FormInterface $form, array $roomChoices): void
|
||||
{
|
||||
$form->add('participants', CollectionType::class, [
|
||||
'entry_type' => BookingCreateParticipantType::class,
|
||||
'allow_add' => false,
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form\DataAdapters;
|
||||
|
||||
/**
|
||||
* Adapter pattern to unify access to participant data regardless of whether it comes from
|
||||
* objects (during PRE_SET_DATA) or arrays (during PRE_SUBMIT).
|
||||
*/
|
||||
class ParticipantDataAdapter
|
||||
{
|
||||
private array $participants;
|
||||
|
||||
public function __construct(array $participants)
|
||||
{
|
||||
$this->participants = $participants;
|
||||
}
|
||||
|
||||
public function getParticipants(): array
|
||||
{
|
||||
return $this->participants;
|
||||
}
|
||||
|
||||
public function getAssignedRoomId(mixed $participant): ?int
|
||||
{
|
||||
if (is_array($participant)) {
|
||||
$assignedRoomId = $participant['assignedRoomId'] ?? null;
|
||||
return null !== $assignedRoomId ? (int) $assignedRoomId : null;
|
||||
}
|
||||
|
||||
return $participant->assignedRoomId;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user