chore: remove dead code
This commit is contained in:
@@ -1,427 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\BusProNet\Constants;
|
||||
use App\BusProNet\Form\CountryType;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use App\Form\Service\EditFieldStateProvider;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class BookingEditParticipantType extends AbstractType
|
||||
{
|
||||
public function __construct(private readonly EditFieldStateProvider $fieldStateProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
|
||||
/** @var ParticipantDto $participantData */
|
||||
$participantData = $event->getData();
|
||||
$participantIndex = $participantData->index;
|
||||
|
||||
// don't add any fields for canceled participants
|
||||
if ('S' === $participantData->status) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form = $event->getForm();
|
||||
|
||||
// Get the booking DTO from the root form
|
||||
$bookingDto = $this->fieldStateProvider->getBookingDtoFromForm($form);
|
||||
|
||||
if (null === $bookingDto) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Helper to get state for a field
|
||||
$getState = fn (string $field) => $this->fieldStateProvider->getFieldState($field, $bookingDto, $participantIndex);
|
||||
|
||||
$form
|
||||
->add('firstName', TextType::class, $this->mergeFieldState([
|
||||
'label' => 'Vorname',
|
||||
'sanitize_html' => true,
|
||||
], $getState('firstName')))
|
||||
->add('lastName', TextType::class, $this->mergeFieldState([
|
||||
'label' => 'Nachname',
|
||||
'sanitize_html' => true,
|
||||
], $getState('lastName')))
|
||||
->add('dateOfBirth', BirthdayType::class, $this->mergeFieldState([
|
||||
'label' => 'Geburtsdatum',
|
||||
'html5' => true,
|
||||
'widget' => 'single_text',
|
||||
'input' => 'datetime_immutable',
|
||||
], $getState('dateOfBirth')))
|
||||
->add('gender', ChoiceType::class, $this->mergeFieldState([
|
||||
'label' => 'Geschlecht',
|
||||
'required' => false,
|
||||
'placeholder' => 'keine Angabe',
|
||||
'choices' => [
|
||||
'männlich' => 'M',
|
||||
'weiblich' => 'W',
|
||||
'divers' => 'D',
|
||||
],
|
||||
], $getState('gender')))
|
||||
->add('nationality', CountryType::class, $this->mergeFieldState([
|
||||
'label' => 'Nationalität',
|
||||
'property' => 'nationality',
|
||||
'required' => true,
|
||||
'preferred_choices' => ['D', 'A', 'CH'],
|
||||
'empty_data' => 'D',
|
||||
], $getState('nationality')))
|
||||
->add('email', EmailType::class, $this->mergeFieldState([
|
||||
'label' => 'E-Mail',
|
||||
'required' => false,
|
||||
'sanitize_html' => true,
|
||||
], $getState('email')))
|
||||
->add('mobile', TextType::class, $this->mergeFieldState([
|
||||
'label' => 'Telefon (mobil)',
|
||||
'required' => false,
|
||||
'sanitize_html' => true,
|
||||
], $getState('mobile')))
|
||||
->add('bodyDimensions', BodyDimensionsType::class, [
|
||||
'height_choices' => $options['height_choices'],
|
||||
'weight_choices' => $options['weight_choices'],
|
||||
'shoe_size_min' => $options['shoe_size_min'],
|
||||
'shoe_size_max' => $options['shoe_size_max'],
|
||||
]);
|
||||
|
||||
$commonChoiceFieldOptions = [
|
||||
'required' => false,
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'choice_value' => 'id',
|
||||
'choice_label' => function (?Service $service) use ($participantIndex) {
|
||||
$price = $service->individualPrice[$participantIndex] ?? $service->price;
|
||||
if (null === $price) {
|
||||
return $service->label;
|
||||
}
|
||||
|
||||
if (0.0 === $price) {
|
||||
return sprintf('%s (inkl.)', $service->label);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'%s (%s €)',
|
||||
$service->label,
|
||||
number_format($price, 2, ',', '.')
|
||||
);
|
||||
},
|
||||
'choice_attr' => function (?Service $service) use ($options) {
|
||||
$attributes = [
|
||||
'data-booking-target' => 'field',
|
||||
'data-action' => 'booking#toggle',
|
||||
];
|
||||
|
||||
// forcibly select mandatory services
|
||||
if (true === $service->mandatory) {
|
||||
$attributes['checked'] = true;
|
||||
$attributes['readonly'] = true;
|
||||
$attributes['class'] = 'text-pink';
|
||||
$attributes['tooltip'] = 'Diese Leistung ist nicht abwählbar';
|
||||
}
|
||||
|
||||
// disable selection of services only available in booking data
|
||||
if (Constants::SOURCE_BOOKING === $service->source) {
|
||||
$attributes['class'] = 'text-pink';
|
||||
}
|
||||
|
||||
// disable selection of services that are unavailable according to their status
|
||||
if (Constants::STATUS_BLOCKED === $service->status) {
|
||||
$attributes['checked'] = false;
|
||||
$attributes['readonly'] = true;
|
||||
$attributes['tooltip'] = 'Diese Leistung ist derzeit leider nicht buchbar';
|
||||
}
|
||||
|
||||
if (false === $options['additional_services_mutable']) {
|
||||
$attributes['readonly'] = true;
|
||||
$attributes['tooltip'] = 'Diese Leistung kann nicht mehr geändert werden';
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
},
|
||||
'choice_filter' => function (?Service $service) use ($participantData) {
|
||||
if (null === $service) {
|
||||
return false;
|
||||
}
|
||||
// remove choices only available in booking data and
|
||||
// which are not mapped to the current participant
|
||||
if (
|
||||
Constants::SOURCE_TRAVEL === $service->source
|
||||
|| Constants::CATEGORY_ADDITIONAL !== $service->category
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return in_array($participantData->index, $service->mapping);
|
||||
},
|
||||
];
|
||||
|
||||
// Additional services
|
||||
if (0 < count($options['selectable_courses'])) {
|
||||
$form->add('courses', ChoiceType::class, [
|
||||
...$commonChoiceFieldOptions,
|
||||
'label' => 'Kurse',
|
||||
'choices' => $options['selectable_courses'],
|
||||
]);
|
||||
}
|
||||
if (0 < count($options['selectable_services'])) {
|
||||
$form->add('additionalServices', ChoiceType::class, [
|
||||
...$commonChoiceFieldOptions,
|
||||
'label' => 'Zusatzleistungen',
|
||||
'choices' => $options['selectable_services'],
|
||||
]);
|
||||
}
|
||||
if (0 < count($options['selectable_ski_passes'])) {
|
||||
$form->add('skiPass', ChoiceType::class, [
|
||||
...$commonChoiceFieldOptions,
|
||||
'label' => 'Skipass',
|
||||
'choices' => $options['selectable_ski_passes'],
|
||||
]);
|
||||
}
|
||||
if (0 < count($options['selectable_board'])) {
|
||||
$form->add('board', ChoiceType::class, [
|
||||
...$commonChoiceFieldOptions,
|
||||
'label' => 'Verpflegung',
|
||||
'choices' => $options['selectable_board'],
|
||||
]);
|
||||
}
|
||||
if (0 < count($options['selectable_rentals'])) {
|
||||
$form->add('rentals', ChoiceType::class, [
|
||||
...$commonChoiceFieldOptions,
|
||||
'label' => 'Verleih',
|
||||
'choices' => $options['selectable_rentals'],
|
||||
]);
|
||||
}
|
||||
|
||||
// Transportation
|
||||
$transportationChoiceAttributes = function (?Service $service) use ($options) {
|
||||
$attributes = [
|
||||
'data-booking-target' => 'field',
|
||||
'data-action' => 'select-toggle#toggle booking#toggle',
|
||||
'data-select-toggle-value' => $service->subType,
|
||||
];
|
||||
if (false === $options['transportation_services_mutable']) {
|
||||
$attributes['readonly'] = true;
|
||||
$attributes['tooltip'] = 'Diese Leistung kann nicht mehr geändert werden';
|
||||
}
|
||||
if (Constants::STATUS_BLOCKED === $service->status) {
|
||||
$attributes['checked'] = false;
|
||||
$attributes['readonly'] = true;
|
||||
$attributes['tooltip'] = 'Diese Leistung ist derzeit leider nicht buchbar';
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
};
|
||||
$form
|
||||
->add('transportationOutbound', ChoiceType::class, [
|
||||
...$commonChoiceFieldOptions,
|
||||
'label' => 'Anreise',
|
||||
'required' => true,
|
||||
'multiple' => false,
|
||||
'choices' => $options['selectable_transportation_services_to'],
|
||||
'choice_attr' => $transportationChoiceAttributes,
|
||||
])
|
||||
->add('transportationInbound', ChoiceType::class, [
|
||||
...$commonChoiceFieldOptions,
|
||||
'label' => 'Rückreise',
|
||||
'required' => true,
|
||||
'multiple' => false,
|
||||
'choices' => $options['selectable_transportation_services_fro'],
|
||||
'choice_attr' => $transportationChoiceAttributes,
|
||||
]);
|
||||
|
||||
// Pickup (unified for both directions)
|
||||
$form->add('pickup', ChoiceType::class, [
|
||||
'label' => 'Zu- und Ausstieg',
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'choices' => $options['selectable_pickups'],
|
||||
'choice_value' => 'id',
|
||||
'choice_label' => function (?Pickup $pickup) {
|
||||
if (null === $pickup) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pickupLabel = $pickup->city;
|
||||
|
||||
if (null !== $pickup->street) {
|
||||
$pickupLabel .= ' ('.$pickup->street.')';
|
||||
}
|
||||
|
||||
$price = $pickup->price;
|
||||
|
||||
if (null === $price) {
|
||||
return $pickupLabel;
|
||||
}
|
||||
|
||||
if (0.0 === $price) {
|
||||
return sprintf('%s (inkl.)', $pickupLabel);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'%s %s€',
|
||||
$pickupLabel,
|
||||
number_format($price, 2, ',', '.')
|
||||
);
|
||||
},
|
||||
'choice_attr' => function (?Pickup $pickup) use ($options) {
|
||||
$attributes = [];
|
||||
if (false === $options['pickups_mutable']) {
|
||||
$attributes['readonly'] = true;
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
},
|
||||
'attr' => [
|
||||
'readonly' => false === $options['pickups_mutable'],
|
||||
],
|
||||
]);
|
||||
})
|
||||
->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
|
||||
$data = $event->getData();
|
||||
$form = $event->getForm();
|
||||
|
||||
// skip processing for canceled participants
|
||||
if ('F' !== $form->getData()->status) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the booking DTO from the root form
|
||||
$bookingDto = $this->fieldStateProvider->getBookingDtoFromForm($form);
|
||||
|
||||
if (null === $bookingDto) {
|
||||
return;
|
||||
}
|
||||
$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',
|
||||
];
|
||||
// Re-apply field states by rebuilding fields with updated state
|
||||
// Note: We need to store the field types and rebuild them since we cannot modify existing field configs
|
||||
$fieldDefinitions = [
|
||||
'firstName' => [TextType::class, ['label' => 'Vorname', 'sanitize_html' => true]],
|
||||
'lastName' => [TextType::class, ['label' => 'Nachname', 'sanitize_html' => true]],
|
||||
'dateOfBirth' => [BirthdayType::class, ['label' => 'Geburtsdatum', 'html5' => true, 'widget' => 'single_text', 'input' => 'datetime_immutable']],
|
||||
'gender' => [ChoiceType::class, ['label' => 'Geschlecht', 'required' => false, 'placeholder' => 'keine Angabe', 'choices' => ['männlich' => 'M', 'weiblich' => 'W', 'divers' => 'D']]],
|
||||
'nationality' => [CountryType::class, ['label' => 'Nationalität', 'property' => 'nationality', 'preferred_choices' => ['D', 'A', 'CH']]],
|
||||
'email' => [EmailType::class, ['label' => 'E-Mail', 'required' => false, 'sanitize_html' => true]],
|
||||
'mobile' => [TextType::class, ['label' => 'Telefon (mobil)', 'required' => false, 'sanitize_html' => true]],
|
||||
];
|
||||
|
||||
foreach ($personalDataFields as $field) {
|
||||
if ($form->has($field) && isset($fieldDefinitions[$field])) {
|
||||
[$fieldType, $baseOptions] = $fieldDefinitions[$field];
|
||||
$updatedOptions = $this->mergeFieldState($baseOptions, $getState($field));
|
||||
$form->remove($field);
|
||||
$form->add($field, $fieldType, $updatedOptions);
|
||||
}
|
||||
}
|
||||
|
||||
$transportationId = $data['transportationOutbound'] ?? null;
|
||||
$transportation = $options['travel']->pickups[$transportationId] ?? null;
|
||||
|
||||
if (null !== $transportation && 'PKW' === $transportation->subType) {
|
||||
$form->remove('pickup');
|
||||
unset($data['pickup']);
|
||||
}
|
||||
|
||||
// forcibly select mandatory services that potentially have been disabled in PRE_SET_DATA
|
||||
$mandatoryServices = array_filter($options['selectable_services'], function (Service $service) use ($form) {
|
||||
$participantIndex = $form->getData()->index;
|
||||
|
||||
return true === $service->mandatory
|
||||
|| (Constants::SOURCE_BOOKING === $service->source && in_array($participantIndex, $service->mapping));
|
||||
});
|
||||
|
||||
if (0 < count($mandatoryServices)) {
|
||||
if (false === isset($data['additionalServices'])) {
|
||||
$data['additionalServices'] = [];
|
||||
}
|
||||
|
||||
$mandatoryServiceIds = array_map(function (Service $service) {
|
||||
return $service->id;
|
||||
}, $mandatoryServices);
|
||||
|
||||
$allServiceIds = [...$mandatoryServiceIds, ...$data['additionalServices']];
|
||||
$data['additionalServices'] = array_unique($allServiceIds);
|
||||
}
|
||||
|
||||
$event->setData($data);
|
||||
});
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => ParticipantDto::class,
|
||||
'selectable_courses' => [],
|
||||
'selectable_ski_passes' => [],
|
||||
'selectable_services' => [],
|
||||
'selectable_board' => [],
|
||||
'selectable_rentals' => [],
|
||||
'selectable_transportation_services_to' => [],
|
||||
'selectable_transportation_services_fro' => [],
|
||||
'selectable_pickups' => [],
|
||||
'personal_data_mutable' => true,
|
||||
'additional_services_mutable' => true,
|
||||
'transportation_services_mutable' => true,
|
||||
'pickups_mutable' => true,
|
||||
'applicant_id' => null,
|
||||
// Booking DTO for field state provider (must be set by parent form)
|
||||
'booking' => null,
|
||||
// Body dimensions choices
|
||||
'height_choices' => [],
|
||||
'weight_choices' => [],
|
||||
'shoe_size_min' => 36,
|
||||
'shoe_size_max' => 48,
|
||||
]);
|
||||
|
||||
$resolver->setAllowedTypes('height_choices', 'array');
|
||||
$resolver->setAllowedTypes('weight_choices', 'array');
|
||||
$resolver->setAllowedTypes('shoe_size_min', 'int');
|
||||
$resolver->setAllowedTypes('shoe_size_max', 'int');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user