wip: refactor
This commit is contained in:
@@ -33,7 +33,7 @@ class CreateStep1Controller extends AbstractController
|
|||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
|
$bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request);
|
||||||
$participantsCount = $this->bookingService->getParticipantsCount($bookingCreateDto->roomSelections, $bookingCreateDto->travelData);
|
$participantsCount = $this->bookingService->getParticipantsCount($bookingCreateDto->roomSelections, $bookingCreateDto->travel);
|
||||||
|
|
||||||
// Validate step access - allow step 1 or redirect to current step
|
// Validate step access - allow step 1 or redirect to current step
|
||||||
$this->validateStepAccess($bookingCreateDto, 1);
|
$this->validateStepAccess($bookingCreateDto, 1);
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class CreateStep2Controller extends AbstractController
|
|||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
->bookingService
|
->bookingService
|
||||||
->getParticipantsCount($bookingCreateDto->roomSelections, $bookingCreateDto->travelData);
|
->getParticipantsCount($bookingCreateDto->roomSelections, $bookingCreateDto->travel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ensureCorrectNumberOfParticipants(BookingCreateDto $bookingCreateDto): void
|
private function ensureCorrectNumberOfParticipants(BookingCreateDto $bookingCreateDto): void
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Form;
|
|||||||
use App\BusProNet\Form\CountryType;
|
use App\BusProNet\Form\CountryType;
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingCreateDto;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
use App\Form\Service\ParticipantFieldOptionsProvider;
|
use App\Form\Service\ParticipantFieldOptionsProvider;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
|
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
|
||||||
@@ -90,11 +91,11 @@ class BookingCreateParticipantType extends AbstractType
|
|||||||
$rootForm = $rootForm->getParent();
|
$rootForm = $rootForm->getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var BookingCreateDto $bookingCreateDto */
|
/** @var BookingDtoInterface $bookingDto */
|
||||||
$bookingCreateDto = $rootForm->getData();
|
$bookingDto = $rootForm->getData();
|
||||||
|
|
||||||
$this->addDynamicFields($form, $bookingCreateDto, $participantData->index);
|
$this->addDynamicFields($form, $bookingDto, $participantData->index);
|
||||||
$this->applyFieldStates($form, $bookingCreateDto, $participantData->index);
|
$this->applyFieldStates($form, $bookingDto, $participantData->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,16 +110,16 @@ class BookingCreateParticipantType extends AbstractType
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the root form data to access BookingCreateDto
|
// Get the root form data to access BookingDtoInterface
|
||||||
$rootForm = $form;
|
$rootForm = $form;
|
||||||
while ($rootForm->getParent()) {
|
while ($rootForm->getParent()) {
|
||||||
$rootForm = $rootForm->getParent();
|
$rootForm = $rootForm->getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var BookingCreateDto $bookingCreateDto */
|
/** @var BookingDtoInterface $bookingDto */
|
||||||
$bookingCreateDto = $rootForm->getData();
|
$bookingDto = $rootForm->getData();
|
||||||
|
|
||||||
if (null === $bookingCreateDto) {
|
if (null === $bookingDto) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +130,7 @@ class BookingCreateParticipantType extends AbstractType
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply updated field states based on submitted data
|
// Apply updated field states based on submitted data
|
||||||
$this->applyFieldStates($form, $bookingCreateDto, $participantData->index, $submittedData);
|
$this->applyFieldStates($form, $bookingDto, $participantData->index, $submittedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,14 +140,14 @@ class BookingCreateParticipantType extends AbstractType
|
|||||||
* the appropriate state modifications (readonly, disabled, etc.).
|
* the appropriate state modifications (readonly, disabled, etc.).
|
||||||
*
|
*
|
||||||
* @param FormInterface $form The form to modify
|
* @param FormInterface $form The form to modify
|
||||||
* @param BookingCreateDto $bookingCreateDto The booking data for context
|
* @param BookingDtoInterface $bookingDto The booking data for context (create or edit)
|
||||||
* @param int $participantIndex The participant index
|
* @param int $participantIndex The participant index
|
||||||
* @param array<string, mixed> $formData Optional submitted form data for state calculation
|
* @param array<string, mixed> $formData Optional submitted form data for state calculation
|
||||||
*/
|
*/
|
||||||
private function applyFieldStates(FormInterface $form, BookingCreateDto $bookingCreateDto, int $participantIndex, array $formData = []): void
|
private function applyFieldStates(FormInterface $form, BookingDtoInterface $bookingDto, int $participantIndex, array $formData = []): void
|
||||||
{
|
{
|
||||||
// Get all fields that have state conditions
|
// Get all fields that have state conditions
|
||||||
$allFieldStates = $this->fieldOptionsProvider->getAllFieldStates($bookingCreateDto, $participantIndex, $formData);
|
$allFieldStates = $this->fieldOptionsProvider->getAllFieldStates($bookingDto, $participantIndex, $formData);
|
||||||
|
|
||||||
foreach ($allFieldStates as $fieldName => $fieldState) {
|
foreach ($allFieldStates as $fieldName => $fieldState) {
|
||||||
if ($form->has($fieldName)) {
|
if ($form->has($fieldName)) {
|
||||||
@@ -167,18 +168,18 @@ class BookingCreateParticipantType extends AbstractType
|
|||||||
/**
|
/**
|
||||||
* Adds all configured dynamic fields to the form with state conditions applied.
|
* Adds all configured dynamic fields to the form with state conditions applied.
|
||||||
*/
|
*/
|
||||||
private function addDynamicFields(FormInterface $form, BookingCreateDto $bookingCreateDto, int $participantIndex): void
|
private function addDynamicFields(FormInterface $form, BookingDtoInterface $bookingDto, int $participantIndex): void
|
||||||
{
|
{
|
||||||
$dynamicFields = ['assignedRoomId']; // List of fields that need dynamic configuration
|
$dynamicFields = ['assignedRoomId']; // List of fields that need dynamic configuration
|
||||||
|
|
||||||
foreach ($dynamicFields as $fieldName) {
|
foreach ($dynamicFields as $fieldName) {
|
||||||
if ($this->fieldOptionsProvider->hasFieldOptions($fieldName)) {
|
if ($this->fieldOptionsProvider->hasFieldOptions($fieldName)) {
|
||||||
// Get base field options
|
// Get base field options
|
||||||
$fieldOptions = $this->fieldOptionsProvider->getFieldOptions($fieldName, $bookingCreateDto, $participantIndex);
|
$fieldOptions = $this->fieldOptionsProvider->getFieldOptions($fieldName, $bookingDto, $participantIndex);
|
||||||
|
|
||||||
// Apply dynamic field state if conditions exist
|
// Apply dynamic field state if conditions exist
|
||||||
if ($this->fieldOptionsProvider->hasStateConditions($fieldName)) {
|
if ($this->fieldOptionsProvider->hasStateConditions($fieldName)) {
|
||||||
$fieldState = $this->fieldOptionsProvider->getFieldState($fieldName, $bookingCreateDto, $participantIndex);
|
$fieldState = $this->fieldOptionsProvider->getFieldState($fieldName, $bookingDto, $participantIndex);
|
||||||
$fieldOptions = $this->mergeFieldState($fieldOptions, $fieldState);
|
$fieldOptions = $this->mergeFieldState($fieldOptions, $fieldState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use App\BusProNet\Form\CountryType;
|
|||||||
use App\BusProNet\Model\Pickup;
|
use App\BusProNet\Model\Pickup;
|
||||||
use App\BusProNet\Model\Service;
|
use App\BusProNet\Model\Service;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
use App\Form\Service\EditFieldStateProvider;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
|
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
@@ -19,6 +21,10 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
|
|
||||||
class BookingEditParticipantType extends AbstractType
|
class BookingEditParticipantType extends AbstractType
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly EditFieldStateProvider $fieldStateProvider,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
{
|
{
|
||||||
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
|
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
|
||||||
@@ -33,34 +39,33 @@ class BookingEditParticipantType extends AbstractType
|
|||||||
|
|
||||||
$form = $event->getForm();
|
$form = $event->getForm();
|
||||||
|
|
||||||
$personalDataMutable = $options['personal_data_mutable'] && $participantData->mutable;
|
// Traverse up the form tree to get the root form's data (BookingEditDto)
|
||||||
$isApplicant = 0 === $participantIndex;
|
$rootForm = $form;
|
||||||
|
while ($rootForm->getParent()) {
|
||||||
|
$rootForm = $rootForm->getParent();
|
||||||
|
}
|
||||||
|
/** @var BookingDtoInterface $bookingDto */
|
||||||
|
$bookingDto = $rootForm->getData();
|
||||||
|
|
||||||
|
// Helper to get state for a field
|
||||||
|
$getState = fn(string $field) => $this->fieldStateProvider->getFieldState($field, $bookingDto, $participantIndex);
|
||||||
|
|
||||||
$form
|
$form
|
||||||
->add('firstName', TextType::class, [
|
->add('firstName', TextType::class, $this->mergeFieldState([
|
||||||
'label' => 'Vorname',
|
'label' => 'Vorname',
|
||||||
'attr' => [
|
|
||||||
'readonly' => false === $personalDataMutable,
|
|
||||||
],
|
|
||||||
'clean_xss' => true,
|
'clean_xss' => true,
|
||||||
])
|
], $getState('firstName')))
|
||||||
->add('lastName', TextType::class, [
|
->add('lastName', TextType::class, $this->mergeFieldState([
|
||||||
'label' => 'Nachname',
|
'label' => 'Nachname',
|
||||||
'attr' => [
|
|
||||||
'readonly' => false === $personalDataMutable,
|
|
||||||
],
|
|
||||||
'clean_xss' => true,
|
'clean_xss' => true,
|
||||||
])
|
], $getState('lastName')))
|
||||||
->add('dateOfBirth', BirthdayType::class, [
|
->add('dateOfBirth', BirthdayType::class, $this->mergeFieldState([
|
||||||
'label' => 'Geburtsdatum',
|
'label' => 'Geburtsdatum',
|
||||||
'html5' => true,
|
'html5' => true,
|
||||||
'widget' => 'single_text',
|
'widget' => 'single_text',
|
||||||
'input' => 'datetime_immutable',
|
'input' => 'datetime_immutable',
|
||||||
'attr' => [
|
], $getState('dateOfBirth')))
|
||||||
'readonly' => false === $personalDataMutable,
|
->add('gender', ChoiceType::class, $this->mergeFieldState([
|
||||||
],
|
|
||||||
])
|
|
||||||
->add('gender', ChoiceType::class, [
|
|
||||||
'label' => 'Geschlecht',
|
'label' => 'Geschlecht',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'placeholder' => 'keine Angabe',
|
'placeholder' => 'keine Angabe',
|
||||||
@@ -69,36 +74,22 @@ class BookingEditParticipantType extends AbstractType
|
|||||||
'weiblich' => 'W',
|
'weiblich' => 'W',
|
||||||
'divers' => 'D',
|
'divers' => 'D',
|
||||||
],
|
],
|
||||||
'attr' => [
|
], $getState('gender')))
|
||||||
'readonly' => false === $personalDataMutable,
|
->add('nationality', CountryType::class, $this->mergeFieldState([
|
||||||
'style' => false === $personalDataMutable ? 'pointer-events: none' : null,
|
|
||||||
],
|
|
||||||
])
|
|
||||||
->add('nationality', CountryType::class, [
|
|
||||||
'label' => 'Nationalität',
|
'label' => 'Nationalität',
|
||||||
'property' => 'nationality',
|
'property' => 'nationality',
|
||||||
'preferred_choices' => ['D', 'A', 'CH'],
|
'preferred_choices' => ['D', 'A', 'CH'],
|
||||||
'attr' => [
|
], $getState('nationality')))
|
||||||
'readonly' => false === $personalDataMutable,
|
->add('email', EmailType::class, $this->mergeFieldState([
|
||||||
'style' => false === $personalDataMutable ? 'pointer-events: none' : null,
|
|
||||||
],
|
|
||||||
])
|
|
||||||
->add('email', EmailType::class, [
|
|
||||||
'label' => 'E-Mail',
|
'label' => 'E-Mail',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => [
|
|
||||||
'readonly' => true === $isApplicant,
|
|
||||||
],
|
|
||||||
'clean_xss' => true,
|
'clean_xss' => true,
|
||||||
])
|
], $getState('email')))
|
||||||
->add('mobile', TextType::class, [
|
->add('mobile', TextType::class, $this->mergeFieldState([
|
||||||
'label' => 'Telefon (mobil)',
|
'label' => 'Telefon (mobil)',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => [
|
|
||||||
'readonly' => true === $isApplicant,
|
|
||||||
],
|
|
||||||
'clean_xss' => true,
|
'clean_xss' => true,
|
||||||
])
|
], $getState('mobile')))
|
||||||
->add('bodyDimensions', BodyDimensionsType::class);
|
->add('bodyDimensions', BodyDimensionsType::class);
|
||||||
|
|
||||||
$commonChoiceFieldOptions = [
|
$commonChoiceFieldOptions = [
|
||||||
@@ -294,6 +285,33 @@ class BookingEditParticipantType extends AbstractType
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Traverse up the form tree to get the root form's data (BookingEditDto)
|
||||||
|
$rootForm = $form;
|
||||||
|
while ($rootForm->getParent()) {
|
||||||
|
$rootForm = $rootForm->getParent();
|
||||||
|
}
|
||||||
|
/** @var BookingDtoInterface $bookingDto */
|
||||||
|
$bookingDto = $rootForm->getData();
|
||||||
|
$participantIndex = $form->getData()->index;
|
||||||
|
|
||||||
|
// Helper to get state for a field based on submitted data
|
||||||
|
$getState = fn(string $field) => $this->fieldStateProvider->getFieldState($field, $bookingDto, $participantIndex, $data);
|
||||||
|
|
||||||
|
// Re-apply field states to all personal data fields
|
||||||
|
$personalDataFields = [
|
||||||
|
'firstName', 'lastName', 'dateOfBirth', 'gender', 'nationality', 'email', 'mobile'
|
||||||
|
];
|
||||||
|
foreach ($personalDataFields as $field) {
|
||||||
|
if ($form->has($field)) {
|
||||||
|
$fieldConfig = $form->get($field)->getConfig();
|
||||||
|
$currentOptions = $fieldConfig->getOptions();
|
||||||
|
$updatedOptions = $this->mergeFieldState($currentOptions, $getState($field));
|
||||||
|
$fieldType = $fieldConfig->getType()->getInnerType();
|
||||||
|
$form->remove($field);
|
||||||
|
$form->add($field, $fieldType::class, $updatedOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$transportationId = $data['transportationServiceTo'] ?? null;
|
$transportationId = $data['transportationServiceTo'] ?? null;
|
||||||
$transportation = $options['travel']->pickups[$transportationId] ?? null;
|
$transportation = $options['travel']->pickups[$transportationId] ?? null;
|
||||||
|
|
||||||
@@ -344,6 +362,33 @@ class BookingEditParticipantType extends AbstractType
|
|||||||
'transportation_services_mutable' => true,
|
'transportation_services_mutable' => true,
|
||||||
'pickups_mutable' => true,
|
'pickups_mutable' => true,
|
||||||
'applicant_id' => null,
|
'applicant_id' => null,
|
||||||
|
// Booking DTO for field state provider (must be set by parent form)
|
||||||
|
'booking' => null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges field state modifications into existing field options.
|
||||||
|
*
|
||||||
|
* This method combines the base field options with dynamic state modifications,
|
||||||
|
* handling attribute merging and option overrides correctly.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $fieldOptions The base field options
|
||||||
|
* @param array<string, mixed> $fieldState The dynamic state modifications
|
||||||
|
*
|
||||||
|
* @return array<string, mixed> The merged field options with state applied
|
||||||
|
*/
|
||||||
|
private function mergeFieldState(array $fieldOptions, array $fieldState): array
|
||||||
|
{
|
||||||
|
foreach ($fieldState as $key => $value) {
|
||||||
|
if ('attr' === $key && isset($fieldOptions['attr'])) {
|
||||||
|
// Merge attributes instead of overwriting
|
||||||
|
$fieldOptions['attr'] = array_merge($fieldOptions['attr'], $value);
|
||||||
|
} else {
|
||||||
|
// Direct assignment for non-attribute options
|
||||||
|
$fieldOptions[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $fieldOptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,4 +47,11 @@ interface BookingDtoInterface
|
|||||||
* @return ParticipantDto|null The participant DTO or null if not found
|
* @return ParticipantDto|null The participant DTO or null if not found
|
||||||
*/
|
*/
|
||||||
public function getParticipant(int $index): ?ParticipantDto;
|
public function getParticipant(int $index): ?ParticipantDto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all selected rooms for the booking.
|
||||||
|
*
|
||||||
|
* @return array<int, RoomSelectionDto> Array of selected room DTOs (may be empty for edit DTOs)
|
||||||
|
*/
|
||||||
|
public function getSelectedRooms(): array;
|
||||||
}
|
}
|
||||||
@@ -83,4 +83,14 @@ class BookingEditDto implements BookingDtoInterface
|
|||||||
{
|
{
|
||||||
return $this->participants[$index] ?? null;
|
return $this->participants[$index] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all selected rooms for the booking (edit context).
|
||||||
|
*
|
||||||
|
* @return array<int, RoomSelectionDto> Always returns an empty array for edit DTOs unless implemented.
|
||||||
|
*/
|
||||||
|
public function getSelectedRooms(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\ParticipantFieldHandler;
|
namespace App\Form\ParticipantFieldHandler;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class providing common functionality for participant field handlers.
|
* Abstract base class providing common functionality for participant field handlers.
|
||||||
@@ -54,14 +54,15 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle
|
|||||||
* if the participant exists at the given index. Returns null if the
|
* if the participant exists at the given index. Returns null if the
|
||||||
* participant doesn't exist, preventing array access errors.
|
* participant doesn't exist, preventing array access errors.
|
||||||
*
|
*
|
||||||
* @param BookingCreateDto $bookingDto The booking DTO containing participants
|
* @param BookingDtoInterface $bookingDto The booking DTO containing participants (create or edit)
|
||||||
* @param int $participantIndex The index of the participant to retrieve
|
* @param int $participantIndex The index of the participant to retrieve
|
||||||
*
|
*
|
||||||
* @return object|null The participant object, or null if not found
|
* @return object|null The participant object, or null if not found
|
||||||
*/
|
*/
|
||||||
protected function getParticipant(BookingCreateDto $bookingDto, int $participantIndex): ?object
|
protected function getParticipant(BookingDtoInterface $bookingDto, int $participantIndex): ?object
|
||||||
{
|
{
|
||||||
return $bookingDto->participants[$participantIndex] ?? null;
|
$participants = $bookingDto->getParticipants();
|
||||||
|
return $participants[$participantIndex] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,12 +127,12 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle
|
|||||||
* processing results.
|
* processing results.
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $submittedData The submitted participant form data
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
* @param BookingCreateDto $bookingDto The booking DTO (potentially modified by processing)
|
* @param BookingDtoInterface $bookingDto The booking DTO (potentially modified by processing)
|
||||||
* @param int $participantIndex The participant index being processed
|
* @param int $participantIndex The participant index being processed
|
||||||
*
|
*
|
||||||
* @return array<string, array<string, mixed>> Empty array (no state modifications by default)
|
* @return array<string, array<string, mixed>> Empty array (no state modifications by default)
|
||||||
*/
|
*/
|
||||||
public function getFieldStateModifications(array $submittedData, BookingCreateDto $bookingDto, int $participantIndex): array
|
public function getFieldStateModifications(array $submittedData, BookingDtoInterface $bookingDto, int $participantIndex): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\ParticipantFieldHandler\Condition;
|
namespace App\Form\ParticipantFieldHandler\Condition;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Condition that evaluates participant age against specified range criteria.
|
* Condition that evaluates participant age against specified range criteria.
|
||||||
@@ -53,15 +53,15 @@ class AgeRangeCondition implements FieldConditionInterface
|
|||||||
* checks if it falls within the configured age range. Returns false if
|
* checks if it falls within the configured age range. Returns false if
|
||||||
* the participant has no date of birth set.
|
* the participant has no date of birth set.
|
||||||
*
|
*
|
||||||
* @param BookingCreateDto $bookingDto The current booking data
|
* @param BookingDtoInterface $bookingDto The current booking data (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data (unused for age conditions)
|
* @param array<string, mixed> $formData Current form data (unused for age conditions)
|
||||||
*
|
*
|
||||||
* @return bool True if the participant's age meets the criteria, false otherwise
|
* @return bool True if the participant's age meets the criteria, false otherwise
|
||||||
*/
|
*/
|
||||||
public function evaluate(BookingCreateDto $bookingDto, int $participantIndex, array $formData): bool
|
public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
$participant = $bookingDto->participants[$participantIndex] ?? null;
|
$participant = $bookingDto->getParticipant($participantIndex);
|
||||||
|
|
||||||
if (null === $participant || null === $participant->dateOfBirth) {
|
if (null === $participant || null === $participant->dateOfBirth) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Form\ParticipantFieldHandler\Condition;
|
||||||
|
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Condition that checks if the participant is the applicant.
|
||||||
|
*
|
||||||
|
* This is used to apply field state logic (e.g., enable/disable fields)
|
||||||
|
* specifically for the applicant participant in the booking.
|
||||||
|
*
|
||||||
|
* The default logic assumes the applicant is the first participant (index 0),
|
||||||
|
* but this can be adjusted if your domain uses a different rule or property.
|
||||||
|
*/
|
||||||
|
class ApplicantCondition implements FieldConditionInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Evaluates if the participant is the applicant.
|
||||||
|
*
|
||||||
|
* @param BookingDtoInterface $bookingDto The current booking data (create or edit)
|
||||||
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
|
* @param array<string, mixed> $formData Current form data (unused)
|
||||||
|
*
|
||||||
|
* @return bool True if the participant is the applicant, false otherwise
|
||||||
|
*/
|
||||||
|
public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
|
{
|
||||||
|
// Default: applicant is the first participant (index 0)
|
||||||
|
return $participantIndex === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDependentFields(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Checks if the participant is the applicant (index 0)';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\ParticipantFieldHandler\Condition;
|
namespace App\Form\ParticipantFieldHandler\Condition;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composite condition that combines multiple conditions with logical operators.
|
* Composite condition that combines multiple conditions with logical operators.
|
||||||
@@ -63,13 +63,13 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
* evaluation for optimal performance. The evaluation stops as soon as the
|
* evaluation for optimal performance. The evaluation stops as soon as the
|
||||||
* final result can be determined.
|
* final result can be determined.
|
||||||
*
|
*
|
||||||
* @param BookingCreateDto $bookingDto The current booking data
|
* @param BookingDtoInterface $bookingDto The current booking data (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data for condition evaluation
|
* @param array<string, mixed> $formData Current form data for condition evaluation
|
||||||
*
|
*
|
||||||
* @return bool True if the composite condition is met, false otherwise
|
* @return bool True if the composite condition is met, false otherwise
|
||||||
*/
|
*/
|
||||||
public function evaluate(BookingCreateDto $bookingDto, int $participantIndex, array $formData): bool
|
public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
return match ($this->operator) {
|
return match ($this->operator) {
|
||||||
self::OPERATOR_AND => $this->evaluateAnd($bookingDto, $participantIndex, $formData),
|
self::OPERATOR_AND => $this->evaluateAnd($bookingDto, $participantIndex, $formData),
|
||||||
@@ -167,7 +167,7 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
* Returns false as soon as any condition evaluates to false,
|
* Returns false as soon as any condition evaluates to false,
|
||||||
* avoiding unnecessary evaluation of remaining conditions.
|
* avoiding unnecessary evaluation of remaining conditions.
|
||||||
*/
|
*/
|
||||||
private function evaluateAnd(BookingCreateDto $bookingDto, int $participantIndex, array $formData): bool
|
private function evaluateAnd(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
foreach ($this->conditions as $condition) {
|
foreach ($this->conditions as $condition) {
|
||||||
if (!$condition->evaluate($bookingDto, $participantIndex, $formData)) {
|
if (!$condition->evaluate($bookingDto, $participantIndex, $formData)) {
|
||||||
@@ -184,7 +184,7 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
* Returns true as soon as any condition evaluates to true,
|
* Returns true as soon as any condition evaluates to true,
|
||||||
* avoiding unnecessary evaluation of remaining conditions.
|
* avoiding unnecessary evaluation of remaining conditions.
|
||||||
*/
|
*/
|
||||||
private function evaluateOr(BookingCreateDto $bookingDto, int $participantIndex, array $formData): bool
|
private function evaluateOr(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
foreach ($this->conditions as $condition) {
|
foreach ($this->conditions as $condition) {
|
||||||
if ($condition->evaluate($bookingDto, $participantIndex, $formData)) {
|
if ($condition->evaluate($bookingDto, $participantIndex, $formData)) {
|
||||||
@@ -198,7 +198,7 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Evaluates NOT logic by inverting the result of the single condition.
|
* Evaluates NOT logic by inverting the result of the single condition.
|
||||||
*/
|
*/
|
||||||
private function evaluateNot(BookingCreateDto $bookingDto, int $participantIndex, array $formData): bool
|
private function evaluateNot(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
return !$this->conditions[0]->evaluate($bookingDto, $participantIndex, $formData);
|
return !$this->conditions[0]->evaluate($bookingDto, $participantIndex, $formData);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Form\ParticipantFieldHandler\Condition;
|
namespace App\Form\ParticipantFieldHandler\Condition;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingCreateDto;
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for evaluating field state conditions.
|
* Interface for evaluating field state conditions.
|
||||||
@@ -29,13 +30,13 @@ interface FieldConditionInterface
|
|||||||
* state of the booking, participant data, and submitted form values.
|
* state of the booking, participant data, and submitted form values.
|
||||||
* The result is used to determine field state (enabled/disabled/readonly).
|
* The result is used to determine field state (enabled/disabled/readonly).
|
||||||
*
|
*
|
||||||
* @param BookingCreateDto $bookingDto The current booking data
|
* @param BookingDtoInterface $bookingDto The current booking data (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data (may include partial submissions)
|
* @param array<string, mixed> $formData Current form data (may include partial submissions)
|
||||||
*
|
*
|
||||||
* @return bool True if the condition is met, false otherwise
|
* @return bool True if the condition is met, false otherwise
|
||||||
*/
|
*/
|
||||||
public function evaluate(BookingCreateDto $bookingDto, int $participantIndex, array $formData): bool;
|
public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns field names that trigger re-evaluation of this condition.
|
* Returns field names that trigger re-evaluation of this condition.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\ParticipantFieldHandler\Condition;
|
namespace App\Form\ParticipantFieldHandler\Condition;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Condition that evaluates field states based on other field values.
|
* Condition that evaluates field states based on other field values.
|
||||||
@@ -59,13 +59,13 @@ class FieldValueCondition implements FieldConditionInterface
|
|||||||
* against the expected value using the configured operator. Supports
|
* against the expected value using the configured operator. Supports
|
||||||
* both participant-level fields and booking-level fields.
|
* both participant-level fields and booking-level fields.
|
||||||
*
|
*
|
||||||
* @param BookingCreateDto $bookingDto The current booking data
|
* @param BookingDtoInterface $bookingDto The current booking data (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data for condition evaluation
|
* @param array<string, mixed> $formData Current form data for condition evaluation
|
||||||
*
|
*
|
||||||
* @return bool True if the field value meets the condition criteria, false otherwise
|
* @return bool True if the field value meets the condition criteria, false otherwise
|
||||||
*/
|
*/
|
||||||
public function evaluate(BookingCreateDto $bookingDto, int $participantIndex, array $formData): bool
|
public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
$fieldValue = $this->getFieldValue($formData, $participantIndex, $bookingDto);
|
$fieldValue = $this->getFieldValue($formData, $participantIndex, $bookingDto);
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ class FieldValueCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Retrieves field value from form data or participant data.
|
* Retrieves field value from form data or participant data.
|
||||||
*/
|
*/
|
||||||
private function getFieldValue(array $formData, int $participantIndex, BookingCreateDto $bookingDto): mixed
|
private function getFieldValue(array $formData, int $participantIndex, BookingDtoInterface $bookingDto): mixed
|
||||||
{
|
{
|
||||||
// First check participant-specific form data
|
// First check participant-specific form data
|
||||||
if (isset($formData['participants'][$participantIndex][$this->fieldName])) {
|
if (isset($formData['participants'][$participantIndex][$this->fieldName])) {
|
||||||
@@ -182,7 +182,7 @@ class FieldValueCondition implements FieldConditionInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then check participant DTO data
|
// Then check participant DTO data
|
||||||
$participant = $bookingDto->participants[$participantIndex] ?? null;
|
$participant = $bookingDto->getParticipant($participantIndex);
|
||||||
if (null !== $participant && property_exists($participant, $this->fieldName)) {
|
if (null !== $participant && property_exists($participant, $this->fieldName)) {
|
||||||
return $participant->{$this->fieldName};
|
return $participant->{$this->fieldName};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Form\ParticipantFieldHandler\Condition;
|
||||||
|
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Condition that checks if a participant's personal data is mutable in the edit flow.
|
||||||
|
*
|
||||||
|
* This is used to set fields as readonly or disabled if the booking or participant
|
||||||
|
* is not allowed to be modified (e.g., after a certain workflow step or status).
|
||||||
|
*
|
||||||
|
* The logic assumes the BookingDtoInterface or its participant DTOs expose a
|
||||||
|
* 'personalDataMutable' property or method. Adjust as needed for your domain.
|
||||||
|
*/
|
||||||
|
class MutabilityCondition implements FieldConditionInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Evaluates if the participant's personal data is mutable.
|
||||||
|
*
|
||||||
|
* @param BookingDtoInterface $bookingDto The current booking data (create or edit)
|
||||||
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
|
* @param array<string, mixed> $formData Current form data (unused)
|
||||||
|
*
|
||||||
|
* @return bool True if the participant's data is mutable, false otherwise
|
||||||
|
*/
|
||||||
|
public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool
|
||||||
|
{
|
||||||
|
$participant = $bookingDto->getParticipant($participantIndex);
|
||||||
|
if (null === $participant) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $participant->mutable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDependentFields(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Checks if the participant\'s personal data is mutable (edit flow)';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Form\ParticipantFieldHandler;
|
namespace App\Form\ParticipantFieldHandler;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingCreateDto;
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles processing of the assignedRoomId field for booking participants.
|
* Handles processing of the assignedRoomId field for booking participants.
|
||||||
@@ -52,10 +53,10 @@ class ParticipantAssignedRoomFieldHandler extends AbstractParticipantFieldHandle
|
|||||||
* 4. Updates the participant's assignedRoomId property
|
* 4. Updates the participant's assignedRoomId property
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $submittedData The submitted participant form data
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
* @param BookingCreateDto $bookingDto The booking DTO to update
|
* @param BookingDtoInterface $bookingDto The booking DTO to update (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being processed
|
* @param int $participantIndex The index of the participant being processed
|
||||||
*/
|
*/
|
||||||
public function processField(array $submittedData, BookingCreateDto $bookingDto, int $participantIndex): void
|
public function processField(array $submittedData, BookingDtoInterface $bookingDto, int $participantIndex): void
|
||||||
{
|
{
|
||||||
// Safely get the participant object, returning early if not found
|
// Safely get the participant object, returning early if not found
|
||||||
$participant = $this->getParticipant($bookingDto, $participantIndex);
|
$participant = $this->getParticipant($bookingDto, $participantIndex);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\ParticipantFieldHandler;
|
namespace App\Form\ParticipantFieldHandler;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for handling dynamic participant form field processing and state modification.
|
* Interface for handling dynamic participant form field processing and state modification.
|
||||||
@@ -32,10 +32,10 @@ interface ParticipantFieldHandlerInterface
|
|||||||
* Processes the participant field data from submitted form data and updates the DTO.
|
* Processes the participant field data from submitted form data and updates the DTO.
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $submittedData The submitted participant form data
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
* @param BookingCreateDto $bookingDto The booking DTO to update
|
* @param BookingDtoInterface $bookingDto The booking DTO to update (create or edit)
|
||||||
* @param int $participantIndex The participant index being processed
|
* @param int $participantIndex The participant index being processed
|
||||||
*/
|
*/
|
||||||
public function processField(array $submittedData, BookingCreateDto $bookingDto, int $participantIndex): void;
|
public function processField(array $submittedData, BookingDtoInterface $bookingDto, int $participantIndex): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if this handler should process the field based on submitted participant data.
|
* Determines if this handler should process the field based on submitted participant data.
|
||||||
@@ -50,12 +50,12 @@ interface ParticipantFieldHandlerInterface
|
|||||||
* to enable/disable/hide fields based on the handler's processing results.
|
* to enable/disable/hide fields based on the handler's processing results.
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $submittedData The submitted participant form data
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
* @param BookingCreateDto $bookingDto The booking DTO (potentially modified by processing)
|
* @param BookingDtoInterface $bookingDto The booking DTO (potentially modified by processing)
|
||||||
* @param int $participantIndex The participant index being processed
|
* @param int $participantIndex The participant index being processed
|
||||||
*
|
*
|
||||||
* @return array<string, array<string, mixed>> Field state modifications indexed by field name
|
* @return array<string, array<string, mixed>> Field state modifications indexed by field name
|
||||||
*/
|
*/
|
||||||
public function getFieldStateModifications(array $submittedData, BookingCreateDto $bookingDto, int $participantIndex): array;
|
public function getFieldStateModifications(array $submittedData, BookingDtoInterface $bookingDto, int $participantIndex): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns field names whose state is affected by this handler's processing.
|
* Returns field names whose state is affected by this handler's processing.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Form\ParticipantFieldHandler;
|
namespace App\Form\ParticipantFieldHandler;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingCreateDto;
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry for managing and executing participant field handlers in dependency order.
|
* Registry for managing and executing participant field handlers in dependency order.
|
||||||
@@ -70,9 +71,9 @@ class ParticipantFieldHandlerRegistry
|
|||||||
* participant's data and updates the booking DTO accordingly.
|
* participant's data and updates the booking DTO accordingly.
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $submittedData The submitted form data containing participants array
|
* @param array<string, mixed> $submittedData The submitted form data containing participants array
|
||||||
* @param BookingCreateDto $bookingDto The booking DTO to update with processed field values
|
* @param BookingDtoInterface $bookingDto The booking DTO to update with processed field values (create or edit)
|
||||||
*/
|
*/
|
||||||
public function processFields(array $submittedData, BookingCreateDto $bookingDto): void
|
public function processFields(array $submittedData, BookingDtoInterface $bookingDto): void
|
||||||
{
|
{
|
||||||
// Early return if no participant data exists in submission
|
// Early return if no participant data exists in submission
|
||||||
if (!isset($submittedData['participants']) || !is_array($submittedData['participants'])) {
|
if (!isset($submittedData['participants']) || !is_array($submittedData['participants'])) {
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Form\Service;
|
||||||
|
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
use App\Form\ParticipantFieldHandler\Condition\FieldConditionInterface;
|
||||||
|
use App\Form\ParticipantFieldHandler\Condition\MutabilityCondition;
|
||||||
|
use App\Form\ParticipantFieldHandler\Condition\ApplicantCondition;
|
||||||
|
use App\Form\ParticipantFieldHandler\Condition\CompositeCondition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field state provider for the booking edit workflow.
|
||||||
|
*
|
||||||
|
* This service calculates dynamic field states (readonly, disabled, etc.)
|
||||||
|
* for participant fields in the edit flow, using edit-specific conditions.
|
||||||
|
*
|
||||||
|
* It is designed to be extensible and composable, allowing reuse of
|
||||||
|
* existing condition classes and easy registration of new logic.
|
||||||
|
*/
|
||||||
|
class EditFieldStateProvider implements FieldStateProviderInterface
|
||||||
|
{
|
||||||
|
/** @var array<string, array<string, FieldConditionInterface>> */
|
||||||
|
private array $fieldStateConditions = [];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->registerFieldStateConditions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers field state conditions for the edit workflow.
|
||||||
|
*
|
||||||
|
* Add or modify conditions as needed for your domain.
|
||||||
|
*/
|
||||||
|
private function registerFieldStateConditions(): void
|
||||||
|
{
|
||||||
|
// Make all personal data fields readonly if not mutable OR if applicant
|
||||||
|
$personalDataFields = [
|
||||||
|
'firstName',
|
||||||
|
'lastName',
|
||||||
|
'dateOfBirth',
|
||||||
|
'gender',
|
||||||
|
'nationality',
|
||||||
|
'email',
|
||||||
|
'mobile',
|
||||||
|
];
|
||||||
|
foreach ($personalDataFields as $field) {
|
||||||
|
$this->fieldStateConditions[$field] = [
|
||||||
|
'readonly' => CompositeCondition::or(
|
||||||
|
new ApplicantCondition(),
|
||||||
|
new MutabilityCondition()
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: Only applicant can edit email
|
||||||
|
$this->fieldStateConditions['email']['readonly'] = new ApplicantCondition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldState(string $fieldName, BookingDtoInterface $bookingDto, int $participantIndex, array $formData = []): array
|
||||||
|
{
|
||||||
|
if (!isset($this->fieldStateConditions[$fieldName])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$stateModifications = [];
|
||||||
|
$attributes = [];
|
||||||
|
|
||||||
|
foreach ($this->fieldStateConditions[$fieldName] as $stateType => $condition) {
|
||||||
|
if ($condition->evaluate($bookingDto, $participantIndex, $formData)) {
|
||||||
|
switch ($stateType) {
|
||||||
|
case 'readonly':
|
||||||
|
$attributes['readonly'] = true;
|
||||||
|
break;
|
||||||
|
case 'disabled':
|
||||||
|
$stateModifications['disabled'] = true;
|
||||||
|
break;
|
||||||
|
case 'required':
|
||||||
|
$stateModifications['required'] = true;
|
||||||
|
break;
|
||||||
|
case 'hidden':
|
||||||
|
$attributes['style'] = ($attributes['style'] ?? '').' display: none;';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($attributes)) {
|
||||||
|
$stateModifications['attr'] = $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stateModifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasStateConditions(string $fieldName): bool
|
||||||
|
{
|
||||||
|
return isset($this->fieldStateConditions[$fieldName]) && !empty($this->fieldStateConditions[$fieldName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldStateDependencies(string $fieldName): array
|
||||||
|
{
|
||||||
|
if (!isset($this->fieldStateConditions[$fieldName])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$dependencies = [];
|
||||||
|
foreach ($this->fieldStateConditions[$fieldName] as $condition) {
|
||||||
|
$dependencies = array_merge($dependencies, $condition->getDependentFields());
|
||||||
|
}
|
||||||
|
return array_unique($dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllFieldStates(BookingDtoInterface $bookingDto, int $participantIndex, array $formData = []): array
|
||||||
|
{
|
||||||
|
$allStates = [];
|
||||||
|
foreach (array_keys($this->fieldStateConditions) as $fieldName) {
|
||||||
|
$fieldState = $this->getFieldState($fieldName, $bookingDto, $participantIndex, $formData);
|
||||||
|
if (!empty($fieldState)) {
|
||||||
|
$allStates[$fieldName] = $fieldState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $allStates;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\Service;
|
namespace App\Form\Service;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for providing dynamic field state based on conditions.
|
* Interface for providing dynamic field state based on conditions.
|
||||||
@@ -46,13 +46,13 @@ interface FieldStateProviderInterface
|
|||||||
* - 'attr' => ['class' => 'conditional-field'] - Add CSS classes
|
* - 'attr' => ['class' => 'conditional-field'] - Add CSS classes
|
||||||
*
|
*
|
||||||
* @param string $fieldName The name of the field to evaluate
|
* @param string $fieldName The name of the field to evaluate
|
||||||
* @param BookingCreateDto $bookingDto The current booking data for context
|
* @param BookingDtoInterface $bookingDto The current booking data for context (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data (may include partial submissions)
|
* @param array<string, mixed> $formData Current form data (may include partial submissions)
|
||||||
*
|
*
|
||||||
* @return array<string, mixed> Symfony form field options for state modifications, empty if no changes needed
|
* @return array<string, mixed> Symfony form field options for state modifications, empty if no changes needed
|
||||||
*/
|
*/
|
||||||
public function getFieldState(string $fieldName, BookingCreateDto $bookingDto, int $participantIndex, array $formData = []): array;
|
public function getFieldState(string $fieldName, BookingDtoInterface $bookingDto, int $participantIndex, array $formData = []): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a field has state conditions configured.
|
* Checks whether a field has state conditions configured.
|
||||||
@@ -91,11 +91,11 @@ interface FieldStateProviderInterface
|
|||||||
* when multiple field states need to be determined simultaneously. It's
|
* when multiple field states need to be determined simultaneously. It's
|
||||||
* particularly useful during form building and bulk state updates.
|
* particularly useful during form building and bulk state updates.
|
||||||
*
|
*
|
||||||
* @param BookingCreateDto $bookingDto The current booking data for context
|
* @param BookingDtoInterface $bookingDto The current booking data for context (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data for condition evaluation
|
* @param array<string, mixed> $formData Current form data for condition evaluation
|
||||||
*
|
*
|
||||||
* @return array<string, array<string, mixed>> Field states indexed by field name
|
* @return array<string, array<string, mixed>> Field states indexed by field name
|
||||||
*/
|
*/
|
||||||
public function getAllFieldStates(BookingCreateDto $bookingDto, int $participantIndex, array $formData = []): array;
|
public function getAllFieldStates(BookingDtoInterface $bookingDto, int $participantIndex, array $formData = []): array;
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\Service;
|
namespace App\Form\Service;
|
||||||
|
|
||||||
use App\Form\Model\BookingCreateDto;
|
use App\Form\Model\BookingDtoInterface;
|
||||||
use App\Form\ParticipantFieldHandler\Condition\FieldConditionInterface;
|
use App\Form\ParticipantFieldHandler\Condition\FieldConditionInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,13 +64,13 @@ class ParticipantFieldOptionsProvider implements FieldStateProviderInterface
|
|||||||
* - 'disabled' - Whether the field should be disabled
|
* - 'disabled' - Whether the field should be disabled
|
||||||
* - 'required' - Whether the field is required
|
* - 'required' - Whether the field is required
|
||||||
*
|
*
|
||||||
* @param string $fieldName The name of the field to configure
|
* @param string $fieldName The name of the field to configure
|
||||||
* @param BookingCreateDto $bookingDto The current booking data for context
|
* @param BookingDtoInterface $bookingDto The current booking data for context (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being configured
|
* @param int $participantIndex The index of the participant being configured
|
||||||
*
|
*
|
||||||
* @return array<string, mixed> Symfony form field options, or empty array if field not supported
|
* @return array<string, mixed> Symfony form field options, or empty array if field not supported
|
||||||
*/
|
*/
|
||||||
public function getFieldOptions(string $fieldName, BookingCreateDto $bookingDto, int $participantIndex): array
|
public function getFieldOptions(string $fieldName, BookingDtoInterface $bookingDto, int $participantIndex): array
|
||||||
{
|
{
|
||||||
// Check if we have a provider for this field
|
// Check if we have a provider for this field
|
||||||
if (!isset($this->fieldOptionProviders[$fieldName])) {
|
if (!isset($this->fieldOptionProviders[$fieldName])) {
|
||||||
@@ -121,7 +121,7 @@ class ParticipantFieldOptionsProvider implements FieldStateProviderInterface
|
|||||||
private function registerFieldOptionProviders(): void
|
private function registerFieldOptionProviders(): void
|
||||||
{
|
{
|
||||||
// Room assignment field provider
|
// Room assignment field provider
|
||||||
$this->fieldOptionProviders['assignedRoomId'] = fn (BookingCreateDto $bookingDto, int $participantIndex) => [
|
$this->fieldOptionProviders['assignedRoomId'] = fn (BookingDtoInterface $bookingDto, int $participantIndex) => [
|
||||||
'label' => 'Zimmer',
|
'label' => 'Zimmer',
|
||||||
'placeholder' => 'Bitte wählen',
|
'placeholder' => 'Bitte wählen',
|
||||||
// Use factory to create context-aware choice loader that:
|
// Use factory to create context-aware choice loader that:
|
||||||
@@ -155,13 +155,13 @@ class ParticipantFieldOptionsProvider implements FieldStateProviderInterface
|
|||||||
* disabled, etc.) and evaluated independently.
|
* disabled, etc.) and evaluated independently.
|
||||||
*
|
*
|
||||||
* @param string $fieldName The name of the field to evaluate
|
* @param string $fieldName The name of the field to evaluate
|
||||||
* @param BookingCreateDto $bookingDto The current booking data for context
|
* @param BookingDtoInterface $bookingDto The current booking data for context (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data for condition evaluation
|
* @param array<string, mixed> $formData Current form data for condition evaluation
|
||||||
*
|
*
|
||||||
* @return array<string, mixed> Symfony form field options for state modifications
|
* @return array<string, mixed> Symfony form field options for state modifications
|
||||||
*/
|
*/
|
||||||
public function getFieldState(string $fieldName, BookingCreateDto $bookingDto, int $participantIndex, array $formData = []): array
|
public function getFieldState(string $fieldName, BookingDtoInterface $bookingDto, int $participantIndex, array $formData = []): array
|
||||||
{
|
{
|
||||||
if (!isset($this->fieldStateConditions[$fieldName])) {
|
if (!isset($this->fieldStateConditions[$fieldName])) {
|
||||||
return [];
|
return [];
|
||||||
@@ -233,13 +233,13 @@ class ParticipantFieldOptionsProvider implements FieldStateProviderInterface
|
|||||||
/**
|
/**
|
||||||
* Calculates field states for all configured fields at once.
|
* Calculates field states for all configured fields at once.
|
||||||
*
|
*
|
||||||
* @param BookingCreateDto $bookingDto The current booking data for context
|
* @param BookingDtoInterface $bookingDto The current booking data for context (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being evaluated
|
* @param int $participantIndex The index of the participant being evaluated
|
||||||
* @param array<string, mixed> $formData Current form data for condition evaluation
|
* @param array<string, mixed> $formData Current form data for condition evaluation
|
||||||
*
|
*
|
||||||
* @return array<string, array<string, mixed>> Field states indexed by field name
|
* @return array<string, array<string, mixed>> Field states indexed by field name
|
||||||
*/
|
*/
|
||||||
public function getAllFieldStates(BookingCreateDto $bookingDto, int $participantIndex, array $formData = []): array
|
public function getAllFieldStates(BookingDtoInterface $bookingDto, int $participantIndex, array $formData = []): array
|
||||||
{
|
{
|
||||||
$allStates = [];
|
$allStates = [];
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3>Zusammenfassung</h3>
|
<h3>Zusammenfassung</h3>
|
||||||
<p>Reise: {{ bookingCreateDto.travelData.label }}</p>
|
<p>Reise: {{ bookingCreateDto.travel.label }}</p>
|
||||||
<p>Datum: {{ bookingCreateDto.travelData.dateFrom | date('d.m.Y') }} - {{ bookingCreateDto.travelData.dateTo | date('d.m.Y') }}</p>
|
<p>Datum: {{ bookingCreateDto.travel.dateFrom | date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo | date('d.m.Y') }}</p>
|
||||||
<p>Hotel: {{ bookingCreateDto.travelData.hotel.name }}</p>
|
<p>Hotel: {{ bookingCreateDto.travel.hotel.name }}</p>
|
||||||
{% if participantsCount > 0 %}
|
{% if participantsCount > 0 %}
|
||||||
<p>Teilnehmerzahl: {{ participantsCount }}</p>
|
<p>Teilnehmerzahl: {{ participantsCount }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -71,19 +71,19 @@
|
|||||||
Reise
|
Reise
|
||||||
</h4>
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
{{ bookingCreateDto.travelData.label }}
|
{{ bookingCreateDto.travel.label }}
|
||||||
</p>
|
</p>
|
||||||
<h4>
|
<h4>
|
||||||
Datum
|
Datum
|
||||||
</h4>
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
{{ bookingCreateDto.travelData.dateFrom | date('d.m.Y') }} - {{ bookingCreateDto.travelData.dateTo | date('d.m.Y') }}
|
{{ bookingCreateDto.travel.dateFrom | date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo | date('d.m.Y') }}
|
||||||
</p>
|
</p>
|
||||||
<h4>
|
<h4>
|
||||||
Unterkunft
|
Unterkunft
|
||||||
</h4>
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
{{ bookingCreateDto.travelData.hotel.name }}
|
{{ bookingCreateDto.travel.hotel.name }}
|
||||||
</p>
|
</p>
|
||||||
{% if participantsCount > 0 %}
|
{% if participantsCount > 0 %}
|
||||||
<h4>
|
<h4>
|
||||||
|
|||||||
Reference in New Issue
Block a user