wip: booking process, refactor participant room assignment logic
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Form;
|
namespace App\Form;
|
||||||
|
|
||||||
|
use App\Form\DataAdapters\ParticipantDataAdapter;
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingCreateDto;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||||
@@ -29,49 +30,9 @@ class BookingCreateStep2Type extends AbstractType
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count participants assigned to each room
|
$adapter = new ParticipantDataAdapter($bookingCreateDto->participants);
|
||||||
$roomOccupancy = [];
|
$roomChoices = $this->generateRoomChoices($adapter, $bookingCreateDto->getSelectedRooms());
|
||||||
foreach ($bookingCreateDto->participants as $participant) {
|
$this->addParticipantsField($form, $roomChoices);
|
||||||
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,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onPreSubmit(FormEvent $event): void
|
public function onPreSubmit(FormEvent $event): void
|
||||||
@@ -81,20 +42,46 @@ class BookingCreateStep2Type extends AbstractType
|
|||||||
/** @var BookingCreateDto $bookingCreateDto */
|
/** @var BookingCreateDto $bookingCreateDto */
|
||||||
$bookingCreateDto = $form->getData();
|
$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 = [];
|
$roomOccupancy = [];
|
||||||
foreach ($data['participants'] as $participant) {
|
|
||||||
if (null !== $participant['assignedRoomId']) {
|
foreach ($adapter->getParticipants() as $participant) {
|
||||||
$assignedRoomId = (int) $participant['assignedRoomId'];
|
$assignedRoomId = $adapter->getAssignedRoomId($participant);
|
||||||
|
if (null !== $assignedRoomId) {
|
||||||
$roomOccupancy[$assignedRoomId] = ($roomOccupancy[$assignedRoomId] ?? 0) + 1;
|
$roomOccupancy[$assignedRoomId] = ($roomOccupancy[$assignedRoomId] ?? 0) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$roomChoices = [];
|
return $roomOccupancy;
|
||||||
foreach ($data['participants'] as $index => $participant) {
|
}
|
||||||
$participantRoomChoices = [];
|
|
||||||
$assignedRoomId = (int) $participant['assignedRoomId'];
|
|
||||||
|
|
||||||
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;
|
$currentOccupancy = $roomOccupancy[$roomSelection->roomId] ?? 0;
|
||||||
|
|
||||||
// If this participant is already assigned to this room, exclude them from occupancy count
|
// 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;
|
$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, [
|
$form->add('participants', CollectionType::class, [
|
||||||
'entry_type' => BookingCreateParticipantType::class,
|
'entry_type' => BookingCreateParticipantType::class,
|
||||||
'allow_add' => false,
|
'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