ultimate_table_field-1.0.0-alpha5/src/Element/UltimateTable.php

src/Element/UltimateTable.php
<?php

namespace Drupal\ultimate_table_field\Element;

use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Element\FormElement;
use Drupal\ultimate_table_field\UltimateTableCellFieldManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

// phpcs:disable
/**
 * Provides ultimate table custom form element.
 *
 * @FormElement("ultimate_table")
 */
// @phpstan-ignore-next-line
class UltimateTable extends FormElement implements ContainerFactoryPluginInterface {
  use UltimateTableTrait;

  /**
   * Ultimate table cell field manager plugin.
   *
   * @var \Drupal\ultimate_table_field\UltimateTableCellFieldManager
   */
  protected $ultimateTableCellFieldManager;

  /**
   * {@inheritDoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, UltimateTableCellFieldManager $ultimateTableCellFieldManager) {
    // @phpstan-ignore-next-line
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->ultimateTableCellFieldManager = $ultimateTableCellFieldManager;
  }
  // phpcs:enable

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('plugin.manager.ultimate_table_cell_field'),
    );
  }

  /**
   * {@inheritDoc}
   */
  public function getInfo() {
    $class = get_class($this);
    return [
      '#input' => TRUE,
      '#process' => [
        [$class, 'elementProcess'],
      ],
      '#element_validate' => [
        [$class, 'elementValidate'],
      ],
      '#theme_wrappers' => ['container'],
      '#allowed_types' => [],
    ];
  }

