You are here

function paragraphs_sets_field_widget_multivalue_form_alter in Paragraphs Sets 8.2

Implements hook_field_widget_multivalue_form_alter().

File

./paragraphs_sets.module, line 142
Main functions of paragraphs_sets.module.

Code

function paragraphs_sets_field_widget_multivalue_form_alter(array &$elements, FormStateInterface $form_state, array $context) {

  /** @var \Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget $widget */
  $widget = $context['widget'];
  if (!$widget instanceof ParagraphsWidget) {
    return;
  }
  $items = $context['items'];
  $host = $context['items']
    ->getEntity();
  $form = $context['form'];
  $widget_settings = $widget
    ->getSettings();

  /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
  $field_definition = $items
    ->getFieldDefinition();
  $field_name = $field_definition
    ->getName();
  $field_parents = $form['#parents'];
  $field_state = ParagraphsSets::getWidgetState($field_parents, $field_name, $form_state);
  $is_multiple = $field_definition
    ->getFieldStorageDefinition()
    ->isMultiple();
  $cardinality = $field_definition
    ->getFieldStorageDefinition()
    ->getCardinality();
  $field_title = $field_definition
    ->getLabel();
  $description = FieldFilteredMarkup::create(\Drupal::token()
    ->replace($field_definition
    ->getDescription()));
  $user_input =& $form_state
    ->getUserInput();
  $max = $field_state['items_count'];
  $entity_type_manager = \Drupal::entityTypeManager();

  // Get a list of all Paragraphs types allowed in this field.
  $field_allowed_paragraphs_types = $widget
    ->getAllowedTypes($field_definition);
  $sets = ParagraphsSets::getSets(array_keys($field_allowed_paragraphs_types));

  // Limit available sets from widget settings.
  $widget_third_party_settings = $widget
    ->getThirdPartySetting('paragraphs_sets', 'paragraphs_sets', []);
  if (isset($widget_third_party_settings['sets_allowed']) && count(array_filter($widget_third_party_settings['sets_allowed']))) {
    $sets = array_intersect_key($sets, array_filter($widget_third_party_settings['sets_allowed']));
  }
  $set = isset($field_state['selected_set']) ? $field_state['selected_set'] : NULL;

  // Consider adding a default paragraph set for new host entities.
  if ($max == 0 && $items
    ->getEntity()
    ->isNew() && empty($set)) {
    $default_set = $widget_third_party_settings['default_set'] ?? PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE;
    if ($default_set !== PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE && isset($sets[$default_set]) && isset($sets[$default_set]['paragraphs']) && ($cardinality === FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || count($sets[$default_set]['paragraphs']) <= $cardinality)) {
      $set = $default_set;
    }
  }
  if ($set && isset($sets[$set])) {
    if (isset($field_state['button_type']) && 'set_selection_button' === $field_state['button_type']) {

      // Clear all items.
      $items
        ->filter(function () {
        return FALSE;
      });

      // Clear field state.
      $field_state['paragraphs'] = [];

      // Clear user input.
      foreach ($user_input[$field_name] as $key => $value) {
        if (!is_numeric($key) || empty($value['subform'])) {
          continue;
        }
        unset($user_input[$field_name][$key]);
      }
      $field_state['items_count'] = 0;
      foreach (Element::children($elements) as $element_key) {
        if (is_numeric($element_key)) {
          unset($elements[$element_key]);
        }
      }
      $max = 0;
    }
    $target_type = $field_definition
      ->getSetting('target_type');
    $context = [
      'set' => $set,
      'field' => $field_definition,
      'form' => $form,
      'form_state' => $form_state,
      'entity' => $host,
    ];

    // Get delta where the sets paragraphs should be added (when using
    // "add in between").
    $insert_delta = isset($user_input[$field_name]['add_more']['add_modal_form_area']['add_more_delta']) ? $user_input[$field_name]['add_more']['add_modal_form_area']['add_more_delta'] : NULL;
    foreach ($sets[$set]['paragraphs'] as $key => $info) {
      $alter_hooks = [
        'paragraphs_set_data',
        'paragraphs_set_' . $set . '_data',
        'paragraphs_set_' . $set . '_' . $field_name . '_data',
      ];
      $context['key'] = $key;
      $context['paragraphs_bundle'] = $info['type'];
      $data = empty($info['data']) ? [] : $info['data'];
      \Drupal::moduleHandler()
        ->alter($alter_hooks, $data, $context);
      $item_values = [
        'type' => $info['type'],
      ] + $data;
      $max++;
      if (isset($insert_delta)) {
        ParagraphsSets::prepareDeltaPosition($field_state, $form_state, [
          $field_name,
        ], $insert_delta);
        $insert_delta++;
      }
      $paragraphs_entity = $entity_type_manager
        ->getStorage($target_type)
        ->create($item_values);
      $display = EntityFormDisplay::collectRenderDisplay($paragraphs_entity, $field_definition
        ->getSetting('form_display_mode'));
      $field_state['paragraphs'][$max - 1] = [
        'entity' => $paragraphs_entity,
        'display' => $display,
        'mode' => isset($widget_settings['edit_mode']) && $widget_settings['edit_mode'] === 'open' ? 'edit' : 'closed',
        'original_delta' => $max,
      ];
    }
    $field_state['items_count'] = $max;
    $field_state['real_item_count'] = $max;
    $field_state['selected_set'] = NULL;
    ParagraphsSets::setWidgetState($field_parents, $field_name, $form_state, $field_state);
  }
  if ($max > 0) {
    for ($delta = 0; $delta < $max; $delta++) {

      // Add a new empty item if it doesn't exist yet at this delta.
      if (!isset($items[$delta])) {
        $items
          ->appendItem();
      }

      // For multiple fields, title and description are handled by the wrapping
      // table.
      $element_base = [
        '#title' => $is_multiple ? '' : $field_title,
        '#description' => $is_multiple ? '' : $description,
        '#paragraphs_bundle' => '',
      ];
      $element_base += [
        '#field_parents' => $form['#parents'],
        // Only the first widget should be required.
        '#required' => $delta == 0 && $field_definition
          ->isRequired(),
        '#delta' => $delta,
        '#weight' => $delta,
      ];
      $element = $widget
        ->formElement($items, $delta, $element_base, $form, $form_state);
      if ($element) {

        // Set paragraphs bundle.
        $widget_state = ParagraphsSets::getWidgetState($element['#field_parents'], $field_name, $form_state);
        $element['#paragraphs_bundle'] = $widget_state['paragraphs'][$delta]['entity']
          ->bundle();

        // Allow modules to alter the field widget form element.
        $context = [
          'form' => $form,
          'widget' => $widget,
          'items' => $items,
          'delta' => $delta,
          'default' => (bool) $form_state
            ->get('default_value_widget'),
        ];
        \Drupal::moduleHandler()
          ->alter([
          'field_widget_form',
          'field_widget_' . $widget
            ->getPluginId() . '_form',
        ], $element, $form_state, $context);

        // Input field for the delta (drag-n-drop reordering).
        if ($is_multiple) {

          // We name the element '_weight' to avoid clashing with elements
          // defined by widget.
          $element['_weight'] = [
            '#type' => 'weight',
            '#title' => t('Weight for row @number', [
              '@number' => $delta + 1,
            ]),
            '#title_display' => 'invisible',
            // Note: this 'delta' is the FAPI #type 'weight' element's property.
            '#delta' => $max,
            '#default_value' => $items[$delta]->_weight ?: $delta,
            '#weight' => 100,
          ];
        }

        // Access for the top element is set to FALSE only when the paragraph
        // was removed. A paragraphs that a user can not edit has access on
        // lower level.
        if (isset($element['#access']) && !$element['#access']) {
          $field_state['items_count']--;
        }
        else {
          $elements[$delta] = $element;
        }
      }
    }
  }
  if ($cardinality !== FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && $field_state['items_count'] >= $cardinality) {
    unset($elements['add_more']);
  }

  // Stop further processing if this field does not want the Paragraphs Sets
  // form elements or there aren't any allowed sets for this field.
  if (empty($widget_third_party_settings['use_paragraphs_sets'])) {
    return;
  }
  $field_state = ParagraphsSets::getWidgetState($field_parents, $field_name, $form_state);
  $field_state['real_item_count'] = $field_state['items_count'];
  $field_state['add_mode'] = $widget
    ->getSetting('add_mode');
  ParagraphsSets::setWidgetState($field_parents, $field_name, $form_state, $field_state);
  if (isset($elements['#theme']) && 'field_multiple_value_form' === $elements['#theme']) {
    $elements['#theme'] = 'field_multiple_value_form__paragraphs_sets';
  }
  if ('modal' === $field_state['add_mode']) {
    $elements['add_more']['#theme'] = 'paragraphs_sets_add_dialog';
    $elements['add_more']['#widget_title'] = $widget
      ->getSetting('title');
    $elements['add_more']['#widget_title_plural'] = $widget
      ->getSetting('title_plural');
    $cardinality = $field_definition
      ->getFieldStorageDefinition()
      ->getCardinality();
    $field_id_prefix = implode('-', array_merge($field_parents, [
      $field_name,
    ]));
    $field_wrapper_id = Html::getId($field_id_prefix . '-add-more-wrapper');
    foreach ($sets as $machine_name => $set) {
      if ($cardinality !== FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && count($set['paragraphs']) > $cardinality) {

        // Do not add sets having more paragraphs than allowed.
        continue;
      }
      $button_key = 'append_selection_button_' . $machine_name;
      $elements['add_more'][$button_key] = ParagraphsWidget::expandButton([
        '#type' => 'submit',
        '#name' => $field_id_prefix . '_' . $machine_name . '_set_set',
        '#value' => $set['label'],
        '#attributes' => [
          'class' => [
            'field-add-more-submit',
            'field-append-set-submit',
          ],
        ],
        '#limit_validation_errors' => [
          array_merge($field_parents, [
            $field_definition
              ->getName(),
            'set_set',
          ]),
        ],
        '#submit' => [
          [
            'Drupal\\paragraphs_sets\\ParagraphsSets',
            'setSetSubmit',
          ],
        ],
        '#ajax' => [
          'callback' => [
            'Drupal\\paragraphs_sets\\ParagraphsSets',
            'setSetAjax',
          ],
          'wrapper' => $field_wrapper_id,
        ],
        '#set_machine_name' => $machine_name,
      ]);
    }
  }
  $context['widget'] = $widget;
  $elements['set_selection'] = ParagraphsSets::buildSelectSetSelection($elements, $context, $form_state, $set);
  $elements['#attached']['library'][] = 'paragraphs_sets/drupal.paragraphs_sets.admin';
}