wip: booking process, refactor participant room assignment logic
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form\ChoiceLoader;
|
||||
|
||||
use App\Form\DataAdapters\ParticipantDataAdapter;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||
|
||||
/**
|
||||
* Choice loader for participant room assignments.
|
||||
*
|
||||
* Generates room choices for each participant based on availability,
|
||||
* current assignments, and room capacity constraints. This loader
|
||||
* ensures participants can only select rooms with available capacity
|
||||
* while maintaining their current assignment if applicable.
|
||||
*/
|
||||
class ParticipantRoomChoiceLoader implements ChoiceLoaderInterface
|
||||
{
|
||||
private ?ChoiceListInterface $choiceList = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly ChoiceListFactoryInterface $factory,
|
||||
private readonly ParticipantDataAdapter $adapter,
|
||||
private readonly array $selectedRooms,
|
||||
private readonly int $participantIndex,
|
||||
) {
|
||||
}
|
||||
|
||||
public function loadChoiceList(?callable $value = null): ChoiceListInterface
|
||||
{
|
||||
if (null === $this->choiceList) {
|
||||
$choices = $this->generateRoomChoicesForParticipant();
|
||||
$this->choiceList = $this->factory->createListFromChoices($choices, $value);
|
||||
}
|
||||
|
||||
return $this->choiceList;
|
||||
}
|
||||
|
||||
public function loadChoicesForValues(array $values, ?callable $value = null): array
|
||||
{
|
||||
if (empty($values)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->loadChoiceList($value)->getChoicesForValues($values);
|
||||
}
|
||||
|
||||
public function loadValuesForChoices(array $choices, ?callable $value = null): array
|
||||
{
|
||||
if (empty($choices)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->loadChoiceList($value)->getValuesForChoices($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates room choices for the specific participant.
|
||||
*
|
||||
* @return array<string, int>
|
||||
*/
|
||||
private function generateRoomChoicesForParticipant(): array
|
||||
{
|
||||
$roomOccupancy = $this->calculateRoomOccupancy();
|
||||
$participantRoomChoices = [];
|
||||
$assignedRoomId = $this->getParticipantAssignedRoomId();
|
||||
|
||||
foreach ($this->selectedRooms as $roomSelection) {
|
||||
$currentOccupancy = $roomOccupancy[$roomSelection->roomId] ?? 0;
|
||||
|
||||
// If this participant is already assigned to this room, exclude them from occupancy count
|
||||
$adjustedOccupancy = $currentOccupancy;
|
||||
if ($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 || $assignedRoomId === $roomSelection->roomId) {
|
||||
$participantRoomChoices[$roomSelection->roomLabel] = $roomSelection->roomId;
|
||||
}
|
||||
}
|
||||
|
||||
return $participantRoomChoices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates room occupancy based on participant assignments.
|
||||
*
|
||||
* @return array<int, int>
|
||||
*/
|
||||
private function calculateRoomOccupancy(): array
|
||||
{
|
||||
$roomOccupancy = [];
|
||||
|
||||
foreach ($this->adapter->getParticipants() as $participant) {
|
||||
$assignedRoomId = $this->adapter->getAssignedRoomId($participant);
|
||||
if (null !== $assignedRoomId) {
|
||||
$roomOccupancy[$assignedRoomId] = ($roomOccupancy[$assignedRoomId] ?? 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $roomOccupancy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the assigned room ID for the current participant.
|
||||
*/
|
||||
private function getParticipantAssignedRoomId(): ?int
|
||||
{
|
||||
$participants = $this->adapter->getParticipants();
|
||||
$participant = $participants[$this->participantIndex] ?? null;
|
||||
|
||||
return null !== $participant ? $this->adapter->getAssignedRoomId($participant) : null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user