You are here

public static function WebformLikert::processWebformLikert in Webform 6.x

Same name and namespace in other branches
  1. 8.5 src/Element/WebformLikert.php \Drupal\webform\Element\WebformLikert::processWebformLikert()

Processes a likert scale webform element.

File

src/Element/WebformLikert.php, line 50

Class

WebformLikert
Provides a webform element for a likert scale.

Namespace

Drupal\webform\Element

Code

public static function processWebformLikert(&$element, FormStateInterface $form_state, &$complete_form) {

  // Get answer with optional N/A.
  static::processWebformLikertAnswers($element);

  // Remove 'for' from element's label.
  $element['#label_attributes']['webform-remove-for-attribute'] = TRUE;

  // Process answers.
  $answers = [];
  foreach ($element['#answers'] as $answer_key => $answer) {
    $answer = (string) $answer;
    if (!WebformOptionsHelper::hasOptionDescription($answer)) {
      $answer_description_property_name = NULL;
      $answer_title = $answer;
      $answer_description = '';
    }
    else {
      $answer_description_property_name = $element['#answers_description_display'] === 'help' ? 'help' : 'description';
      list($answer_title, $answer_description) = WebformOptionsHelper::splitOption($answer);
    }
    $answers[$answer_key] = [
      'description_property_name' => $answer_description_property_name,
      'title' => $answer_title,
      'description' => $answer_description,
    ];
  }

  // Build header.
  $header = [
    'likert_question' => [
      'data' => [
        'title' => WebformAccessibilityHelper::buildVisuallyHidden(t('Questions')),
      ],
    ],
  ];
  foreach ($answers as $answer_key => $answer) {
    $header[$answer_key] = [
      'data' => [
        'title' => [
          '#markup' => $answer['title'],
        ],
      ],
    ];
    switch ($answer['description_property_name']) {
      case 'help':
        $header[$answer_key]['data']['help'] = [
          '#type' => 'webform_help',
          '#help' => $answer['description'],
          '#help_title' => $answer['title'],
        ];
        break;
      case 'description':
        $header[$answer_key]['data']['description'] = [
          '#type' => 'container',
          '#markup' => $answer['description'],
          '#attributes' => [
            'class' => [
              'description',
            ],
          ],
        ];
        break;
    }
  }

  // Randomize questions.
  if (!empty($element['#questions_randomize'])) {
    $element['#questions'] = WebformElementHelper::randomize($element['#questions']);
  }

  // Build rows.
  $rows = [];
  foreach ($element['#questions'] as $question_key => $question) {
    $question = (string) $question;
    if (!WebformOptionsHelper::hasOptionDescription($question)) {
      $question_description_property_name = NULL;
      $question_title = $question;
      $question_description = '';
    }
    else {
      $question_description_property_name = $element['#questions_description_display'] === 'help' ? '#help' : '#description';
      list($question_title, $question_description) = WebformOptionsHelper::splitOption($question);
    }
    $value = isset($element['#value'][$question_key]) ? $element['#value'][$question_key] : NULL;

    // Get question id.
    // @see \Drupal\Core\Form\FormBuilder::doBuildForm
    $question_id = 'edit-' . implode('-', array_merge($element['#parents'], [
      'table',
      $question_key,
      'likert_question',
    ]));
    $question_id = Html::getUniqueId($question_id);
    $row = [];

    // Must format the label as an item so that inline webform errors will be
    // displayed.
    $row['likert_question'] = [
      '#type' => 'item',
      '#title' => $question_title,
      '#id' => $question_id,
      // Must include an empty <span> so that the item's value is
      // not required.
      '#value' => '<span></span>',
      '#webform_element' => TRUE,
      '#required' => $element['#required'],
      '#label_attributes' => [
        'webform-remove-for-attribute' => TRUE,
      ],
    ];
    if ($question_description_property_name) {
      $row['likert_question'][$question_description_property_name] = $question_description;
    }
    foreach ($answers as $answer_key => $answer) {
      $answer_attributes = [
        'aria-labelledby' => $question_id,
      ];

      // Add required attributes to input without setting the <label>
      // to required.
      if ($element['#required']) {
        $answer_attributes['required'] = 'required';
        $answer_attributes['aria-required'] = 'true';
      }
      $row[$answer_key] = [
        '#parents' => [
          $element['#name'],
          $question_key,
        ],
        '#type' => 'radio',
        // Must cast values as strings to prevent NULL and empty strings.
        // from being evaluated as 0.
        '#return_value' => (string) $answer_key,
        // Set value to FALSE to prevent '0' or '' from being checked when
        // value is NULL.
        // @see \Drupal\Core\Render\Element\Radio::preRenderRadio
        '#value' => $value === NULL ? FALSE : (string) $value,
        '#attributes' => $answer_attributes,
      ];

      // Wrap title in span.webform-likert-label.visually-hidden
      // so that it can hidden but accessible to screen readers
      // when Likert is displayed in grid on desktop.
      // Wrap help and description in
      // span.webform-likert-(help|description).hidden to block screen
      // readers except on mobile.
      // @see webform.element.likert.css
      $row[$answer_key]['#title_display'] = 'after';
      switch ($answer['description_property_name']) {
        case 'help':
          $build = [
            'title' => [
              '#markup' => $answer['title'],
            ],
            'help' => [
              '#type' => 'webform_help',
              '#help' => $answer['description'],
              '#help_title' => $answer['title'],
              '#prefix' => '<span class="webform-likert-help hidden">',
              '#suffix' => '</span>',
            ],
            '#prefix' => '<span class="webform-likert-label visually-hidden">',
            '#suffix' => '</span>',
          ];
          $row[$answer_key]['#title'] = \Drupal::service('renderer')
            ->render($build);
          break;
        case 'description':
          $row[$answer_key] += [
            '#title' => new FormattableMarkup('<span class="webform-likert-label visually-hidden">@title</span>', [
              '@title' => $answer['title'],
            ]),
            '#description' => new FormattableMarkup('<span class="webform-likert-description hidden">@description</span>', [
              '@description' => $answer['description'],
            ]),
          ];
          break;
        default:
          $row[$answer_key] += [
            '#title' => new FormattableMarkup('<span class="webform-likert-label visually-hidden">@title</span>', [
              '@title' => $answer['title'],
            ]),
          ];
      }
    }
    $rows[$question_key] = $row;
  }
  $element['table'] = [
    '#type' => 'table',
    '#header' => $header,
    '#sticky' => $element['#sticky'],
    '#attributes' => [
      'class' => [
        'webform-likert-table',
      ],
      'data-likert-answers-count' => count($element['#answers']),
    ],
    '#prefix' => '<div class="webform-likert-table-wrapper">',
    '#suffix' => '</div>',
  ] + $rows;

  // Build table element with selected properties.
  $properties = [
    '#states',
    '#sticky',
  ];
  $element['table'] += array_intersect_key($element, array_combine($properties, $properties));
  $element['#tree'] = TRUE;

  // Add after_build callback.
  $element['#after_build'][] = [
    get_called_class(),
    'afterBuild',
  ];

  // Add validate callback.
  $element += [
    '#element_validate' => [],
  ];
  array_unshift($element['#element_validate'], [
    get_called_class(),
    'validateWebformLikert',
  ]);
  $element['#attached']['library'][] = 'webform/webform.element.likert';
  return $element;
}