per participant, not aggregated * in collection. Validation is performed by PurchaseVoucher constraint. * * Dependencies: None (purchase vouchers don't require price calculation) */ class ParticipantPurchaseVoucherFieldHandler extends AbstractParticipantFieldHandler { public function __construct( private readonly VoucherValidationService $voucherValidationService, ) { } public function getFieldName(): string { return 'purchaseVoucherCode'; } public function getDependencies(): array { // No dependencies - purchase vouchers don't require price calculation return []; } public function shouldProcess(array $submittedData, string $mode, int $participantIndex): bool { $voucherCode = $this->getFieldValue($submittedData, $this->getFieldName()); return null !== $voucherCode && '' !== trim($voucherCode); } public function processField(array $submittedData, BookingDto $bookingDto, int $participantIndex): void { $participant = $this->getParticipant($bookingDto, $participantIndex); if (null === $participant) { return; } $voucherCode = $this->getFieldValue($submittedData, $this->getFieldName()); // Clear validated voucher if code is empty if (null === $voucherCode || '' === trim($voucherCode)) { $participant->validatedPurchaseVoucher = null; return; } // Validate voucher and store result $result = $this->voucherValidationService->validatePurchaseVoucher($voucherCode); // Store validated voucher (null if invalid) $participant->validatedPurchaseVoucher = $result->isValid ? $result->voucher : null; } }