6.4 KiB
Address Fields Implementation
Date: 2025-10-06 Status: ✅ TESTED SUCCESSFULLY (2025-10-06)
Overview
Added participant address collection to the booking create flow. Address is mandatory for the applicant (first participant) and optional for others.
Implementation
1. Models
ParticipantDto (src/Form/Model/ParticipantDto.php):
- Added
Address $addressproperty - Made email field required (
@Assert\NotBlank) - Added constructor to initialize
Addressobject - Removed
@Assert\NotNullconstraint (validation handled by ParticipantValidator)
Address (src/BusProNet/Model/Address.php):
- Already had
toPayload()method for XML generation - Properties: street, postCode, city, district, country
- No changes needed (existing model worked perfectly)
2. Forms
AddressType (src/Form/AddressType.php) - NEW:
class AddressType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('street', TextType::class, [...])
->add('postCode', TextType::class, [...])
->add('city', TextType::class, [...])
->add('country', CountryType::class, [
'property' => 'country',
'preferred_choices' => ['DE', 'AT', 'CH'],
]);
}
}
BookingParticipantType (src/Form/BookingParticipantType.php):
- Added address field after mobile field
required => 0 === $participantIndex(mandatory for applicant)- Added 'address' to
$baseFieldsarray for rebuild handling
3. Validation
ParticipantValidator (src/Validator/Constraints/ParticipantValidator.php):
- Added
assertApplicantAddressValid()method - Validates street, postCode, city, country for applicant only
- Uses
$participant->isApplicant()to check if validation should run - Error messages: "Bitte angeben" for each missing field
4. Payload Generation
BookingDataProcessor (src/BusProNet/DataProcessor/BookingDataProcessor.php):
Applicant section (lines 451-454):
// Add address for applicant
if (null !== $firstParticipant->address) {
$payload['anmelder']['anschrift'] = $firstParticipant->address->toPayload();
}
Participant list (lines 481-488):
// Add address (always include structure, even if empty)
$participantData['anschrift'] = $participant->address?->toPayload() ?? [
'strasse' => null,
'plz' => null,
'ort' => null,
'ortsteil' => null,
'land' => null,
];
XML Output:
<anmelder>
<anschrift>
<strasse>Gablonzer Straße 32</strasse>
<plz>53359</plz>
<ort>Rheinbach</ort>
<ortsteil />
<land>D</land>
</anschrift>
</anmelder>
<teilnehmerliste>
<teilnehmer id="1">
<anschrift>
<strasse>Gablonzer Straße 32</strasse>
<plz>53359</plz>
<ort>Rheinbach</ort>
<ortsteil />
<land>D</land>
</anschrift>
</teilnehmer>
</teilnehmerliste>
Bug Fixes (Same Session)
1. Room Quantity Fix
Issue: Room @anzahl was set to participant count instead of room quantity
Fix: Use roomSelections[].quantity from step 1 (lines 576-603)
$roomQuantities = [];
foreach ($bookingDto->roomSelections as $selection) {
if ($selection->quantity > 0) {
$roomQuantities[$selection->roomId] = $selection->quantity;
}
}
$quantity = $roomQuantities[$roomId] ?? 1;
2. Insurance Selection for Dependent Participants
Issue: ParticipantBulkInsuranceFieldHandler cleared independent selections on every form submit
Fix: Added wasBulkInsurancePreviouslyEnabled() check (lines 90, 144-176)
if (false === $isBulkEnabled && $this->wasBulkInsurancePreviouslyEnabled($bookingDto)) {
$this->clearDependentParticipantsInsurance($bookingDto);
}
Files Modified
src/Form/Model/ParticipantDto.php- Added address property, constructor, required emailsrc/Form/AddressType.php- NEW form typesrc/Form/BookingParticipantType.php- Added address fieldsrc/Validator/Constraints/ParticipantValidator.php- Added address validationsrc/BusProNet/DataProcessor/BookingDataProcessor.php- Address in payload, room quantity fix,isApplicant()usagesrc/Form/Service/ParticipantBulkInsuranceFieldHandler.php- Insurance clearing fix
Testing
Manual Testing Checklist:
- Applicant address required (all fields) - ✅ PASSED
- Dependent participant address optional - ✅ PASSED
- Country dropdown shows DE, AT, CH first - ✅ PASSED
- Address appears in XML for applicant - ✅ PASSED
- Address appears in XML for all participants (empty if not provided) - ✅ PASSED
- Email is mandatory for all participants - ✅ PASSED
- Insurance selection works for dependent participants - ✅ PASSED
- Room quantity matches selection from step 1 - ✅ PASSED
Expected XML:
- Applicant: Full address in
<anmelder><anschrift> - All participants: Address structure in
<teilnehmer><anschrift>(may be empty) - Room quantity: Matches quantity selected in step 1, not participant count
Notes
- Address object initialized in ParticipantDto constructor
- Uses existing
Address::toPayload()method for XML generation - CountryType provides nationality dropdown with German country codes
- Validation runs via existing ParticipantValidator constraint
- Template integration happens automatically via Symfony form system
Implementation Status: ✅ TESTED SUCCESSFULLY Code Quality: ✅ PHP-CS-Fixer validated Test Date: 2025-10-06
Test Results
Test Date: 2025-10-06 Environment: DDEV sandbox with BusProNet API
Validated Features:
- ✅ Applicant address validation (all fields mandatory)
- ✅ Dependent participant address optional
- ✅ Country dropdown with preferred choices (DE, AT, CH)
- ✅ Address correctly included in XML payload for applicant
- ✅ Address structure included for all participants (empty nodes for optional)
- ✅ Email mandatory validation working for all participants
- ✅ Mobile mandatory validation working for applicant only
Validated Bug Fixes:
- ✅ Room quantity using correct value from step 1 selections
- ✅ Insurance selection working correctly for dependent participants
- ✅ Pickup locations included with correct quantities
Result: All address field requirements working correctly in production-like environment.