You are here

public function WebformSubmissionConditionsValidator::buildForm in Webform 8.5

Same name and namespace in other branches
  1. 6.x src/WebformSubmissionConditionsValidator.php \Drupal\webform\WebformSubmissionConditionsValidator::buildForm()

Apply form #states to visible elements.

Parameters

array $form: An associative array containing the structure of the form.

\Drupal\Core\Form\FormStateInterface $form_state: The current state of the form.

Overrides WebformSubmissionConditionsValidatorInterface::buildForm

See also

\Drupal\webform\WebformSubmissionForm::buildForm

File

src/WebformSubmissionConditionsValidator.php, line 96

Class

WebformSubmissionConditionsValidator
Webform submission conditions (#states) validator.

Namespace

Drupal\webform

Code

public function buildForm(array &$form, FormStateInterface $form_state) {

  /** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
  $webform_submission = $form_state
    ->getFormObject()
    ->getEntity();

  // Get build/visible form elements.
  $visible_elements =& $this
    ->getBuildElements($form);

  // Loop through visible elements with #states.
  foreach ($visible_elements as &$element) {
    $states =& WebformElementHelper::getStates($element);

    // Store original #states in #_webform_states.
    $element['#_webform_states'] = $states;
    foreach ($states as $original_state => $conditions) {
      if (!is_array($conditions)) {
        continue;
      }

      // Process state/negate.
      list($state, $negate) = $this
        ->processState($original_state);

      // If hide/show we need to make sure that validation is not triggered.
      if (strpos($state, 'visible') === 0) {
        $element['#after_build'][] = [
          get_class($this),
          'elementAfterBuild',
        ];
      }
      $targets = $this
        ->getConditionTargetsVisibility($conditions, $visible_elements);

      // Determine if targets are visible or cross page.
      $all_targets_visible = array_sum($targets) === count($targets);
      $has_cross_page_targets = !$all_targets_visible && array_sum($targets);

      // Skip if evaluating conditions when all targets are visible.
      if ($all_targets_visible) {

        // Add .js-webform-states-hidden to element's that are not visible when
        // the form is rendered.
        if (strpos($state, 'visible') === 0 && !$this
          ->validateConditions($conditions, $webform_submission)) {
          $this
            ->addStatesHiddenToElement($element);
        }
        continue;
      }

      // Replace hidden cross page targets with hidden inputs.
      if ($has_cross_page_targets) {
        $cross_page_targets = array_filter($targets, function ($visible) {
          return $visible === FALSE;
        });
        $states[$original_state] = $this
          ->replaceCrossPageTargets($conditions, $webform_submission, $cross_page_targets, $form);
        continue;
      }
      $result = $this
        ->validateConditions($conditions, $webform_submission);

      // Skip invalid conditions.
      if ($result === NULL) {
        continue;
      }

      // Negate the result.
      $result = $negate ? !$result : $result;

      // Apply result to element state.
      switch ($state) {
        case 'required':
          $element['#required'] = $result;
          break;
        case 'readonly':

          // Set custom readonly attribute and class.
          // We can't use the custom #readonly property because it is
          // processed before cross page targets.
          // @see \Drupal\webform\Plugin\WebformElementBase::prepare
          if ($result) {
            $element['#attributes']['readonly'] = 'readonly';
            $element['#wrapper_attributes']['class'][] = 'webform-readonly';
          }
          break;
        case 'disabled':
          $element['#disabled'] = $result;
          break;
        case 'visible':
        case 'visible-slide':
          if (!$result) {

            // Visual hide the element.
            $this
              ->addStatesHiddenToElement($element);

            // Clear the default value.
            if (!isset($element['#states_clear']) || $element['#states_clear'] === TRUE) {
              unset($element['#default_value']);
            }
          }
          break;
        case 'collapsed':
          $element['#open'] = !$result;
          break;
        case 'checked':
          $element['#default_value'] = $result;
          break;
      }

      // Remove #states state/conditions.
      unset($states[$original_state]);
    }

    // Remove #states if all states have been applied.
    if (empty($states)) {
      unset($element['#states']);
    }
  }
}