class Table
Same name in this branch
- 11.x core/modules/views/src/Plugin/views/style/Table.php \Drupal\views\Plugin\views\style\Table
Same name and namespace in other branches
- 9 core/modules/views/src/Plugin/views/style/Table.php \Drupal\views\Plugin\views\style\Table
- 9 core/lib/Drupal/Core/Render/Element/Table.php \Drupal\Core\Render\Element\Table
- 8.9.x core/modules/views/src/Plugin/views/style/Table.php \Drupal\views\Plugin\views\style\Table
- 8.9.x core/lib/Drupal/Core/Render/Element/Table.php \Drupal\Core\Render\Element\Table
- 10 core/modules/views/src/Plugin/views/style/Table.php \Drupal\views\Plugin\views\style\Table
- 10 core/lib/Drupal/Core/Render/Element/Table.php \Drupal\Core\Render\Element\Table
Provides a render element for a table.
Note: Although this extends FormElementBase, it can be used outside the context of a form.
Properties:
@property $header An array of table header labels. @property $rows An array of the rows to be displayed. Each row is either an array of cell contents or an array of properties as described in table.html.twig Alternatively specify the data for the table as child elements of the table element. Table elements would contain rows elements that would in turn contain column elements. @property $empty Text to display when no rows are present. @property $responsive Indicates whether to add the drupal.tableresponsive library providing responsive tables. Defaults to TRUE. @property $sticky Indicates whether to make the table headers sticky at the top of the page. Defaults to FALSE. @property $footer Table footer rows, in the same format as the #rows property. @property $caption A localized string for the <caption> tag.
Usage example 1: A simple form with an additional information table which doesn't include any other form field.
// Table header.
$header = [
'name' => $this->t('Name'),
'age' => $this->t('Age'),
'email' => $this->t('Email'),
];
// Default data rows (these can be fetched from the database or any other
// source).
$default_rows = [
[
'name' => 'John',
'age' => 28,
'email' => 'john@example.com',
],
[
'name' => 'Jane',
'age' => 25,
'email' => 'jane@example.com',
],
];
// Prepare rows for the table element. We just display the information with
// #markup.
$rows = [];
foreach ($default_rows as $default_row) {
$rows[] = [
'name' => [
'data' => [
'#markup' => $default_row['name'],
],
],
'age' => [
'data' => [
'#markup' => $default_row['age'],
],
],
'email' => [
'data' => [
'#markup' => $default_row['email'],
],
],
];
}
// Now set the table element.
$form['information'] = [
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
// Add the prepared rows here.
'#empty' => $this->t('No entries available.'),
];
Usage example 2: A table of form fields without the #rows property defined.
// Set the contact element as a table render element with no #rows property.
// Next add five rows as sub-elements (or children) that will populate
// automatically the #rows property in preRenderTable().
$form['contacts'] = [
'#type' => 'table',
'#caption' => $this->t('Sample Table'),
'#header' => [
$this->t('Name'),
$this->t('Phone'),
],
'#rows' => [],
'#empty' => $this->t('No entries available.'),
];
// Add arbitrarily four rows to the table. Each row contains two fields
// (name and phone). The preRenderTable() method will add each sub-element
// (or children) of the table element to the #rows property.
for ($i = 1; $i <= 4; $i++) {
// Add foo and baz classes for each row.
$form['contacts'][$i]['#attributes'] = [
'class' => [
'foo',
'baz',
],
];
// Set the first column.
$form['contacts'][$i]['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Name'),
'#title_display' => 'invisible',
];
// Set the second column.
$form['contacts'][$i]['phone'] = [
'#type' => 'tel',
'#title' => $this->t('Phone'),
'#title_display' => 'invisible',
];
}
// Add the fifth row as a colspan of two columns.
$form['contacts'][]['colspan_example'] = [
'#plain_text' => 'Colspan Example',
'#wrapper_attributes' => [
'colspan' => 2,
'class' => [
'foo',
'bar',
],
],
];
Attributes
Hierarchy
- class \Drupal\Component\Plugin\PluginBase extends \Drupal\Component\Plugin\PluginInspectionInterface, \Drupal\Component\Plugin\DerivativeInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait implements \Drupal\Component\Plugin\PluginBase
- class \Drupal\Core\Render\Element\RenderElementBase extends \Drupal\Core\Render\Element\ElementInterface, \Drupal\Core\Plugin\ContainerFactoryPluginInterface implements \Drupal\Core\Plugin\PluginBase
- class \Drupal\Core\Render\Element\FormElementBase extends \Drupal\Core\Render\Element\FormElementInterface implements \Drupal\Core\Render\Element\RenderElementBase
- class \Drupal\Core\Render\Element\Table implements \Drupal\Core\Render\Element\FormElementBase
- class \Drupal\Core\Render\Element\FormElementBase extends \Drupal\Core\Render\Element\FormElementInterface implements \Drupal\Core\Render\Element\RenderElementBase
- class \Drupal\Core\Render\Element\RenderElementBase extends \Drupal\Core\Render\Element\ElementInterface, \Drupal\Core\Plugin\ContainerFactoryPluginInterface implements \Drupal\Core\Plugin\PluginBase
- class \Drupal\Core\Plugin\PluginBase uses \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait implements \Drupal\Component\Plugin\PluginBase
Expanded class hierarchy of Table
See also
\Drupal\Core\Render\Element\Tableselect
1 file declares its use of Table
- FieldUiTable.php in core/
modules/ field_ui/ src/ Element/ FieldUiTable.php
77 string references to 'Table'
- BookAdminEditForm::bookAdminTableTree in core/
modules/ book/ src/ Form/ BookAdminEditForm.php - Helps build the main table in the book administration page form.
- BookAdminEditForm::submitForm in core/
modules/ book/ src/ Form/ BookAdminEditForm.php - Form submission handler.
- ckeditor5.ckeditor5.yml in core/
modules/ ckeditor5/ ckeditor5.ckeditor5.yml - core/modules/ckeditor5/ckeditor5.ckeditor5.yml
- ckeditor5.ckeditor5.yml in core/
modules/ ckeditor5/ ckeditor5.ckeditor5.yml - core/modules/ckeditor5/ckeditor5.ckeditor5.yml
- claro_preprocess_file_widget_multiple in core/
themes/ claro/ claro.theme - Implements hook_preprocess_HOOK() for file_widget_multiple.
69 #type uses of Table
- BanAdmin::buildForm in core/
modules/ ban/ src/ Form/ BanAdmin.php - BlockLibraryController::listBlocks in core/
modules/ block/ src/ Controller/ BlockLibraryController.php - Shows a list of blocks that can be added to a theme's layout.
- BlockListBuilder::buildBlocksForm in core/
modules/ block/ src/ BlockListBuilder.php - Builds the main "Blocks" portion of the form.
- BookAdminEditForm::bookAdminTable in core/
modules/ book/ src/ Form/ BookAdminEditForm.php - Builds the table portion of the form for the book administration page.
- BookController::adminOverview in core/
modules/ book/ src/ Controller/ BookController.php - Returns an administrative overview of all books.
File
-
core/
lib/ Drupal/ Core/ Render/ Element/ Table.php, line 119
Namespace
Drupal\Core\Render\ElementView source
class Table extends FormElementBase {
/**
* {@inheritdoc}
*/
public function getInfo() {
return [
'#header' => [],
'#rows' => [],
'#empty' => '',
// Properties for tableselect support.
'#input' => TRUE,
'#tree' => TRUE,
'#tableselect' => FALSE,
'#sticky' => FALSE,
'#responsive' => TRUE,
'#multiple' => TRUE,
'#js_select' => TRUE,
'#process' => [
[
static::class,
'processTable',
],
],
'#element_validate' => [
[
static::class,
'validateTable',
],
],
// Properties for tabledrag support.
// The value is a list of arrays that are passed to
// drupal_attach_tabledrag(). Table::preRenderTable() prepends the HTML ID
// of the table to each set of options.
// @see drupal_attach_tabledrag()
'#tabledrag' => [],
// Render properties.
'#pre_render' => [
[
static::class,
'preRenderTable',
],
],
'#theme' => 'table',
];
}
/**
* {@inheritdoc}
*/
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
// If #multiple is FALSE, the regular default value of radio buttons is
// used.
if (!empty($element['#tableselect']) && !empty($element['#multiple'])) {
// Contrary to #type 'checkboxes', the default value of checkboxes in a
// table is built from the array keys (instead of array values) of the
// #default_value property.
// @todo D8: Remove this inconsistency.
if ($input === FALSE) {
$element += [
'#default_value' => [],
];
$value = array_keys(array_filter($element['#default_value']));
return array_combine($value, $value);
}
else {
return is_array($input) ? array_combine($input, $input) : [];
}
}
}
/**
* Render API callback: Adds tableselect support to #type 'table'.
*
* This function is assigned as a #process callback.
*
* @param array $element
* An associative array containing the properties and children of the
* table element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param array $complete_form
* The complete form structure.
*
* @return array
* The processed element.
*/
public static function processTable(&$element, FormStateInterface $form_state, &$complete_form) {
if ($element['#tableselect']) {
if ($element['#multiple']) {
$value = is_array($element['#value']) ? $element['#value'] : [];
}
else {
$element['#js_select'] = FALSE;
}
// Add a "Select all" checkbox column to the header.
// @todo D8: Rename into #select_all?
if ($element['#js_select']) {
$element['#attached']['library'][] = 'core/drupal.tableselect';
array_unshift($element['#header'], [
'class' => [
'select-all',
],
]);
}
else {
array_unshift($element['#header'], '');
}
if (!isset($element['#default_value']) || $element['#default_value'] === 0) {
$element['#default_value'] = [];
}
// Create a checkbox or radio for each row in a way that the value of the
// tableselect element behaves as if it had been of #type checkboxes or
// radios.
foreach (Element::children($element) as $key) {
$row =& $element[$key];
// Prepare the element #parents for the tableselect form element.
// Their values have to be located in child keys (#tree is ignored),
// since Table::validateTable() has to be able to validate whether input
// (for the parent #type 'table' element) has been submitted.
$element_parents = array_merge($element['#parents'], [
$key,
]);
// Since the #parents of the tableselect form element will equal the
// #parents of the row element, prevent FormBuilder from auto-generating
// an #id for the row element, since
// \Drupal\Component\Utility\Html::getUniqueId() would automatically
// append a suffix to the tableselect form element's #id otherwise.
$row['#id'] = HtmlUtility::getUniqueId('edit-' . implode('-', $element_parents) . '-row');
// Do not overwrite manually created children.
if (!isset($row['select'])) {
// Determine option label; either an assumed 'title' column, or the
// first available column containing a #title or #markup.
// @todo Consider to add an optional $element[$key]['#title_key']
// defaulting to 'title'?
unset($label_element);
$title = NULL;
if (isset($row['title']['#type']) && $row['title']['#type'] == 'label') {
$label_element =& $row['title'];
}
else {
if (!empty($row['title']['#title'])) {
$title = $row['title']['#title'];
}
else {
foreach (Element::children($row) as $column) {
if (isset($row[$column]['#title'])) {
$title = $row[$column]['#title'];
break;
}
if (isset($row[$column]['#markup'])) {
$title = $row[$column]['#markup'];
break;
}
}
}
if (isset($title) && $title !== '') {
$title = t('Update @title', [
'@title' => $title,
]);
}
}
// Prepend the select column to existing columns.
$row = [
'select' => [],
] + $row;
$row['select'] += [
'#type' => $element['#multiple'] ? 'checkbox' : 'radio',
'#id' => HtmlUtility::getUniqueId('edit-' . implode('-', $element_parents)),
// @todo If rows happen to use numeric indexes instead of string
// keys, this results in a first row with $key === 0, which is
// always FALSE.
'#return_value' => $key,
'#attributes' => $element['#attributes'],
'#wrapper_attributes' => [
'class' => [
'table-select',
],
],
];
if ($element['#multiple']) {
$row['select']['#default_value'] = isset($value[$key]) ? $key : NULL;
$row['select']['#parents'] = $element_parents;
}
else {
$row['select']['#default_value'] = $element['#default_value'] == $key ? $key : NULL;
$row['select']['#parents'] = $element['#parents'];
}
if (isset($label_element)) {
$label_element['#id'] = $row['select']['#id'] . '--label';
$label_element['#for'] = $row['select']['#id'];
$row['select']['#attributes']['aria-labelledby'] = $label_element['#id'];
$row['select']['#title_display'] = 'none';
}
else {
$row['select']['#title'] = $title;
$row['select']['#title_display'] = 'invisible';
}
}
}
}
return $element;
}
/**
* Render API callback: Validates the #type 'table'.
*
* This function is assigned as a #element_validate callback.
*
* @param array $element
* An associative array containing the properties and children of the
* table element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param array $complete_form
* The complete form structure.
*/
public static function validateTable(&$element, FormStateInterface $form_state, &$complete_form) {
// Skip this validation if the button to submit the form does not require
// selected table row data.
$triggering_element = $form_state->getTriggeringElement();
if (empty($triggering_element['#tableselect'])) {
return;
}
if ($element['#multiple']) {
if (!is_array($element['#value']) || !count(array_filter($element['#value']))) {
$form_state->setError($element, t('No items selected.'));
}
}
elseif (!isset($element['#value']) || $element['#value'] === '') {
$form_state->setError($element, t('No item selected.'));
}
}
/**
* Render API callback: Transform children of an element of #type 'table'.
*
* This function is assigned as a #pre_render callback.
*
* This function converts sub-elements of an element of #type 'table' to be
* suitable for table.html.twig:
* - The first level of sub-elements are table rows. Only the #attributes
* property is taken into account.
* - The second level of sub-elements is converted into columns for the
* corresponding first-level table row.
*
* Simple example usage:
*
* @code
* $form['table'] = [
* '#type' => 'table',
* '#header' => [$this->t('Title'), ['data' => $this->t('Operations'), 'colspan' => '1']],
* // Optionally, to add tableDrag support:
* '#tabledrag' => [
* [
* 'action' => 'order',
* 'relationship' => 'sibling',
* 'group' => 'thing-weight',
* ],
* ],
* ];
* foreach ($things as $row => $thing) {
* $form['table'][$row]['#weight'] = $thing['weight'];
*
* $form['table'][$row]['title'] = [
* '#type' => 'textfield',
* '#default_value' => $thing['title'],
* ];
*
* // Optionally, to add tableDrag support:
* $form['table'][$row]['#attributes']['class'][] = 'draggable';
* $form['table'][$row]['weight'] = [
* '#type' => 'textfield',
* '#title' => $this->t('Weight for @title', ['@title' => $thing['title']]),
* '#title_display' => 'invisible',
* '#size' => 4,
* '#default_value' => $thing['weight'],
* '#attributes' => ['class' => ['thing-weight']],
* );
*
* // The amount of link columns should be identical to the 'colspan'
* // attribute in #header above.
* $form['table'][$row]['edit'] = [
* '#type' => 'link',
* '#title' => $this->t('Edit'),
* '#url' => Url::fromRoute('entity.test_entity.edit_form', ['test_entity' => $row]),
* ];
* }
* @endcode
*
* @param array $element
* 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
* Associative array of rendered child elements for a table.
*
* @see template_preprocess_table()
* @see \Drupal\Core\Render\AttachmentsResponseProcessorInterface::processAttachments()
* @see drupal_attach_tabledrag()
*/
public static function preRenderTable($element) {
foreach (Element::children($element) as $first) {
$row = [
'data' => [],
];
// Apply attributes of first-level elements as table row attributes.
if (isset($element[$first]['#attributes'])) {
$row += $element[$first]['#attributes'];
}
// Turn second-level elements into table row columns.
// @todo Do not render a cell for children of #type 'value'.
// @see https://www.drupal.org/node/1248940
foreach (Element::children($element[$first]) as $second) {
// Assign the element by reference, so any potential changes to the
// original element are taken over.
$column = [
'data' => &$element[$first][$second],
];
// Apply wrapper attributes of second-level elements as table cell
// attributes.
if (isset($element[$first][$second]['#wrapper_attributes'])) {
$column += $element[$first][$second]['#wrapper_attributes'];
}
$row['data'][] = $column;
}
$element['#rows'][] = $row;
}
// Take over $element['#id'] as HTML ID attribute, if not already set.
Element::setAttributes($element, [
'id',
]);
// Add sticky headers, if applicable.
if (count($element['#header']) && $element['#sticky']) {
$element['#attached']['library'][] = 'core/drupal.tableheader';
$element['#attributes']['class'][] = 'sticky-header';
}
// If the table has headers and it should react responsively to columns
// hidden with the classes represented by the constants
// RESPONSIVE_PRIORITY_MEDIUM and RESPONSIVE_PRIORITY_LOW, add the
// tableresponsive behaviors.
if (count($element['#header']) && $element['#responsive']) {
$element['#attached']['library'][] = 'core/drupal.tableresponsive';
// Add 'responsive-enabled' class to the table to identify it for JS.
// This is needed to target tables constructed by this function.
$element['#attributes']['class'][] = 'responsive-enabled';
}
// 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.
if (!empty($element['#tabledrag']) && isset($element['#attributes']['id'])) {
foreach ($element['#tabledrag'] as $options) {
$options['table_id'] = $element['#attributes']['id'];
drupal_attach_tabledrag($element, $options);
}
}
return $element;
}
}
Members
Title Sort descending | Deprecated | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|---|
DependencySerializationTrait::$_entityStorages | protected | property | An array of entity type IDs keyed by the property name of their storages. | |||
DependencySerializationTrait::$_serviceIds | protected | property | An array of service IDs keyed by property name used for serialization. | |||
FormElementBase::processAutocomplete | public static | function | Adds autocomplete functionality to elements. | 1 | ||
FormElementBase::processPattern | public static | function | Render API callback: Handles the #pattern form element property. | 1 | ||
FormElementBase::validatePattern | public static | function | Render API callback: Handles the #pattern form element property.. | 1 | ||
MessengerTrait::$messenger | protected | property | The messenger. | 25 | ||
MessengerTrait::messenger | public | function | Gets the messenger. | 25 | ||
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 | Deprecated | public | function | Determines if the plugin is configurable. | ||
RenderElementBase::$renderParent | protected | property | The parent element. | |||
RenderElementBase::$renderParentName | protected | property | The parent key. | |||
RenderElementBase::$storage | protected | property | The storage. | |||
RenderElementBase::addChild | public | function | Adds a child render element. | Overrides ElementInterface::addChild | ||
RenderElementBase::changeType | public | function | Change the type of the element. | Overrides ElementInterface::changeType | ||
RenderElementBase::create | public static | function | Creates an instance of the plugin. | Overrides ContainerFactoryPluginInterface::create | 2 | |
RenderElementBase::createChild | public | function | Creates a render object and attaches it to the current render object. | Overrides ElementInterface::createChild | ||
RenderElementBase::elementInfoManager | protected | function | Returns the element info manager. | |||
RenderElementBase::getChild | public | function | Gets a child. | Overrides ElementInterface::getChild | ||
RenderElementBase::getChildren | public | function | Returns child elements. | Overrides ElementInterface::getChildren | ||
RenderElementBase::initializeInternalStorage | public | function | Initialize storage. | Overrides ElementInterface::initializeInternalStorage | ||
RenderElementBase::preRenderAjaxForm | public static | function | Adds Ajax information about an element to communicate with JavaScript. | 2 | ||
RenderElementBase::preRenderGroup | public static | function | Adds members of this group as actual elements for rendering. | 2 | ||
RenderElementBase::processAjaxForm | public static | function | Form element processing handler for the #ajax form property. | 3 | ||
RenderElementBase::processGroup | public static | function | Arranges elements into groups. | 2 | ||
RenderElementBase::removeChild | public | function | Removes a child. | Overrides ElementInterface::removeChild | ||
RenderElementBase::setAttributes | public static | function | Sets a form element's class attribute. | Overrides ElementInterface::setAttributes | 2 | |
RenderElementBase::setType | protected | function | Set type on initialize. | 1 | ||
RenderElementBase::toRenderable | public | function | Returns a render array. | Overrides ElementInterface::toRenderable | ||
RenderElementBase::__construct | public | function | Constructs a new render element object. | Overrides PluginBase::__construct | 6 | |
RenderElementBase::__get | public | function | Magic method: gets a property value. | |||
RenderElementBase::__isset | public | function | Magic method: checks if a property value is set. | |||
RenderElementBase::__set | public | function | Magic method: Sets a property value. | |||
RenderElementBase::__sleep | public | function | Overrides DependencySerializationTrait::__sleep | |||
RenderElementBase::__unset | public | function | Magic method: unsets a property value. | |||
RenderElementBase::__wakeup | public | function | Overrides DependencySerializationTrait::__wakeup | |||
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. | 2 | ||
StringTranslationTrait::t | protected | function | Translates a string to the current language or to a given language. | 1 | ||
Table::getInfo | public | function | Returns the element properties for this element. | Overrides ElementInterface::getInfo | 2 | |
Table::preRenderTable | public static | function | Render API callback: Transform children of an element of #type 'table'. | |||
Table::processTable | public static | function | Render API callback: Adds tableselect support to #type 'table'. | |||
Table::validateTable | public static | function | Render API callback: Validates the #type 'table'. | |||
Table::valueCallback | public static | function | Determines how user input is mapped to an element's #value property. | Overrides FormElementBase::valueCallback | 1 |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.