chore: remove dead code

This commit is contained in:
Björn Fromme
2026-03-16 12:03:00 +01:00
parent e505eba111
commit e6880b7fed
-427
View File
@@ -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&nbsp;€)',
$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;
}
}