You are here

protected function ModuleBuilderComponentFormBase::elementCompound in Module Builder 7.2

Set form element properties specific to compound component properties.

Parameters

&$element: The form element for the component property.

FormStateInterface $form_state: The form state.

$property_info: The info array for the component property.

$form_default_value: The default value for the form element.

Return value

string The handling type to be applied to this element's value on submit.

File

includes/module_builder.form.inc, line 393

Class

ModuleBuilderComponentFormBase
Backport of ComponentFormBase from 8.x-3.x version.

Code

protected function elementCompound(&$element, FormStateInterface $form_state, $property_info, $form_default_value) {

  // A compound property shows a fieldset element, for which we recurse and
  // show another component.
  // D7: use fieldset instead of details element.
  $element['#type'] = 'fieldset';
  $element['#collapsed'] = FALSE;

  // Figure out how many items to show.
  // If we're reloading the form in response to the 'add more' button, then
  // form storage dictates the item count.
  // If there's nothing set in form storage yet, it's the first time we're
  // here and the number of items in the entity tells us how many items to
  // show in the form.
  // Finally, if that's empty, then show no items, just a button to add one.
  $item_count = static::getCompoundPropertyItemCount($form_state, $element['#mb_value_address']);
  if (is_null($item_count)) {
    $item_count = count($form_default_value);
    static::setCompoundPropertyItemCount($form_state, $element['#mb_value_address'], $item_count);
  }
  if (empty($item_count)) {
    $item_count = 0;
    static::setCompoundPropertyItemCount($form_state, $element['#mb_value_address'], $item_count);
  }

  // Property cardinality overrides anything else.
  if (isset($property_info['cardinality'])) {
    $item_count = min($item_count, $property_info['cardinality']);
    if ($item_count == $property_info['cardinality']) {

      // We're at the maximum item count.
      $add_more = FALSE;
    }
    else {

      // We're not yet at the cardinality: we can add more.
      $add_more = TRUE;
    }
  }
  else {

    // Unlimited cardinality: can always add more.
    $add_more = TRUE;
  }

  // Set up a wrapper for AJAX.
  $wrapper_id = Html::getUniqueId(implode('-', $element['#mb_value_address']) . '-add-more-wrapper');

  // TODO - use   '#type' => 'container',?
  $element['#prefix'] = '<div id="' . $wrapper_id . '">';
  $element['#suffix'] = '</div>';

  // Show the items in a table. This is single-column, with all child
  // properties in the one cell, but we just want the striping for visual
  // clarity.
  // D7: this won't work, but theming a table inside a form in D7 is just too
  // much faff. TODO: add borders or something?
  $element['table'] = array(
    '#type' => 'table',
  );

  // The address in the properties array to find this component's properties
  // list.
  $component_properties_address = $element['#mb_property_address'];
  $component_properties_address[] = 'properties';
  $component_value_address = $element['#mb_value_address'];
  $component_value_address[] = 'properties';
  $property_form_value_address = $element['#parents'];
  for ($delta = 0; $delta < $item_count; $delta++) {
    $row = [];
    $delta_value_address = $component_value_address;
    $delta_value_address[] = $delta;
    $delta_form_value_address = $property_form_value_address;
    $delta_form_value_address[] = $delta;

    // Put all the properties into a single cell so it's a 1-column table.
    // TODO: WTF NO STRIPING IN SEVEN THEME???
    $delta_component_element = $this
      ->getCompomentElement($form_state, $component_properties_address, $delta_value_address, $delta_form_value_address, []);
    $row['row'] = $delta_component_element;
    $element['table'][$delta] = $row;
  }
  if ($add_more) {

    // Show a button to add items, if they can be added.
    $button_text = $item_count == 0 ? t('Add a @label item', [
      '@label' => strtolower($property_info['label']),
    ]) : t('Add another @label item', [
      '@label' => strtolower($property_info['label']),
    ]);
    $element['actions']['add'] = array(
      '#type' => 'submit',
      // This allows FormAPI to figure out which button is the triggering
      // element. The name must be unique across all buttons in the form,
      // otherwise, the first matching name will be taken by FormAPI as being
      // the button that was clicked, with unexpected results.
      // See \Drupal\Core\Form\FormBuilder::elementTriggeredScriptedSubmission().
      '#name' => implode(':', $element['#mb_value_address']) . '_add_more',
      '#value' => $button_text,
      '#limit_validation_errors' => [],
      '#submit' => [
        'mb_addItemSubmit',
      ],
      '#ajax' => array(
        'callback' => 'mb_itemButtonAjax',
        'wrapper' => $wrapper_id,
        'effect' => 'fade',
      ),
    );
  }
  if ($item_count > 0) {
    $element['actions']['remove'] = [
      '#type' => 'submit',
      '#name' => implode(':', $element['#mb_value_address']) . '_remove_item',
      '#value' => t('Remove last item'),
      '#limit_validation_errors' => [],
      '#submit' => [
        'mb_removeItemSubmit',
      ],
      '#ajax' => array(
        'callback' => 'mb_itemButtonAjax',
        'wrapper' => $wrapper_id,
        'effect' => 'fade',
      ),
    ];
  }
  return 'compound';
}