handler = new ParticipantEmailFieldHandler(); } public function testChildWithoutEmailInheritsTheApplicants(): void { $bookingDto = $this->createBookingDto(); $this->handler->processField(['email' => ''], $bookingDto, 1); $this->assertSame('applicant@example.com', $bookingDto->participants[1]->email); } public function testChildKeepsAnEmailThatWasTypedIn(): void { $bookingDto = $this->createBookingDto(); $this->handler->processField(['email' => 'kind@example.com'], $bookingDto, 1); $this->assertSame( 'kind@example.com', $bookingDto->participants[1]->email, 'The pre-filled address stays overridable' ); } public function testAdultWithoutEmailDoesNotInherit(): void { $bookingDto = $this->createBookingDto(); $bookingDto->participants[1]->dateOfBirth = new \DateTimeImmutable('1990-01-01'); $this->handler->processField(['email' => ''], $bookingDto, 1); $this->assertNull( $bookingDto->participants[1]->email, 'An adult supplies their own address; NotBlank reports the gap' ); } public function testApplicantDoesNotInheritFromThemselves(): void { $bookingDto = $this->createBookingDto(); $bookingDto->participants[0]->dateOfBirth = new \DateTimeImmutable('2015-01-01'); $this->handler->processField(['email' => ''], $bookingDto, 0); $this->assertNull($bookingDto->participants[0]->email); } public function testChildAtIndexZeroInheritsWhenTheApplicantDoesNotTravel(): void { $bookingDto = $this->createBookingDto(); $bookingDto->applicantTravels = false; $bookingDto->applicant = $this->createParticipant('elternteil@example.com', '1981-03-16'); $bookingDto->participants[0]->dateOfBirth = new \DateTimeImmutable('2015-01-01'); $this->handler->processField(['email' => ''], $bookingDto, 0); $this->assertSame('elternteil@example.com', $bookingDto->participants[0]->email); } public function testEditModeNeverPreFills(): void { $bookingDto = $this->createBookingDto(); $bookingDto->booking = new Booking(); $this->handler->processField(['email' => ''], $bookingDto, 1); $this->assertNull( $bookingDto->participants[1]->email, 'participant[0] is not reliably the applicant in edit mode, and a blank may be intended' ); } public function testEditModeLeavesAnInternalAgencyChildWithoutEmail(): void { $bookingDto = $this->createBookingDto(); $bookingDto->booking = new Booking(); $bookingDto->agencyCode = AgencyLoader::INTERNAL_AGENCY_CODE; $this->handler->processField(['email' => ''], $bookingDto, 1); $this->assertNull($bookingDto->participants[1]->email); } public function testHandlerRunsAfterDateOfBirth(): void { $this->assertSame( ['dateOfBirth'], $this->handler->getDependencies(), 'Whether someone counts as a child is only known once their DOB is processed' ); } /** * The handler runs in PRE_SUBMIT and writes to the DTO, but the form then binds the submitted * data over it. Only fields the registry syncs back survive, so the pre-filled address has to * reappear in the returned data - otherwise the blank wins and the field renders empty. */ public function testPreFilledEmailIsSyncedBackIntoTheSubmittedData(): void { $bookingDto = $this->createBookingDto(); $registry = new ParticipantFieldHandlerRegistry([ new ParticipantDateOfBirthFieldHandler(new NullLogger()), new ParticipantEmailFieldHandler(), ]); $synced = $registry->processFieldsForParticipantAndSync(['email' => ''], $bookingDto, 1); $this->assertSame('applicant@example.com', $bookingDto->participants[1]->email); $this->assertSame( 'applicant@example.com', $synced['email'], 'Without the sync the form binds the blank back over the pre-filled address' ); } private function createBookingDto(): BookingDto { $bookingDto = new BookingDto(new Travel(), 1); $bookingDto->participants = [ $this->createParticipant('applicant@example.com', '1980-01-01'), $this->createParticipant('', '2015-01-01'), ]; $bookingDto->participants[0]->index = 0; $bookingDto->participants[1]->index = 1; $bookingDto->participants[1]->email = null; return $bookingDto; } private function createParticipant(string $email, string $dateOfBirth): ParticipantDto { $participant = new ParticipantDto(); $participant->email = '' !== $email ? $email : null; $participant->dateOfBirth = new \DateTimeImmutable($dateOfBirth); return $participant; } }