292 lines
12 KiB
PHP
292 lines
12 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Form\Service;
|
|
|
|
use App\BusProNet\Utility\DirectionMapper;
|
|
use App\Form\Service\Abstract\AbstractFieldStateProvider;
|
|
use App\Form\Service\Condition\ApplicantCondition;
|
|
use App\Form\Service\Condition\AuthenticatedUserPersonalDataCondition;
|
|
use App\Form\Service\Condition\BookingEligibilityCondition;
|
|
use App\Form\Service\Condition\BulkInsuranceBookingCondition;
|
|
use App\Form\Service\Condition\CompositeCondition;
|
|
use App\Form\Service\Condition\DateOfBirthProvidedCondition;
|
|
use App\Form\Service\Condition\FieldValueCondition;
|
|
use App\Form\Service\Condition\RentalSelectionCondition;
|
|
use App\Form\Service\Condition\RoomSelectionCondition;
|
|
use App\Form\Service\Condition\ServiceSubTypeCondition;
|
|
use App\Form\Service\Condition\SingleRoomTypeCondition;
|
|
use App\Form\Service\Condition\SkiPassSelectionCondition;
|
|
use App\Service\ParticipantEligibilityService;
|
|
|
|
/**
|
|
* Field state provider for the booking create workflow.
|
|
*
|
|
* This service calculates dynamic field states (readonly, disabled, static_text, etc.)
|
|
* for participant fields in the create flow. It extends the common field
|
|
* state functionality provided by AbstractFieldStateProvider.
|
|
*
|
|
* Current field state conditions:
|
|
* - Personal data fields render as static text for authenticated users (prevents duplicate BPN records)
|
|
* - Body dimension fields are hidden unless rental services are selected
|
|
* - Age-dependent service fields are hidden until birth date is provided
|
|
* - Transportation pickup fields are hidden by default, shown only when transportation type is BUS
|
|
* - Parking field is hidden by default, shown only when outbound transportation is PKW
|
|
* - All service fields are hidden for ineligible participants (no skipasses available for their age)
|
|
*/
|
|
class CreateFieldStateProvider extends AbstractFieldStateProvider
|
|
{
|
|
public function __construct(
|
|
private readonly ParticipantEligibilityService $participantEligibilityService,
|
|
) {
|
|
parent::__construct();
|
|
}
|
|
|
|
/**
|
|
* Registers field state conditions for the create workflow.
|
|
*
|
|
* This method defines the conditional logic for field states in the
|
|
* booking creation process. Each field can have multiple state conditions
|
|
* (readonly, disabled, hidden, required) that are evaluated independently.
|
|
*
|
|
* Adding new field state conditions:
|
|
* To add conditional state logic for a field, register conditions here:
|
|
*
|
|
* $this->fieldStateConditions['fieldName'] = [
|
|
* 'readonly' => new SomeCondition(),
|
|
* 'disabled' => CompositeCondition::and(
|
|
* new AgeRangeCondition(null, 17),
|
|
* FieldValueCondition::equals('someField', 'someValue')
|
|
* ),
|
|
* ];
|
|
*
|
|
* Condition Types:
|
|
* - 'readonly': Field is visible but not editable
|
|
* - 'disabled': Field interaction is disabled
|
|
* - 'required': Field becomes mandatory
|
|
* - 'hidden': Field is not displayed
|
|
*/
|
|
protected function registerFieldStateConditions(): void
|
|
{
|
|
// Booking eligibility condition - hide all service fields when no skipasses available for participant's age
|
|
$bookingEligibilityCondition = new BookingEligibilityCondition($this->participantEligibilityService);
|
|
|
|
$rentalCondition = new RentalSelectionCondition();
|
|
$skiPassCondition = new SkiPassSelectionCondition();
|
|
|
|
// Authenticated user personal data protection
|
|
// Render personal data fields as static text for participants linked to BPN accounts (prevents duplicate records)
|
|
$authenticatedUserCondition = new AuthenticatedUserPersonalDataCondition();
|
|
|
|
$this->fieldStateConditions['firstName'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['lastName'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['gender'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['nationality'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['dateOfBirth'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['email'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
// Mobile field: static text for authenticated users, required for guest applicants
|
|
$this->fieldStateConditions['mobile'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
'required' => new ApplicantCondition(),
|
|
];
|
|
|
|
// Address subfields - must render as static text to prevent creating duplicate BPN records
|
|
$this->fieldStateConditions['address.street'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['address.postCode'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['address.city'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['address.country'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
$this->fieldStateConditions['address.district'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
];
|
|
|
|
// Note: Body dimensions (height, weight, shoeSize) are NOT hidden for authenticated users
|
|
// These are preferences/measurements that can be updated without creating duplicate records
|
|
|
|
// Hide body dimensions section unless rental services are selected
|
|
$this->fieldStateConditions['bodyDimensions'] = [
|
|
'hidden' => CompositeCondition::not($rentalCondition),
|
|
];
|
|
|
|
// Hide age-dependent fields when no date of birth is provided
|
|
$dateOfBirthProvidedCondition = new DateOfBirthProvidedCondition();
|
|
|
|
// Age-dependent service fields are hidden until birth date is provided OR when participant is ineligible
|
|
$this->fieldStateConditions['courses'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
$this->fieldStateConditions['additionalServices'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
// Skipass field - hidden when participant is ineligible OR when no date of birth
|
|
$this->fieldStateConditions['skiPass'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
// Show rentals only when both date of birth is provided AND skipass is selected AND participant is eligible
|
|
$this->fieldStateConditions['rentals'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
CompositeCondition::not($skiPassCondition),
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
$this->fieldStateConditions['board'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
// Bulk insurance booking conditions
|
|
$bulkInsuranceBookingCondition = new BulkInsuranceBookingCondition();
|
|
|
|
// Show bulk insurance booking checkbox ONLY for applicant (index 0) and when insurance field is visible
|
|
$this->fieldStateConditions['bulkInsuranceBooking'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition), // Hide until date of birth provided
|
|
CompositeCondition::not(new ApplicantCondition()) // Hide for non-applicants
|
|
),
|
|
];
|
|
|
|
// Hide insurance field until date of birth is provided OR when bulk insurance booking is active OR when participant is ineligible
|
|
$this->fieldStateConditions['insurance'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
$bulkInsuranceBookingCondition,
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
// Room-specific field conditions
|
|
$sharedRoomCondition = new RoomSelectionCondition(['mbz']);
|
|
|
|
// Show remarks room field only when room with code 'mbz' is selected
|
|
$this->fieldStateConditions['remarksRoom'] = [
|
|
'hidden' => CompositeCondition::not($sharedRoomCondition),
|
|
];
|
|
|
|
// Transportation-related field conditions
|
|
// All transportation fields require date of birth and participant eligibility
|
|
|
|
// Outbound transportation - hidden until date of birth provided AND participant is eligible
|
|
$this->fieldStateConditions['transportationOutbound'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
// Inbound transportation - hidden until date of birth provided AND participant is eligible
|
|
$this->fieldStateConditions['transportationInbound'] = [
|
|
'hidden' => CompositeCondition::or(
|
|
CompositeCondition::not($dateOfBirthProvidedCondition),
|
|
$bookingEligibilityCondition
|
|
),
|
|
];
|
|
|
|
// Show pickup only when either outbound or inbound transportation is BUS (hidden by default)
|
|
$this->fieldStateConditions['pickup'] = [
|
|
'hidden' => CompositeCondition::not(
|
|
CompositeCondition::or(
|
|
ServiceSubTypeCondition::equals('transportationOutbound', DirectionMapper::SUBTYPE_BUS_API),
|
|
ServiceSubTypeCondition::equals('transportationInbound', DirectionMapper::SUBTYPE_BUS_API)
|
|
)
|
|
),
|
|
];
|
|
|
|
// Show parking only when outbound transportation is PKW (hidden by default)
|
|
// Parking is offered at holiday destination for those arriving by car
|
|
$this->fieldStateConditions['parking'] = [
|
|
'hidden' => CompositeCondition::not(
|
|
ServiceSubTypeCondition::equals('transportationOutbound', DirectionMapper::SUBTYPE_CAR_API)
|
|
),
|
|
];
|
|
|
|
// Show rental insurance only when rental services are selected (hidden by default)
|
|
$this->fieldStateConditions['rentalInsurance'] = [
|
|
'hidden' => CompositeCondition::not($rentalCondition),
|
|
];
|
|
|
|
// Show license plate only when parking is selected (hidden by default)
|
|
$this->fieldStateConditions['licensePlate'] = [
|
|
'hidden' => FieldValueCondition::equals('parking', false),
|
|
];
|
|
|
|
// Make address field required for applicant (participant index 0)
|
|
// Also render as static text for authenticated users to prevent duplicate BPN records
|
|
$this->fieldStateConditions['address'] = [
|
|
'static_text' => $authenticatedUserCondition,
|
|
'required' => new ApplicantCondition(),
|
|
];
|
|
|
|
// Render assignedRoomId field as static text when only one room type is selected (auto-assigned by RoomAssignmentService)
|
|
$this->fieldStateConditions['assignedRoomId'] = [
|
|
'static_text' => new SingleRoomTypeCondition(),
|
|
];
|
|
|
|
// Example field state conditions would be registered here
|
|
// For demonstration purposes, here are some example patterns:
|
|
|
|
// Example 1: Make assignedRoomId readonly for participants under 18
|
|
// $this->fieldStateConditions['assignedRoomId'] = [
|
|
// 'readonly' => new AgeRangeCondition(null, 17),
|
|
// ];
|
|
|
|
// Example 2: Disable service selection if no room is assigned
|
|
// $this->fieldStateConditions['serviceSelection'] = [
|
|
// 'disabled' => FieldValueCondition::isEmpty('assignedRoomId'),
|
|
// ];
|
|
|
|
// Example 3: Complex condition with multiple criteria
|
|
// $this->fieldStateConditions['advancedOptions'] = [
|
|
// 'hidden' => CompositeCondition::or(
|
|
// new AgeRangeCondition(null, 15),
|
|
// FieldValueCondition::equals('userType', 'basic')
|
|
// ),
|
|
// ];
|
|
}
|
|
}
|