Files
myep/src/Service/ParticipantDataPrefiller.php
T

149 lines
5.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Service;
use App\BusProNet\ApiClient;
use App\BusProNet\Model\Address;
use App\BusProNet\Model\Notification;
use App\Entity\User;
use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto;
use App\Security\Crypt;
use Carbon\CarbonImmutable;
use Psr\Log\LoggerInterface;
/**
* Service for prepopulating participant data from authenticated user's personal data.
*
* Fetches personal data from BPN API and maps it to a ParticipantDto to streamline
* the booking process for authenticated users. All errors are handled gracefully
* to ensure the booking flow is never interrupted.
*/
class ParticipantDataPrefiller
{
public const TOKEN = '#KUN#';
public function __construct(
private readonly ApiClient $apiClient,
private readonly Crypt $crypt,
private readonly LoggerInterface $logger,
) {
}
/**
* Prepopulates applicant data from authenticated user's personal data.
*
* Fetches PersonalData from BPN API using the user's credentials and maps
* the data to the provided ParticipantDto. If the API call fails or returns
* incomplete data, the method logs the error and returns the unpopulated
* participant without throwing exceptions.
*
* @param User $user The authenticated user
* @param ParticipantDto $applicant The applicant DTO to prepopulate
*
* @return ParticipantDto The prepopulated participant (or unchanged if API fails)
*/
public function prefillApplicantFromUser(User $user, ParticipantDto $applicant): ParticipantDto
{
try {
// Decrypt user password for API authentication
$password = $this->crypt->decrypt($user->getPassword());
$email = $user->getEmail();
// Fetch personal data from API
$result = $this->apiClient->getPersonalData($email, $password);
// Handle API error response
if ($result instanceof Notification) {
$this->logger->warning('Failed to fetch personal data for prepopulation', [
'email' => $email,
'code' => $result->code,
'message' => $result->message,
]);
return $applicant;
}
// Create a temporary participant from personal data
$prepopulated = ParticipantDto::fromPersonalData($result);
// Copy personal data fields to the existing applicant
// Preserve booking-specific fields (roomId, services, etc.)
$applicant->addressId = $prepopulated->addressId;
$applicant->personId = $prepopulated->personId;
$applicant->firstName = $prepopulated->firstName;
$applicant->lastName = $prepopulated->lastName;
$applicant->title = $prepopulated->title;
$applicant->gender = $prepopulated->gender;
$applicant->nationality = $prepopulated->nationality;
$applicant->dateOfBirth = $prepopulated->dateOfBirth;
$applicant->email = $prepopulated->email;
$applicant->mobile = $prepopulated->mobile;
$applicant->address = $prepopulated->address;
$applicant->height = $prepopulated->height;
$applicant->weight = $prepopulated->weight;
$applicant->shoeSize = $prepopulated->shoeSize;
$applicant->remarksRoom = $prepopulated->remarksRoom;
$applicant->licensePlate = $prepopulated->licensePlate;
return $applicant;
} catch (\Exception $e) {
// Catch any unexpected exceptions (decryption failure, API errors, etc.)
$this->logger->error('Exception during applicant prepopulation', [
'error' => $e->getMessage(),
'email' => $user->getEmail(),
]);
return $applicant;
}
}
/**
* Determines whether the applicant should be prepopulated.
*
* Only prepopulates if the participant is fresh.
*/
public function shouldPrefillApplicant(ParticipantDto $applicant): bool
{
return null === $applicant->firstName || '' === $applicant->firstName;
}
/**
* Checks if the participant's last name triggers dummy data fill.
*
* Only matches in create mode to avoid accidental triggering during edits.
*/
public function isDummyDataFillRequested(ParticipantDto $participant, string $mode): bool
{
if (BookingDto::MODE_CREATE !== $mode) {
return false;
}
return self::TOKEN === $participant->lastName;
}
/**
* Fills the participant DTO with generated dummy personal data.
*/
public function fillDummyParticipant(ParticipantDto $participant, int $participantIndex): void
{
$participantNumber = $participantIndex + 1;
$now = CarbonImmutable::now();
$participant->firstName = sprintf('Vorname %d', $participantNumber);
$participant->lastName = sprintf('Muster %d %s', $participantNumber, $now->format('H:i'));
$participant->mobile = '0171/111111';
$participant->email = sprintf('teilnehmer.in%[email protected]', $participantNumber);
$participant->dateOfBirth = $now->subYears(20)->toImmutable();
$address = new Address();
$address->street = 'Musterstr. 123';
$address->postCode = '99999';
$address->city = 'MusterOrt';
$address->country = 'Deutschland';
$participant->address = $address;
}
}