You are here

protected function ComponentSectionForm::buildComplexFormElement in Module Builder 8.3

Builds a form element with multiple child elements.

Helper for buildFormElement().

Note that buildFormElement() is responsible for some attributes of the element.

1 call to ComponentSectionForm::buildComplexFormElement()
ComponentSectionForm::buildFormElement in src/Form/ComponentSectionForm.php
Builds the form element for a data item.

File

src/Form/ComponentSectionForm.php, line 482

Class

ComponentSectionForm
Generic form for entering a section of data for a component.

Namespace

Drupal\module_builder\Form

Code

protected function buildComplexFormElement(&$form, FormStateInterface $form_state, DataItem $data) {

  // Set up a wrapper for AJAX.
  $wrapper_id = Html::getId($data
    ->getAddress() . '-complex-wrapper');
  $element = [
    '#type' => 'details',
    '#title' => $data
      ->getLabel(),
    '#open' => TRUE,
    '#attributes' => [
      'id' => $wrapper_id,
    ],
  ];

  // Don't show an optional and single-valued complex element until the user
  // requests it. This is to keep the form clear, and to prevent validation
  // errors of the complex element has required properties but the user
  // doesn't want it.
  if (!$data
    ->isRequired() && $data
    ->isEmpty() && !$data
    ->isDelta()) {
    $element[':add_button'] = [
      '#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' => $data
        ->getAddress() . '_add',
      '#value' => $this
        ->t('Add @component', [
        '@component' => $data
          ->getLabel(),
      ]),
      '#limit_validation_errors' => [],
      '#submit' => [
        '::addComplexDataSubmit',
      ],
      '#data_address' => $data
        ->getAddress(),
      '#ajax' => [
        'callback' => '::complexButtonAjax',
        'wrapper' => $wrapper_id,
        'effect' => 'fade',
      ],
      '#prefix' => '<div>',
      '#suffix' => '</div>',
    ];
    return $element;
  }
  foreach ($data as $data_item) {
    $this
      ->buildFormElement($element, $form_state, $data_item);
  }
  if (!$data
    ->isRequired() && !$data
    ->isEmpty() && !$data
    ->isDelta()) {
    $element[':remove_button'] = [
      '#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' => $data
        ->getAddress() . '_remove',
      '#value' => $this
        ->t('Remove @component', [
        '@component' => $data
          ->getLabel(),
      ]),
      '#limit_validation_errors' => [],
      '#submit' => [
        '::removeComplexDataSubmit',
      ],
      '#data_address' => $data
        ->getAddress(),
      '#ajax' => [
        'callback' => '::complexButtonAjax',
        'wrapper' => $wrapper_id,
        'effect' => 'fade',
      ],
      '#prefix' => '<div>',
      '#suffix' => '</div>',
    ];
  }

  // NO! has to go immediately after the variant property!
  if ($data
    ->isMutable()) {
    if (count($data
      ->getProperties()) == 1 && $data
      ->getVariantData()->value) {
      $element['count_notice'] = [
        '#type' => 'container',
        'notice' => [
          '#plain_text' => $this
            ->t("The @variant variant has no additional properties.", [
            '@variant' => $data
              ->getVariantData()
              ->getLabel(),
          ]),
        ],
      ];
    }

    // Set up a wrapper for AJAX.
    // Note that we don't to use Html::getUniqueId() because the data's
    // address is already unique, and furthermore, we don't WANT uniqueness
    // because we want the same data item to produce the same HTML ID when
    // we're looking at the variant property form element further on.
    // TODO: this assumes only one root data item in the form, as another
    // data item could have the same addresses!
    $wrapper_id = Html::getId($data
      ->getAddress() . '-mutable-wrapper');
    $element['#attributes'] = [
      'id' => $wrapper_id,
    ];

    // WARNING: assumes the form structure!
    $mutable_property_form_address = explode(':', $data
      ->getAddress());
    $variant_property_address = array_merge($mutable_property_form_address, [
      $data
        ->getVariantData()
        ->getName(),
    ]);
    $element[':update_variant'] = [
      '#type' => 'submit',
      // Needs to be full address for uniquess in the whole form.
      '#name' => $data
        ->getAddress() . '_update_variant',
      // TODO: customisable!
      '#value' => $data
        ->isEmpty() ? $this
        ->t('Set variant') : $this
        ->t('Change variant and delete data for this item'),
      // We need to validate the variant property so we get its value in the
      // submit handler for this button.
      '#limit_validation_errors' => [
        $variant_property_address,
      ],
      '#element_validate' => [
        '::updateVariantValidate',
      ],
      '#submit' => [
        '::updateVariantSubmit',
      ],
      '#data_address' => $data
        ->getVariantData()
        ->getAddress(),
      '#variant_data_name' => $data
        ->getVariantData()
        ->getName(),
      '#ajax' => [
        'callback' => '::variantButtonAjax',
        'wrapper' => $wrapper_id,
        'effect' => 'fade',
      ],
      '#prefix' => '<div>',
      '#suffix' => '</div>',
      '#weight' => -10,
    ];

    // Also tweak the weight of the variant property so it goes above the
    // button to change the variant.
    $variant_property_name = $data
      ->getVariantData()
      ->getName();
    $element[$variant_property_name]['#weight'] = -20;
  }
  return $element;
}