> Field state conditions indexed by field name and state type */ protected array $fieldStateConditions = []; public function __construct() { $this->registerFieldStateConditions(); } /** * Determines whether a field should be included in the form at all. * * Fields with 'hidden' state conditions should not be added to the form * rather than being hidden with CSS. This method evaluates the hidden * condition independently to allow early field exclusion. * * @param string $fieldName The name of the field to evaluate * @param BookingDto $bookingDto The current booking data for context (create or edit) * @param int $participantIndex The index of the participant being evaluated * @param array $formData Current form data for condition evaluation * * @return bool True if the field should be included in the form, false if it should be excluded */ public function shouldIncludeField(string $fieldName, BookingDto $bookingDto, int $participantIndex, array $formData = []): bool { if (false === isset($this->fieldStateConditions[$fieldName]['hidden'])) { return true; // No hidden condition means field should be included } $hiddenCondition = $this->fieldStateConditions[$fieldName]['hidden']; return !$hiddenCondition->evaluate($bookingDto, $participantIndex, $formData); } /** * Calculates the dynamic state for a specified field. * * Evaluates all configured conditions for a field and returns the appropriate * state modifications. State conditions are organized by state type (readonly, * disabled, etc.) and evaluated independently. * * Note: This method no longer handles 'hidden' state as fields should be * excluded from the form entirely rather than hidden with CSS. * * @param string $fieldName The name of the field to evaluate * @param BookingDto $bookingDto The current booking data for context (create or edit) * @param int $participantIndex The index of the participant being evaluated * @param array $formData Current form data for condition evaluation * * @return array Symfony form field options for state modifications */ public function getFieldState(string $fieldName, BookingDto $bookingDto, int $participantIndex, array $formData = []): array { if (false === isset($this->fieldStateConditions[$fieldName])) { return []; } $stateModifications = []; $attributes = []; foreach ($this->fieldStateConditions[$fieldName] as $stateType => $condition) { if ($condition->evaluate($bookingDto, $participantIndex, $formData)) { switch ($stateType) { case 'readonly': $attributes['readonly'] = true; break; case 'disabled': $stateModifications['disabled'] = true; break; case 'required': $stateModifications['required'] = true; break; } } } if (false === empty($attributes)) { $stateModifications['attr'] = $attributes; } return $stateModifications; } /** * Checks whether a field has state conditions configured. * * @param string $fieldName The name of the field to check * * @return bool True if the field has state conditions configured */ public function hasStateConditions(string $fieldName): bool { return isset($this->fieldStateConditions[$fieldName]) && !empty($this->fieldStateConditions[$fieldName]); } /** * Returns field names that trigger state re-evaluation for a given field. * * @param string $fieldName The name of the field to get dependencies for * * @return string[] Array of field names that affect the specified field's state */ public function getFieldStateDependencies(string $fieldName): array { if (!isset($this->fieldStateConditions[$fieldName])) { return []; } $dependencies = []; foreach ($this->fieldStateConditions[$fieldName] as $condition) { $dependencies = array_merge($dependencies, $condition->getDependentFields()); } return array_unique($dependencies); } /** * Calculates field states for all configured fields at once. * * @param BookingDto $bookingDto The current booking data for context (create or edit) * @param int $participantIndex The index of the participant being evaluated * @param array $formData Current form data for condition evaluation * * @return array> Field states indexed by field name */ public function getAllFieldStates(BookingDto $bookingDto, int $participantIndex, array $formData = []): array { $allStates = []; foreach (array_keys($this->fieldStateConditions) as $fieldName) { $fieldState = $this->getFieldState($fieldName, $bookingDto, $participantIndex, $formData); if (!empty($fieldState)) { $allStates[$fieldName] = $fieldState; } } return $allStates; } /** * Registers field state conditions during service initialization. * * This method must be implemented by concrete classes to define their * specific field state conditions. */ abstract protected function registerFieldStateConditions(): void; }