  /**
   * Ultimate table form element process callback.
   */
  public static function elementProcess(array &$element, FormStateInterface $form_state, array &$complete_form) {
    $parents_reverse = array_reverse($element['#array_parents'] ?? $element['#parents']);
    $first_parent = array_pop($parents_reverse);
    $id = trim('ut-' . str_replace(['_', '[', ']'], '-', $element['#name'] ?? 'ultimate-table'), '-');
    $formatted_id = str_replace('-', '_', $id);
    $values_key = $formatted_id . '_values';
    $row_count_key = $formatted_id . '_row_count';
    $column_count_key = $formatted_id . '_column_count';
    if (!$form_state->get($values_key)) {
      $form_state->set($values_key, $element['#default_value']['values'] ?? []);
    }
    $values = $form_state->get($values_key) ?? [];

    if (!$form_state->get($row_count_key)) {
      $form_state->set($row_count_key, count($values['rows'] ?? []) + 1);
    }
    if (!$form_state->get($column_count_key)) {
      $form_state->set($column_count_key, count($values['columns'] ?? []) ?: 1);
    }

    $allowed_types = $element['#allowed_types'] ?? [];
    $row_count = $form_state->get($row_count_key);
    $column_count = $form_state->get($column_count_key);
    $element += [
      '#input' => TRUE,
      '#prefix' => '<div id="' . $id . '"><div id="' . $id . '-data-dialog-wrapper"></div>',
      '#suffix' => '</div>',
      '#tree' => TRUE,
    ];
    $label = $element['#title'] ?? '';
    $required = $element['#required'] ?? FALSE;
    $element['label'] = [
      '#type' => 'markup',
      '#markup' => !empty($label) ? '<strong class="form-item__label ' . ($required ? 'js-form-required form-required' : '') . '">' . $label . '</strong>' : '',
    ];

    $element['nb_unit'] = [
      '#type' => 'number',
      '#default_value' => 1,
      '#description' => t('Number of columns or rows to add'),
      '#min' => 1,
      '#prefix' => '<div class="table-actions-container"><div class="table-expand-btn">+</div><div class="table-actions">',
    ];
    $element['add_column'] = [
      '#type' => 'submit',
      '#name' => 'add_column::' . str_replace('-', '_', $id),
      '#value' => t('Add column'),
      '#submit' => [[self::class, 'elementSubmitCallback']],
      '#limit_validation_errors' => [[$first_parent]],
      '#ajax' => [
        'callback' => [self::class, 'updateTable'],
        'wrapper' => $id,
      ],
    ];
    $element['add_row'] = [
      '#type' => 'submit',
      '#name' => 'add_row::' . str_replace('-', '_', $id),
      '#value' => t('Add row'),
      '#submit' => [[self::class, 'elementSubmitCallback']],
      '#limit_validation_errors' => [[$first_parent]],
      '#ajax' => [
        'callback' => [self::class, 'updateTable'],
        'wrapper' => $id,
      ],
      '#suffix' => '</div></div>',
    ];
    $element['table'] = [
      '#type' => 'table',
      '#tabledrag' => [
        [
          'action' => 'order',
          'relationship' => 'sibling',
          'group' => 'table-order-weight',
        ],
      ],
      '#attributes' => [
        'class' => ['custom-bordered-table'],
      ],
      '#input' => TRUE,
      '#tree' => TRUE,
      '#prefix' => '<div class="top-scroll"><div class="top-scroll-content"></div></div><div class="table-responsive">',
      '#suffix' => '</div>',
    ];
    $ut_cell_field_manager = \Drupal::service('plugin.manager.ultimate_table_cell_field');
    for ($i = 0; $i < $row_count; $i++) {
      $items_data = NULL;
      // Create draggable rows.
      if ($i !== 0) {
        $element['table'][$i] = [
          '#attributes' => ['class' => ['draggable']],
          '#weight' => $i,
        ];
      }
      for ($j = 0; $j < $column_count; $j++) {
        $first_row_ever = FALSE;
        if ($i == 0 && $j != 0) {
          $first_row_ever = TRUE;
          $items_data = $values['columns'][$j] ?? [];
          // Remove column item.
          $element['table'][$i][$j]['remove_col'] = static::getControlledItem($id, $first_parent, $i, $j, $values, 'column');
        }
        elseif ($j == 0 && $i != 0) {
          // Remove row item.
          $element['table'][$i][$j]['remove_row'] = static::getControlledItem($id, $first_parent, $i, $j, $values);
        }
        elseif ($j == 0 && $i == 0) {
          $first_row_ever = TRUE;
          $items_data = $values['columns'][$j] ?? [];
        }
        if (!$first_row_ever) {
          $items_data = $values['rows'][$i - 1][$j] ?? [];
        }
        $cell_id = $id . '_items_data_' . $i . '_' . $j;
        $element['table'][$i][$j]['data'] = [
          '#type' => 'hidden',
          '#default_value' => Json::encode($items_data),
          '#attributes' => [
            'id' => 'data-input-' . $i . '-' . $j . '--' . $id,
          ],
        ];
        static::buildCellSummaryElement($id, $first_parent, $element, $i, $j, $items_data, $cell_id, $ut_cell_field_manager, $allowed_types);
      }
      $element['table'][$i]['weight'] = [
        '#type' => 'weight',
        '#title' => t('Weight for row @number', ['@number' => $i]),
        '#title_display' => 'invisible',
        '#default_value' => $i,
        '#attributes' => ['class' => ['table-order-weight']],
      ];
    }
    $element['update'] = [
      '#type' => 'submit',
      '#name' => 'update_table::' . str_replace('-', '_', $id),
      '#value' => t('Update'),
      '#limit_validation_errors' => [[$first_parent]],
      '#attributes' => [
        'class' => ['js-hide'],
      ],
      '#submit' => [[self::class, 'elementSubmitCallback']],
      '#ajax' => [
        'callback' => [self::class, 'updateTable'],
        'wrapper' => $id,
      ],
    ];

    // Add legend field if enabled.
    if (!empty($element['#enable_legend'])) {
      $element['legend'] = [
        '#type' => 'text_format',
        '#title' => t('Legend'),
        '#format' => 'full_html',
        '#default_value' => $values['legend'] ?? '',
        '#rows' => 3,
      ];
    }

    $element['#attached']['library'][] = 'ultimate_table_field/style';
    $element['#attached']['library'][] = 'ultimate_table_field/table-actions';
    $element['#attached']['library'][] = 'core/drupal.dialog.ajax';
    return $element;
  }

