fix: enforce mutability checks for all fields

This commit is contained in:
Björn Fromme
2026-02-24 11:53:00 +01:00
parent 31153e90b4
commit 5a64c85fb6
3 changed files with 67 additions and 3 deletions
@@ -21,6 +21,32 @@ use App\Form\Service\Contract\ParticipantFieldHandlerInterface;
*/
class ParticipantFieldHandlerRegistry
{
private const MUTABILITY_ADDITIONAL_SERVICES = 'additional_services';
private const MUTABILITY_TRANSPORTATION = 'transportation';
private const MUTABILITY_PICKUPS = 'pickups';
/**
* Maps handler names to mutability categories for edit-mode enforcement.
*
* @var array<string, string>
*/
private const HANDLER_MUTABILITY_CATEGORY_MAP = [
'additionalServices' => self::MUTABILITY_ADDITIONAL_SERVICES,
'courses' => self::MUTABILITY_ADDITIONAL_SERVICES,
'board' => self::MUTABILITY_ADDITIONAL_SERVICES,
'veg' => self::MUTABILITY_ADDITIONAL_SERVICES,
'skiPass' => self::MUTABILITY_ADDITIONAL_SERVICES,
'rentals' => self::MUTABILITY_ADDITIONAL_SERVICES,
'rentalInsurance' => self::MUTABILITY_ADDITIONAL_SERVICES,
'transportationOutbound' => self::MUTABILITY_TRANSPORTATION,
'transportationInbound' => self::MUTABILITY_TRANSPORTATION,
'parking' => self::MUTABILITY_TRANSPORTATION,
'licensePlate' => self::MUTABILITY_TRANSPORTATION,
'transportationDiscountReplacement' => self::MUTABILITY_TRANSPORTATION,
'pickup' => self::MUTABILITY_PICKUPS,
'dropOff' => self::MUTABILITY_PICKUPS,
];
/** @var array<string, ParticipantFieldHandlerInterface> Registered handlers indexed by field name */
private array $handlers = [];
@@ -121,6 +147,10 @@ class ParticipantFieldHandlerRegistry
// Process each handler across all participants before moving to the next handler
// This ensures booking-level state (like family booking detection) is accurate
foreach ($sortedHandlerNames as $handlerName) {
if (false === $this->isHandlerMutableForBooking($handlerName, $bookingDto)) {
continue;
}
$handler = $this->handlers[$handlerName];
// Apply this handler to all participants
@@ -158,6 +188,10 @@ class ParticipantFieldHandlerRegistry
// Apply each handler to the specified participant
foreach ($sortedHandlerNames as $handlerName) {
if (false === $this->isHandlerMutableForBooking($handlerName, $bookingDto)) {
continue;
}
$handler = $this->handlers[$handlerName];
// Let each handler decide if it should process this participant's data
@@ -224,8 +258,11 @@ class ParticipantFieldHandlerRegistry
'courses',
'additionalServices',
'board',
'veg',
'pickup',
'dropOff',
'parking',
'licensePlate',
];
foreach ($serviceFields as $fieldName) {
@@ -521,6 +558,25 @@ class ParticipantFieldHandlerRegistry
return $this->convertSingleValueToSubmittedFormat($dtoValue);
}
/**
* Checks whether a field handler is allowed to run based on edit-mode mutability flags.
*/
private function isHandlerMutableForBooking(string $handlerName, BookingDto $bookingDto): bool
{
if (BookingDto::MODE_CREATE === $bookingDto->getMode()) {
return true;
}
$mutabilityCategory = self::HANDLER_MUTABILITY_CATEGORY_MAP[$handlerName] ?? null;
return match ($mutabilityCategory) {
self::MUTABILITY_ADDITIONAL_SERVICES => $bookingDto->travel->additionalServicesMutable,
self::MUTABILITY_TRANSPORTATION => $bookingDto->travel->transportationServicesMutable,
self::MUTABILITY_PICKUPS => $bookingDto->travel->pickupsMutable,
default => true,
};
}
/**
* Converts a single DTO value to submitted form format.
*