feat: extract participant draft field applier
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
|
||||
/**
|
||||
* Applies participant-level draft payloads onto booking DTO participants.
|
||||
*/
|
||||
class BookingEditDraftParticipantApplier
|
||||
{
|
||||
public function apply(
|
||||
BookingDto $bookingDto,
|
||||
int $participantIndex,
|
||||
ParticipantDto $participant,
|
||||
array $data,
|
||||
): void {
|
||||
$canApplyPersonalDataDraft = $this->canApplyPersonalDataDraft($bookingDto, $participantIndex, $participant);
|
||||
|
||||
// Personal data
|
||||
if (true === $canApplyPersonalDataDraft && isset($data['personalData']) && true === is_array($data['personalData'])) {
|
||||
$this->applyPersonalData($participant, $data['personalData']);
|
||||
}
|
||||
|
||||
// Address
|
||||
if (true === $canApplyPersonalDataDraft && isset($data['address']) && true === is_array($data['address'])) {
|
||||
$this->applyAddressData($participant, $data['address']);
|
||||
}
|
||||
|
||||
// Body dimensions
|
||||
if (true === isset($data['bodyDimensions']) && true === is_array($data['bodyDimensions'])) {
|
||||
$this->applyBodyDimensions($participant, $data['bodyDimensions']);
|
||||
}
|
||||
|
||||
// Room assignment
|
||||
if (true === isset($data['roomAssignment']) && true === is_array($data['roomAssignment'])) {
|
||||
$this->applyRoomAssignment($participant, $data['roomAssignment']);
|
||||
}
|
||||
|
||||
// License plate
|
||||
if (true === array_key_exists('licensePlate', $data)) {
|
||||
$participant->licensePlate = $data['licensePlate'];
|
||||
}
|
||||
|
||||
// Vouchers
|
||||
if (true === isset($data['vouchers']) && true === is_array($data['vouchers'])) {
|
||||
$this->applyVoucherCodes($participant, $data['vouchers']);
|
||||
}
|
||||
}
|
||||
|
||||
private function canApplyPersonalDataDraft(BookingDto $bookingDto, int $participantIndex, ParticipantDto $participant): bool
|
||||
{
|
||||
if (true === $bookingDto->isInternalAgencyBooking()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (0 === $participantIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $participant->mutable;
|
||||
}
|
||||
|
||||
private function applyPersonalData(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('firstName', $data)) {
|
||||
$participant->firstName = $data['firstName'];
|
||||
}
|
||||
if (true === array_key_exists('lastName', $data)) {
|
||||
$participant->lastName = $data['lastName'];
|
||||
}
|
||||
if (true === array_key_exists('dateOfBirth', $data) && null !== $data['dateOfBirth']) {
|
||||
$participant->dateOfBirth = new \DateTimeImmutable($data['dateOfBirth']);
|
||||
}
|
||||
if (true === array_key_exists('email', $data)) {
|
||||
$participant->email = $data['email'];
|
||||
}
|
||||
if (true === array_key_exists('mobile', $data)) {
|
||||
$participant->mobile = $data['mobile'];
|
||||
}
|
||||
if (true === array_key_exists('gender', $data)) {
|
||||
$participant->gender = $data['gender'];
|
||||
}
|
||||
if (true === array_key_exists('nationality', $data) && '' !== $data['nationality'] && null !== $data['nationality']) {
|
||||
$participant->nationality = $data['nationality'];
|
||||
}
|
||||
}
|
||||
|
||||
private function applyAddressData(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
$hasAddressData = null !== ($data['street'] ?? null)
|
||||
|| null !== ($data['postCode'] ?? null)
|
||||
|| null !== ($data['city'] ?? null)
|
||||
|| null !== ($data['country'] ?? null);
|
||||
|
||||
if (false === $hasAddressData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $participant->address) {
|
||||
$participant->address = new \App\BusProNet\Model\Address();
|
||||
}
|
||||
|
||||
if (true === array_key_exists('street', $data)) {
|
||||
$participant->address->street = $data['street'];
|
||||
}
|
||||
if (true === array_key_exists('postCode', $data)) {
|
||||
$participant->address->postCode = $data['postCode'];
|
||||
}
|
||||
if (true === array_key_exists('city', $data)) {
|
||||
$participant->address->city = $data['city'];
|
||||
}
|
||||
if (true === array_key_exists('country', $data)) {
|
||||
$participant->address->country = $data['country'];
|
||||
}
|
||||
}
|
||||
|
||||
private function applyBodyDimensions(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('height', $data)) {
|
||||
$participant->height = $data['height'];
|
||||
}
|
||||
if (true === array_key_exists('weight', $data)) {
|
||||
$participant->weight = $data['weight'];
|
||||
}
|
||||
if (true === array_key_exists('shoeSize', $data)) {
|
||||
$participant->shoeSize = $data['shoeSize'];
|
||||
}
|
||||
}
|
||||
|
||||
private function applyRoomAssignment(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('assignedRoomId', $data)) {
|
||||
$participant->assignedRoomId = $data['assignedRoomId'];
|
||||
}
|
||||
if (true === array_key_exists('remarksRoom', $data)) {
|
||||
$participant->remarksRoom = $data['remarksRoom'];
|
||||
}
|
||||
}
|
||||
|
||||
private function applyVoucherCodes(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('purchaseVoucherCode', $data)) {
|
||||
$participant->purchaseVoucherCode = $data['purchaseVoucherCode'];
|
||||
}
|
||||
if (true === array_key_exists('promoVoucherCode', $data)) {
|
||||
$participant->promoVoucherCode = $data['promoVoucherCode'];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\BusProNet\Model\Address;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\Entity\BookingEditDraft;
|
||||
use App\Entity\User;
|
||||
@@ -29,6 +28,7 @@ class BookingEditDraftService
|
||||
private readonly BookingEditDraftRepository $draftRepository,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly BookingFingerprintService $fingerprintService,
|
||||
private readonly BookingEditDraftParticipantApplier $participantApplier,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
@@ -148,7 +148,16 @@ class BookingEditDraftService
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->applyParticipantData($dto, $index, $participantData, $travel);
|
||||
$this->participantApplier->apply(
|
||||
$dto,
|
||||
$index,
|
||||
$dto->participants[$index],
|
||||
$participantData,
|
||||
);
|
||||
|
||||
if (isset($participantData['services']) && true === is_array($participantData['services'])) {
|
||||
$this->applyServiceSelections($dto->participants[$index], $participantData['services'], $travel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,160 +197,6 @@ class BookingEditDraftService
|
||||
$dto->bankAccount->accountHolder = $accountHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies participant data from draft to a ParticipantDto.
|
||||
*/
|
||||
private function applyParticipantData(BookingDto $bookingDto, int $participantIndex, array $data, Travel $travel): void
|
||||
{
|
||||
$participant = $bookingDto->participants[$participantIndex];
|
||||
$canApplyPersonalDataDraft = $this->canApplyPersonalDataDraft($bookingDto, $participantIndex, $participant);
|
||||
|
||||
// Personal data
|
||||
if (true === $canApplyPersonalDataDraft && isset($data['personalData']) && true === is_array($data['personalData'])) {
|
||||
$this->applyPersonalData($participant, $data['personalData']);
|
||||
}
|
||||
|
||||
// Address
|
||||
if (true === $canApplyPersonalDataDraft && isset($data['address']) && true === is_array($data['address'])) {
|
||||
$this->applyAddressData($participant, $data['address']);
|
||||
}
|
||||
|
||||
// Body dimensions
|
||||
if (true === isset($data['bodyDimensions']) && true === is_array($data['bodyDimensions'])) {
|
||||
$this->applyBodyDimensions($participant, $data['bodyDimensions']);
|
||||
}
|
||||
|
||||
// Room assignment
|
||||
if (true === isset($data['roomAssignment']) && true === is_array($data['roomAssignment'])) {
|
||||
$this->applyRoomAssignment($participant, $data['roomAssignment']);
|
||||
}
|
||||
|
||||
// License plate
|
||||
if (true === array_key_exists('licensePlate', $data)) {
|
||||
$participant->licensePlate = $data['licensePlate'];
|
||||
}
|
||||
|
||||
// Services
|
||||
if (true === isset($data['services']) && true === is_array($data['services'])) {
|
||||
$this->applyServiceSelections($participant, $data['services'], $travel);
|
||||
}
|
||||
|
||||
// Vouchers
|
||||
if (true === isset($data['vouchers']) && true === is_array($data['vouchers'])) {
|
||||
$this->applyVoucherCodes($participant, $data['vouchers']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether personal/address draft data may be applied.
|
||||
*
|
||||
* Edit rules mirror UI mutability behavior:
|
||||
* - Internal agency bookings may always update participant personal data
|
||||
* - Non-internal agency: first participant is always read-only in edit flow
|
||||
* - Other participants require participant-level mutability from BPN
|
||||
*/
|
||||
private function canApplyPersonalDataDraft(BookingDto $bookingDto, int $participantIndex, ParticipantDto $participant): bool
|
||||
{
|
||||
if (true === $bookingDto->isInternalAgencyBooking()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (0 === $participantIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $participant->mutable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies personal data fields to participant.
|
||||
*/
|
||||
private function applyPersonalData(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('firstName', $data)) {
|
||||
$participant->firstName = $data['firstName'];
|
||||
}
|
||||
if (true === array_key_exists('lastName', $data)) {
|
||||
$participant->lastName = $data['lastName'];
|
||||
}
|
||||
if (true === array_key_exists('dateOfBirth', $data) && null !== $data['dateOfBirth']) {
|
||||
$participant->dateOfBirth = new \DateTimeImmutable($data['dateOfBirth']);
|
||||
}
|
||||
if (true === array_key_exists('email', $data)) {
|
||||
$participant->email = $data['email'];
|
||||
}
|
||||
if (true === array_key_exists('mobile', $data)) {
|
||||
$participant->mobile = $data['mobile'];
|
||||
}
|
||||
if (true === array_key_exists('gender', $data)) {
|
||||
$participant->gender = $data['gender'];
|
||||
}
|
||||
if (true === array_key_exists('nationality', $data) && '' !== $data['nationality'] && null !== $data['nationality']) {
|
||||
$participant->nationality = $data['nationality'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies address data to participant.
|
||||
*/
|
||||
private function applyAddressData(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
$hasAddressData = null !== ($data['street'] ?? null)
|
||||
|| null !== ($data['postCode'] ?? null)
|
||||
|| null !== ($data['city'] ?? null)
|
||||
|| null !== ($data['country'] ?? null);
|
||||
|
||||
if (false === $hasAddressData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $participant->address) {
|
||||
$participant->address = new Address();
|
||||
}
|
||||
|
||||
if (true === array_key_exists('street', $data)) {
|
||||
$participant->address->street = $data['street'];
|
||||
}
|
||||
if (true === array_key_exists('postCode', $data)) {
|
||||
$participant->address->postCode = $data['postCode'];
|
||||
}
|
||||
if (true === array_key_exists('city', $data)) {
|
||||
$participant->address->city = $data['city'];
|
||||
}
|
||||
if (true === array_key_exists('country', $data)) {
|
||||
$participant->address->country = $data['country'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies body dimension data to participant.
|
||||
*/
|
||||
private function applyBodyDimensions(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('height', $data)) {
|
||||
$participant->height = $data['height'];
|
||||
}
|
||||
if (true === array_key_exists('weight', $data)) {
|
||||
$participant->weight = $data['weight'];
|
||||
}
|
||||
if (true === array_key_exists('shoeSize', $data)) {
|
||||
$participant->shoeSize = $data['shoeSize'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies room assignment data to participant.
|
||||
*/
|
||||
private function applyRoomAssignment(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('assignedRoomId', $data)) {
|
||||
$participant->assignedRoomId = $data['assignedRoomId'];
|
||||
}
|
||||
if (true === array_key_exists('remarksRoom', $data)) {
|
||||
$participant->remarksRoom = $data['remarksRoom'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies service selections to participant, resolving IDs against Travel data.
|
||||
*
|
||||
@@ -463,95 +318,6 @@ class BookingEditDraftService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies voucher codes to participant.
|
||||
*/
|
||||
private function applyVoucherCodes(ParticipantDto $participant, array $data): void
|
||||
{
|
||||
if (true === array_key_exists('purchaseVoucherCode', $data)) {
|
||||
$participant->purchaseVoucherCode = $data['purchaseVoucherCode'];
|
||||
}
|
||||
if (true === array_key_exists('promoVoucherCode', $data)) {
|
||||
$participant->promoVoucherCode = $data['promoVoucherCode'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a single service ID to a Service object from the available services.
|
||||
*
|
||||
* @param int|null $serviceId The service ID to resolve
|
||||
* @param array $services Available services indexed by ID
|
||||
*
|
||||
* @return object|null The service object if found, null otherwise
|
||||
*/
|
||||
private function resolveService(?int $serviceId, array $services): ?object
|
||||
{
|
||||
if (null === $serviceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $services[$serviceId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an array of service IDs to Service objects.
|
||||
*
|
||||
* @param array $serviceIds Array of service IDs
|
||||
* @param array $services Available services indexed by ID
|
||||
*
|
||||
* @return array Array of resolved Service objects (missing services are skipped)
|
||||
*/
|
||||
private function resolveServiceArray(array $serviceIds, array $services): array
|
||||
{
|
||||
$resolved = [];
|
||||
$addedIds = [];
|
||||
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
if (isset($services[$serviceId]) && false === isset($addedIds[$serviceId])) {
|
||||
$resolved[] = $services[$serviceId];
|
||||
$addedIds[$serviceId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a pickup ID to a Pickup object.
|
||||
*/
|
||||
private function resolvePickup(?int $pickupId, Travel $travel): ?object
|
||||
{
|
||||
if (null === $pickupId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travel->pickups[$pickupId] ?? $travel->dropOffs[$pickupId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a drop-off ID to a Pickup object from the travel drop-offs list.
|
||||
*/
|
||||
private function resolveDropOff(?int $dropOffId, Travel $travel): ?object
|
||||
{
|
||||
if (null === $dropOffId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travel->dropOffs[$dropOffId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an insurance ID to an Insurance object.
|
||||
*/
|
||||
private function resolveInsurance(?string $insuranceId, Travel $travel): ?object
|
||||
{
|
||||
if (null === $insuranceId || '' === $insuranceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travel->insurances[$insuranceId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preserves mandatory services from API data when applying draft.
|
||||
*
|
||||
@@ -600,4 +366,64 @@ class BookingEditDraftService
|
||||
|
||||
return $draftServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, object> $services
|
||||
*/
|
||||
private function resolveService(?int $serviceId, array $services): ?object
|
||||
{
|
||||
if (null === $serviceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $services[$serviceId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, int> $serviceIds
|
||||
* @param array<int, object> $services
|
||||
*
|
||||
* @return array<int, object>
|
||||
*/
|
||||
private function resolveServiceArray(array $serviceIds, array $services): array
|
||||
{
|
||||
$resolved = [];
|
||||
$addedIds = [];
|
||||
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
if (isset($services[$serviceId]) && false === isset($addedIds[$serviceId])) {
|
||||
$resolved[] = $services[$serviceId];
|
||||
$addedIds[$serviceId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $resolved;
|
||||
}
|
||||
|
||||
private function resolvePickup(?int $pickupId, Travel $travel): ?object
|
||||
{
|
||||
if (null === $pickupId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travel->pickups[$pickupId] ?? $travel->dropOffs[$pickupId] ?? null;
|
||||
}
|
||||
|
||||
private function resolveDropOff(?int $dropOffId, Travel $travel): ?object
|
||||
{
|
||||
if (null === $dropOffId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travel->dropOffs[$dropOffId] ?? null;
|
||||
}
|
||||
|
||||
private function resolveInsurance(?string $insuranceId, Travel $travel): ?object
|
||||
{
|
||||
if (null === $insuranceId || '' === $insuranceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $travel->insurances[$insuranceId] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user