  /**
   * {@inheritDoc}
   */
  public static function elementValidate(array &$element, FormStateInterface $form_state, array &$complete_form) {

  }

  /**
   * {@inheritDoc}
   */
  public static function elementSubmitCallback(array &$element, FormStateInterface $form_state) {
    $user_input = $form_state->getUserInput();
    $values = $form_state->getValues();
    $triggering_element = $form_state->getTriggeringElement();
    $name = $triggering_element['#name'] ?? '';
    $name_pieces = explode('::', $name);
    $name_from_id = $name_pieces[0] ?? NULL;
    $id = $name_pieces[1] ?? NULL;
    $name = $name_from_id ?? $name;
    $is_update_table = FALSE;
    $values_key = $id . '_values';
    $row_count_key = $id . '_row_count';
    $column_count_key = $id . '_column_count';
    if (str_starts_with($name, 'row_remove') || str_starts_with($name, 'column_remove')) {
      $parents = $triggering_element['#parents'];
      array_splice($parents, -5);
    }
    $main_buttons = [
      'update_table',
      'add_row',
      'add_column',
    ];
    if (in_array($name, $main_buttons, TRUE)) {
      $parents = $triggering_element['#parents'];
      array_pop($parents);
    }
    $table_values = NestedArray::getValue($values, $parents);
    $nb_unit = !empty($table_values['nb_unit']) ? $table_values['nb_unit'] : 1;
    NestedArray::setValue($user_input, [...$parents, 'nb_unit'], 1);
    $table_values = $table_values['values'] ?? [];
    if (str_starts_with($name, 'add_row')) {
      $row_count = $form_state->get($row_count_key);
      $form_state->set($row_count_key, $row_count + $nb_unit);
      $is_update_table = TRUE;
    }
    if (str_starts_with($name, 'add_column')) {
      $column_count = $form_state->get($column_count_key);
      $form_state->set($column_count_key, $column_count + $nb_unit);
      $is_update_table = TRUE;
    }
    if (str_starts_with($name, 'row_remove')) {
      $indexes_infos = array_slice($triggering_element['#array_parents'], -4);
      $row_index = $indexes_infos[0];
      unset($table_values['rows'][$row_index - 1]);
      $table_values['rows'] = array_values($table_values['rows']);
      $row_count = $form_state->get('row_count');
      $form_state->set($row_count_key, --$row_count);
      $parents = $triggering_element['#parents'];
      $parents = array_slice($parents, 0, count($parents) - 3);
      $user_input_row_index = array_pop($parents);
      $rows_table_input = NestedArray::getValue($user_input, $parents) ?? [];
      unset($rows_table_input[$user_input_row_index]);
      NestedArray::setValue($user_input, $parents, $rows_table_input);
    }
    if (str_starts_with($name, 'column_remove')) {
      $indexes_infos = array_slice($triggering_element['#array_parents'], -3);
      $column_index = $indexes_infos[0];
      unset($table_values['columns'][$column_index]);
      $table_values['columns'] = array_values($table_values['columns']);
      foreach ($table_values['rows'] as &$value) {
        unset($value[$column_index]);
        $value = array_values($value);
      }
      $column_count = $form_state->get('column_count');
      $form_state->set($column_count_key, --$column_count);
      $parents = $triggering_element['#parents'];
      $input_indexes_infos = array_slice($parents, -3);
      $input_column_index = reset($input_indexes_infos);
      $parents = array_slice($parents, 0, count($parents) - 4);
      $rows_table_input = NestedArray::getValue($user_input, $parents) ?? [];
      foreach ($rows_table_input as &$row) {
        foreach ($row as $key => $item) {
          if ($key == $input_column_index) {
            unset($row[$key]);
            break;
          }
        }
      }
      NestedArray::setValue($user_input, $parents, array_values($rows_table_input));
    }
    if ($is_update_table || str_starts_with($name, 'update_table')) {
      $parents = $triggering_element['#parents'];
      array_pop($parents);
      $parents[] = 'table';
      $table_input = NestedArray::getValue($user_input, $parents) ?? [];
    }

    if (str_starts_with($name, 'row_remove') || str_starts_with($name, 'column_remove')) {
      $parents = $triggering_element['#parents'];
      $parents = array_splice($parents, -3);
      $table_input = NestedArray::getValue($user_input, $parents) ?? [];
    }

    usort($table_input, function ($a, $b) {
      return $a['weight'] <=> $b['weight'];
    });
    NestedArray::setValue($user_input, $parents, $table_input);

    $form_state->setUserInput($user_input);
    $form_state->set($values_key, $table_values);
    $form_state->setRebuild();
  }

