Same name and namespace in other branches
  1. 8.9.x core/modules/field_ui/src/Element/FieldUiTable.php \Drupal\field_ui\Element\FieldUiTable
  2. 9 core/modules/field_ui/src/Element/FieldUiTable.php \Drupal\field_ui\Element\FieldUiTable

Hierarchy

Expanded class hierarchy of FieldUiTable

File

core/modules/field_ui/src/Element/FieldUiTable.php, line 14

Namespace

Drupal\field_ui\Element
View source
class FieldUiTable extends Table {

  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    $info = parent::getInfo();
    $info['#regions'] = [
      '' => [],
    ];
    $info['#theme'] = 'field_ui_table';

    // Prepend FieldUiTable's prerender callbacks.
    array_unshift($info['#pre_render'], [
      $this,
      'tablePreRender',
    ], [
      $this,
      'preRenderRegionRows',
    ]);
    return $info;
  }

  /**
   * Performs pre-render tasks on field_ui_table elements.
   *
   * @param array $elements
   *   A structured array containing two sub-levels of elements. Properties
   *   used:
   *   - #region_callback: A callback that provides the region of the table to
   *     place the row in.
   *   - #tabledrag: The value is a list of $options arrays that are passed to
   *     drupal_attach_tabledrag(). The HTML ID of the table is added to each
   *     $options array.
   *
   * @return array
   *   The $element with prepared variables ready for field-ui-table.html.twig.
   *
   * @see \Drupal\Core\Render\RendererInterface::render()
   * @see \Drupal\Core\Render\Element\Table::preRenderTable()
   */
  public static function tablePreRender($elements) {
    $js_settings = [];

    // For each region, build the tree structure from the weight and parenting
    // data contained in the flat form structure, to determine row order and
    // indentation.
    $regions = $elements['#regions'];
    $tree = [
      '' => [
        'name' => '',
        'children' => [],
      ],
    ];
    $trees = array_fill_keys(array_keys($regions), $tree);
    $parents = [];
    $children = Element::children($elements);
    $list = array_combine($children, $children);

    // Iterate on rows until we can build a known tree path for all of them.
    while ($list) {
      foreach ($list as $name) {
        $row =& $elements[$name];
        $parent = $row['parent_wrapper']['parent']['#value'];

        // Proceed if parent is known.
        if (empty($parent) || isset($parents[$parent])) {

          // Grab parent, and remove the row from the next iteration.
          $parents[$name] = $parent ? array_merge($parents[$parent], [
            $parent,
          ]) : [];
          unset($list[$name]);

          // Determine the region for the row.
          $region_name = call_user_func_array($row['#region_callback'], [
            &$row,
          ]);

          // Add the element in the tree.
          // phpcs:ignore DrupalPractice.CodeAnalysis.VariableAnalysis.UnusedVariable
          $target =& $trees[$region_name][''];
          foreach ($parents[$name] as $key) {
            $target =& $target['children'][$key];
          }
          $target['children'][$name] = [
            'name' => $name,
            'weight' => $row['weight']['#value'],
          ];

          // Add tabledrag indentation to the first row cell.
          if ($depth = count($parents[$name])) {
            $children = Element::children($row);
            $cell = current($children);
            $indentation = [
              '#theme' => 'indentation',
              '#size' => $depth,
              '#suffix' => $row[$cell]['#prefix'] ?? '',
            ];
            $row[$cell]['#prefix'] = \Drupal::service('renderer')
              ->render($indentation);
          }

          // Add row id and associate JS settings.
          $id = Html::getClass($name);
          $row['#attributes']['id'] = $id;
          if (isset($row['#js_settings'])) {
            $row['#js_settings'] += [
              'rowHandler' => $row['#row_type'],
              'name' => $name,
              'region' => $region_name,
            ];
            $js_settings[$id] = $row['#js_settings'];
          }
        }
      }
    }

    // Determine rendering order from the tree structure.
    foreach ($regions as $region_name => $region) {
      $elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], [
        static::class,
        'reduceOrder',
      ]);
    }
    $elements['#attached']['drupalSettings']['fieldUIRowsData'] = $js_settings;

    // If the custom #tabledrag is set and there is an HTML ID, add the table's
    // HTML ID to the options and attach the behavior.
    // @see \Drupal\Core\Render\Element\Table::preRenderTable()
    if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
      foreach ($elements['#tabledrag'] as $options) {
        $options['table_id'] = $elements['#attributes']['id'];
        drupal_attach_tabledrag($elements, $options);
      }
    }
    return $elements;
  }

  /**
   * Performs pre-render to move #regions to rows.
   *
   * @param array $elements
   *   A structured array containing two sub-levels of elements. Properties
   *   used:
   *   - #tabledrag: The value is a list of $options arrays that are passed to
   *     drupal_attach_tabledrag(). The HTML ID of the table is added to each
   *     $options array.
   *
   * @return array
   *   The $element with prepared variables ready for field-ui-table.html.twig.
   */
  public static function preRenderRegionRows($elements) {

    // Determine the colspan to use for region rows, by checking the number of
    // columns in the headers.
    $columns_count = 0;
    foreach ($elements['#header'] as $header) {
      $columns_count += is_array($header) && isset($header['colspan']) ? $header['colspan'] : 1;
    }
    $rows = [];
    foreach (Element::children($elements) as $key) {
      $rows[$key] = $elements[$key];
      unset($elements[$key]);
    }

    // Render rows, region by region.
    foreach ($elements['#regions'] as $region_name => $region) {
      $region_name_class = Html::getClass($region_name);

      // Add region rows.
      if (isset($region['title']) && empty($region['invisible'])) {
        $elements['#rows'][] = [
          'class' => [
            'region-title',
            'region-' . $region_name_class . '-title',
          ],
          'no_striping' => TRUE,
          'data' => [
            [
              'data' => $region['title'],
              'colspan' => $columns_count,
            ],
          ],
        ];
      }
      if (isset($region['message'])) {
        $class = empty($region['rows_order']) ? 'region-empty' : 'region-populated';
        $elements['#rows'][] = [
          'class' => [
            'region-message',
            'region-' . $region_name_class . '-message',
            $class,
          ],
          'no_striping' => TRUE,
          'data' => [
            [
              'data' => $region['message'],
              'colspan' => $columns_count,
            ],
          ],
        ];
      }

      // Add form rows, in the order determined at pre-render time.
      foreach ($region['rows_order'] as $name) {
        $element = $rows[$name];
        $row = [
          'data' => [],
        ];
        if (isset($element['#attributes'])) {
          $row += $element['#attributes'];
        }

        // Render children as table cells.
        foreach (Element::children($element) as $cell_key) {
          $child = $element[$cell_key];

          // Do not render a cell for children of #type 'value'.
          if (!(isset($child['#type']) && $child['#type'] == 'value')) {
            $cell = [
              'data' => $child,
            ];
            if (isset($child['#cell_attributes'])) {
              $cell += $child['#cell_attributes'];
            }
            $row['data'][] = $cell;
          }
        }
        $elements['#rows'][] = $row;
      }
    }
    return $elements;
  }

  /**
   * Determines the rendering order of an array representing a tree.
   *
   * Callback for array_reduce() within ::tablePreRender().
   *
   * @param mixed $array
   *   Holds the return value of the previous iteration; in the case of the
   *   first iteration it instead holds the value of the initial array.
   * @param mixed $a
   *   Holds the value of the current iteration.
   *
   * @return array
   *   Array where rendering order has been determined.
   */
  public static function reduceOrder($array, $a) {
    $array = !$array ? [] : $array;
    if (!empty($a['name'])) {
      $array[] = $a['name'];
    }
    if (!empty($a['children'])) {
      uasort($a['children'], [
        'Drupal\\Component\\Utility\\SortArray',
        'sortByWeightElement',
      ]);
      $array = array_merge($array, array_reduce($a['children'], [
        static::class,
        'reduceOrder',
      ]));
    }
    return $array;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
FieldUiTable::getInfo public function Returns the element properties for this element. Overrides Table::getInfo
FieldUiTable::preRenderRegionRows public static function Performs pre-render to move #regions to rows.
FieldUiTable::reduceOrder public static function Determines the rendering order of an array representing a tree.
FieldUiTable::tablePreRender public static function Performs pre-render tasks on field_ui_table elements.
FormElement::processAutocomplete public static function Adds autocomplete functionality to elements.
FormElement::processPattern public static function #process callback for #pattern form element property.
FormElement::validatePattern public static function #element_validate callback for #pattern form element property.
MessengerTrait::$messenger protected property The messenger. 10
MessengerTrait::messenger public function Gets the messenger. 10
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 2
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginBase::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. 38
RenderElement::preRenderAjaxForm public static function Adds Ajax information about an element to communicate with JavaScript.
RenderElement::preRenderGroup public static function Adds members of this group as actual elements for rendering.
RenderElement::processAjaxForm public static function Form element processing handler for the #ajax form property. 1
RenderElement::processGroup public static function Arranges elements into groups.
RenderElement::setAttributes public static function Sets a form element's class attribute. Overrides ElementInterface::setAttributes
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 1
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
Table::preRenderTable public static function #pre_render callback to transform children of an element of #type 'table'.
Table::processTable public static function #process callback for #type 'table' to add tableselect support.
Table::validateTable public static function #element_validate callback for #type 'table'.
Table::valueCallback public static function Determines how user input is mapped to an element's #value property. Overrides FormElement::valueCallback 1