  /**
   * {@inheritDoc}
   */
  public static function updateTable(array &$element, FormStateInterface $form_state) {
    $user_input = $form_state->getUserInput();
    $triggering_element = $form_state->getTriggeringElement();
    $name = $triggering_element['#name'];
    $name_pieces = explode('::', $name);
    $name_from_id = $name_pieces[0] ?? NULL;
    $id = $name_pieces[1] ?? NULL;
    $formatted_id = str_replace('_', '-', $id);
    $name = $name_from_id ?? $name;
    if (str_starts_with($name, 'item_remove')) {
      $parents = $triggering_element['#parents'];
      array_splice($parents, -3);
      $data_input = NestedArray::getValue($user_input, $parents);
      $data = $data_input['data'] ?? NULL;
      $name_pieces = explode(':', $name);
      $indexes = explode('_', $name_pieces[1]);
      $i = $indexes[0];
      $j = $indexes[1];
      $k = $indexes[2];
      $items_data = $data ? Json::decode($data) : [];
      unset($items_data[$k]);
      $items_data = array_values($items_data);
      $response = new AjaxResponse();
      $update_button_selector = 'input[name="update_table::' . $id . '"]';
      $data_input_selector = '#data-input-' . $i . '-' . $j . '--' . $formatted_id;
      $response->addCommand(new InvokeCommand($data_input_selector, 'val', [Json::encode($items_data)]))
        ->addCommand(new InvokeCommand($update_button_selector, 'trigger', ['mousedown']));
      return $response;
    }
    $parents = $triggering_element['#array_parents'];
    if (str_starts_with($name, 'row_remove') || str_starts_with($name, 'column_remove')) {
      array_splice($parents, -5);
    }
    $main_buttons = [
      'update_table',
      'add_row',
      'add_column',
    ];
    if (in_array($name, $main_buttons, TRUE)) {
      array_pop($parents);
    }
    $element = NestedArray::getValue($element, $parents);
    return $element;
  }

  /**
   * {@inheritDoc}
   */
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
    $columns_values = [];
    $rows_values = [];
    $legend = '';

    if ($input) {
      if (isset($input['legend'])) {
        $legend = $input['legend']['value'];
      }
      $input = $input['table'] ?? $input;
      $columns = $input[0];
      unset($input[0]);
      foreach ($columns as $key => $column) {
        if ($key === 'weight') {
          continue;
        }
        if (is_array($column)) {
          $data = $column['data'];
          $data = Json::decode($data);
          $columns_values[] = $data;
        }
        else {
          $columns_values[] = $column;
        }
      }
      if (!empty($input)) {
        foreach ($input as $row) {
          $row_values = [];
          foreach ($row as $column_index => $value) {
            if ($column_index === 'weight') {
              continue;
            }
            if (is_array($value)) {
              $data = $value['data'];
              $data = Json::decode($data);
              $row_values[] = $data;
            }
            else {
              $row_values[] = $value;
            }
          }
          $rows_values[] = $row_values;
        }
      }
    }

    $values = [
      'values' => [
        'columns' => $columns_values,
        'rows' => $rows_values,
        'legend' => $legend,
      ],
    ];

    return $values;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc