diff --git a/core/modules/taxonomy/src/TermViewsData.php b/core/modules/taxonomy/src/TermViewsData.php index 8c9f37a..4003640 100644 --- a/core/modules/taxonomy/src/TermViewsData.php +++ b/core/modules/taxonomy/src/TermViewsData.php @@ -7,27 +7,21 @@ namespace Drupal\taxonomy; -use Drupal\views\EntityViewsDataInterface; +use Drupal\views\EntityViewsData; /** * Provides the views data for the taxonomy entity type. */ -class TermViewsData implements EntityViewsDataInterface { +class TermViewsData extends EntityViewsData { /** * {@inheritdoc} */ public function getViewsData() { - $data = array(); - - $data['taxonomy_term_data']['table']['group'] = t('Taxonomy term'); - $data['taxonomy_term_data']['table']['base'] = array( - 'field' => 'tid', - 'title' => t('Term'), - 'help' => t('Taxonomy terms are attached to nodes.'), - 'access query tag' => 'term_access', - ); - $data['taxonomy_term_data']['table']['entity type'] = 'taxonomy_term'; + $data = parent::getViewsData(); + + $data['taxonomy_term_data']['table']['base']['help'] = t('Taxonomy terms are attached to nodes.'); + $data['taxonomy_term_data']['table']['base']['access query tag'] = 'term_access'; $data['taxonomy_term_data']['table']['wizard_id'] = 'taxonomy_term'; $data['taxonomy_term_data']['table']['join'] = array( @@ -38,36 +32,17 @@ public function getViewsData() { ), ); - $data['taxonomy_term_field_data']['table']['group'] = t('Taxonomy term'); - $data['taxonomy_term_field_data']['table']['entity type'] = 'taxonomy_term'; - $data['taxonomy_term_field_data']['table']['join']['taxonomy_term_data'] = array( - 'type' => 'INNER', - 'left_field' => 'tid', - 'field' => 'tid', - ); + $data['taxonomy_term_data']['tid']['help'] = t('The tid of a taxonomy term.'); - $data['taxonomy_term_data']['tid'] = array( - 'title' => t('Term ID'), - 'help' => t('The tid of a taxonomy term.'), - 'field' => array( - 'id' => 'numeric', - ), - 'sort' => array( - 'id' => 'standard', - ), - 'argument' => array( - 'id' => 'taxonomy', - 'name field' => 'name', - 'zero is null' => TRUE, - ), - 'filter' => array( - 'title' => t('Term'), - 'help' => t('Taxonomy term chosen from autocomplete or select widget.'), - 'id' => 'taxonomy_index_tid', - 'hierarchy table' => 'taxonomy_term_hierarchy', - 'numeric' => TRUE, - ), - ); + $data['taxonomy_term_data']['tid']['argument']['id'] = 'taxonomy'; + $data['taxonomy_term_data']['tid']['argument']['name field'] = 'name'; + $data['taxonomy_term_data']['tid']['argument']['zero is null'] = TRUE; + + $data['taxonomy_term_data']['tid']['filter']['id'] = 'taxonomy_index_tid'; + $data['taxonomy_term_data']['tid']['filter']['title'] = t('Term'); + $data['taxonomy_term_data']['tid']['filter']['help'] = t('Taxonomy term chosen from autocomplete or select widget.'); + $data['taxonomy_term_data']['tid']['filter']['hierarchy table'] = 'taxonomy_term_hierarchy'; + $data['taxonomy_term_data']['tid']['filter']['numeric'] = TRUE; $data['taxonomy_term_data']['tid_raw'] = array( 'title' => t('Term ID'), @@ -95,81 +70,10 @@ public function getViewsData() { ), ); - $data['taxonomy_term_field_data']['name'] = array( - 'title' => t('Name'), - 'help' => t('The taxonomy term name.'), - 'field' => array( - 'id' => 'taxonomy', - ), - 'sort' => array( - 'id' => 'standard', - ), - 'filter' => array( - 'id' => 'string', - 'help' => t('Taxonomy term name.'), - ), - 'argument' => array( - 'id' => 'string', - 'help' => t('Taxonomy term name.'), - 'many to one' => TRUE, - 'empty field name' => t('Uncategorized'), - ), - ); - - $data['taxonomy_term_field_data']['weight'] = array( - 'title' => t('Weight'), - 'help' => t('The term weight field'), - 'field' => array( - 'id' => 'numeric', - ), - 'sort' => array( - 'id' => 'standard', - ), - 'filter' => array( - 'id' => 'numeric', - ), - 'argument' => array( - 'id' => 'numeric', - ), - ); - - $data['taxonomy_term_field_data']['description__value'] = array( - 'title' => t('Term description'), - 'help' => t('The description associated with a taxonomy term.'), - 'field' => array( - 'id' => 'markup', - 'format' => array('field' => 'description__format'), - 'click sortable' => FALSE, - ), - 'filter' => array( - 'id' => 'string', - ), - ); - - $data['taxonomy_term_data']['vid'] = array( - 'title' => t('Vocabulary'), - 'help' => t('Filter the results of "Taxonomy: Term" to a particular vocabulary.'), - 'filter' => array( - 'id' => 'bundle', - ), - ); - - $data['taxonomy_term_field_data']['langcode'] = array( - 'title' => t('Language'), // The item it appears as on the UI, - 'help' => t('Language of the term'), - 'field' => array( - 'id' => 'taxonomy_term_language', - ), - 'sort' => array( - 'id' => 'standard', - ), - 'filter' => array( - 'id' => 'language', - ), - 'argument' => array( - 'id' => 'language', - ), - ); + $data['taxonomy_term_data']['vid']['help'] = t('Filter the results of "Taxonomy: Term" to a particular vocabulary.'); + unset($data['taxonomy_term_data']['vid']['field']); + unset($data['taxonomy_term_data']['vid']['argument']); + unset($data['taxonomy_term_data']['vid']['sort']); $data['taxonomy_term_data']['edit_term'] = array( 'field' => array( @@ -180,19 +84,26 @@ public function getViewsData() { ), ); - $data['taxonomy_term_field_data']['changed'] = array( - 'title' => t('Updated date'), - 'help' => t('The date the term was last updated.'), - 'field' => array( - 'id' => 'date', - ), - 'sort' => array( - 'id' => 'date' - ), - 'filter' => array( - 'id' => 'date', - ), - ); + if (\Drupal::moduleHandler()->moduleExists('content_translation')) { + $data['taxonomy_term_data']['translation_link'] = array( + 'title' => t('Translation link'), + 'help' => t('Provide a link to the translations overview for taxonomy terms.'), + 'field' => array( + 'id' => 'content_translation_link', + ), + ); + } + + $data['taxonomy_term_field_data']['name']['field']['id'] = 'taxonomy'; + $data['taxonomy_term_field_data']['name']['argument']['many to one'] = TRUE; + $data['taxonomy_term_field_data']['name']['argument']['empty field name'] = t('Uncategorized'); + + $data['taxonomy_term_field_data']['description__value']['field']['click sortable'] = FALSE; + + $data['taxonomy_term_field_data']['langcode']['field']['id'] = 'taxonomy_term_language'; + + $data['taxonomy_term_field_data']['changed']['title'] = t('Updated date'); + $data['taxonomy_term_field_data']['changed']['help'] = t('The date the term was last updated.'); $data['taxonomy_term_field_data']['changed_fulldate'] = array( 'title' => t('Updated date'), @@ -248,16 +159,6 @@ public function getViewsData() { ), ); - if (\Drupal::moduleHandler()->moduleExists('content_translation')) { - $data['taxonomy_term_data']['translation_link'] = array( - 'title' => t('Translation link'), - 'help' => t('Provide a link to the translations overview for taxonomy terms.'), - 'field' => array( - 'id' => 'content_translation_link', - ), - ); - } - $data['taxonomy_index']['table']['group'] = t('Taxonomy term'); $data['taxonomy_index']['table']['join'] = array( @@ -314,30 +215,30 @@ public function getViewsData() { ); - $data['taxonomy_index']['sticky'] = [ - 'title' => t('Sticky status'), - 'help' => t('Whether or not the content related to a term is sticky.'), - 'filter' => [ - 'id' => 'boolean', - 'label' => t('Sticky status'), - 'type' => 'yes-no', - ], - 'sort' => [ - 'id' => 'standard', - 'help' => t('Whether or not the content related to a term is sticky. To list sticky content first, set this to descending.'), - ], - ]; - - $data['taxonomy_index']['created'] = [ - 'title' => t('Post date'), - 'help' => t('The date the content related to a term was posted.'), - 'sort' => [ - 'id' => 'date' - ], - 'filter' => [ - 'id' => 'date', - ], - ]; + $data['taxonomy_index']['sticky'] = [ + 'title' => t('Sticky status'), + 'help' => t('Whether or not the content related to a term is sticky.'), + 'filter' => [ + 'id' => 'boolean', + 'label' => t('Sticky status'), + 'type' => 'yes-no', + ], + 'sort' => [ + 'id' => 'standard', + 'help' => t('Whether or not the content related to a term is sticky. To list sticky content first, set this to descending.'), + ], + ]; + + $data['taxonomy_index']['created'] = [ + 'title' => t('Post date'), + 'help' => t('The date the content related to a term was posted.'), + 'sort' => [ + 'id' => 'date' + ], + 'filter' => [ + 'id' => 'date', + ], + ]; $data['taxonomy_term_hierarchy']['table']['group'] = t('Taxonomy term'); @@ -377,4 +278,3 @@ public function getViewsData() { } } - diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php index 2477885..96c7064 100644 --- a/core/modules/views/src/EntityViewsData.php +++ b/core/modules/views/src/EntityViewsData.php @@ -226,22 +226,12 @@ protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterf $field_definition_type = $field_definition->getType(); // Add all properties to views table data. + $multiple = (count($field_column_mapping) > 1); $first = TRUE; foreach ($field_column_mapping as $field_column_name => $schema_field_name) { - $schema = $field_schema['columns'][$field_column_name]; - // We want to both have an entry in the views data for the actual field, - // but also each additional schema field, for example the file - // description. - // @todo Introduce a concept of the "main" schema field for a field item. - // This would be the FID for a file reference for example. - // @see https://www.drupal.org/node/2337517 - if ($first) { - $first = FALSE; - $table_data[$field_name] = $this->mapSingleFieldViewsData($table, $field_definition_type, $schema_field_name, $field_definition, TRUE); - } - else { - $table_data["$field_name.$field_column_name"] = $this->mapSingleFieldViewsData($table, $schema['type'], $schema_field_name, $field_definition, FALSE); - } + $views_field_name = ($multiple) ? $field_name . '__' . $field_column_name : $field_name; + $table_data[$views_field_name] = $this->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition); + $first = FALSE; } } @@ -250,111 +240,117 @@ protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterf * * @param string $table * The table of the field to handle. - * @param string $data_type - * The data type to generate views data for, for example "int". The data - * type comes directly from the schema definition of each field item. - * @param string $schema_field_name - * The schema field name. + * @param string $field_name + * The machine name of the field being processed. + * @param string $field_type + * The type of field being handled. + * @param string $column_name + * For fields containing multiple columns, the column name being processed. + * @param string $column_type + * Within the field, the column type being handled. + * @param bool $first + * TRUE if this is the first column within the field. * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition. - * @param bool $first - * Is it the first column of the schema. * * @return array * The modified views data field definition. */ - protected function mapSingleFieldViewsData($table, $data_type, $schema_field_name, FieldDefinitionInterface $field_definition, $first) { + protected function mapSingleFieldViewsData($table, $field_name, $field_type, $column_name, $column_type, $first, FieldDefinitionInterface $field_definition) { $views_field = array(); - // Provide a nicer, less verbose label for the first field. + // Provide a nicer, less verbose label for the first column within a field. if ($first) { $views_field['title'] = $field_definition->getLabel(); } else { - $views_field['title'] = $field_definition->getLabel() . " ($schema_field_name)"; + $views_field['title'] = $field_definition->getLabel() . " ($column_name)"; } if ($description = $field_definition->getDescription()) { $views_field['help'] = $description; } + // Set up the field, sort, argument, and filters, based on + // the column and/or field data type. // @todo Allow field types to customize this. // @see https://www.drupal.org/node/2337515 - switch ($data_type) { - case 'int': - case 'integer': - case 'smallint': - case 'tinyint': - case 'mediumint': - case 'float': - case 'double': - case 'decimal': - $views_field['field']['id'] = 'numeric'; - $views_field['argument']['id'] = 'numeric'; - $views_field['filter']['id'] = 'numeric'; - $views_field['sort']['id'] = 'standard'; - break; - case 'char': - case 'string': - case 'varchar': - case 'tinytext': - case 'text': - case 'mediumtext': - case 'longtext': - $views_field['field']['id'] = 'standard'; - $views_field['argument']['id'] = 'string'; - $views_field['filter']['id'] = 'string'; - $views_field['sort']['id'] = 'standard'; - break; - case 'boolean': - $views_field['field']['id'] = 'boolean'; - $views_field['argument']['id'] = 'numeric'; - $views_field['filter']['id'] = 'boolean'; - $views_field['sort']['id'] = 'standard'; - break; - case 'uuid': - $views_field['field']['id'] = 'standard'; - $views_field['argument']['id'] = 'string'; - $views_field['filter']['id'] = 'string'; - $views_field['sort']['id'] = 'standard'; + switch ($field_type) { + + // Special case a few field types. + + case 'timestamp': + case 'created': + case 'changed': + $views_field['field']['id'] = 'date'; + $views_field['argument']['id'] = 'date'; + $views_field['filter']['id'] = 'date'; + $views_field['sort']['id'] = 'date'; break; + case 'language': $views_field['field']['id'] = 'language'; $views_field['argument']['id'] = 'language'; $views_field['filter']['id'] = 'language'; $views_field['sort']['id'] = 'standard'; break; - case 'created': - case 'changed': - $views_field['field']['id'] = 'date'; - $views_field['argument']['id'] = 'date'; - $views_field['filter']['id'] = 'date'; - $views_field['sort']['id'] = 'date'; - break; - case 'entity_reference': - // @todo Should the actual field handler respect that this is just renders a number - // @todo Create an optional entity field handler, that can render the - // entity. - // @see https://www.drupal.org/node/2322949 - $views_field['field']['id'] = 'standard'; - $views_field['argument']['id'] = 'standard'; - $views_field['filter']['id'] = 'standard'; - $views_field['sort']['id'] = 'standard'; - break; - case 'uri': - $views_field['field']['id'] = 'standard'; - $views_field['argument']['id'] = 'string'; - $views_field['filter']['id'] = 'string'; + + case 'boolean': + $views_field['field']['id'] = 'boolean'; + $views_field['argument']['id'] = 'numeric'; + $views_field['filter']['id'] = 'boolean'; $views_field['sort']['id'] = 'standard'; break; + + case 'text': + case 'text_with_summary': + // Treat these three long text fields the same. + $field_type = 'long_text'; + // Intentional fall-through here to the default processing! + default: - $views_field['field']['id'] = 'standard'; - $views_field['argument']['id'] = 'standard'; - $views_field['filter']['id'] = 'standard'; - $views_field['sort']['id'] = 'standard'; + // For most fields, the field type is generic enough to just use + // the column type to determine the filters etc. + switch ($column_type) { + + case 'int': + case 'integer': + case 'smallint': + case 'tinyint': + case 'mediumint': + case 'float': + case 'double': + case 'decimal': + $views_field['field']['id'] = 'numeric'; + $views_field['argument']['id'] = 'numeric'; + $views_field['filter']['id'] = 'numeric'; + $views_field['sort']['id'] = 'standard'; + break; + + case 'char': + case 'string': + case 'varchar': + case 'tinytext': + case 'text': + case 'mediumtext': + case 'longtext': + $views_field['field']['id'] = 'standard'; + $views_field['argument']['id'] = 'string'; + $views_field['filter']['id'] = 'string'; + $views_field['sort']['id'] = 'standard'; + break; + + default: + $views_field['field']['id'] = 'standard'; + $views_field['argument']['id'] = 'standard'; + $views_field['filter']['id'] = 'standard'; + $views_field['sort']['id'] = 'standard'; + } } - $process_method = 'processViewsDataFor' . Container::camelize($data_type); + // Do post-processing for a few field types. + + $process_method = 'processViewsDataFor' . Container::camelize($field_type); if (method_exists($this, $process_method)) { $this->{$process_method}($table, $field_definition, $views_field); } @@ -395,6 +391,13 @@ protected function processViewsDataForLanguage($table, FieldDefinitionInterface * The views field data. */ protected function processViewsDataForEntityReference($table, FieldDefinitionInterface $field_definition, array &$views_field) { + + // @todo Should the actual field handler respect that this just renders a + // number? + // @todo Create an optional entity field handler, that can render the + // entity. + // @see https://www.drupal.org/node/2322949 + if ($entity_type_id = $field_definition->getItemDefinition()->getSetting('target_type')) { $entity_type = $this->entityManager->getDefinition($entity_type_id); if ($entity_type instanceof ContentEntityType) { @@ -426,6 +429,26 @@ protected function processViewsDataForEntityReference($table, FieldDefinitionInt } /** + * Processes the views data for a text field with formatting. + * + * @param string $table + * The table the language field is added to. + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition. + * @param array $views_field + * The views field data. + * @param string $field_column_name + * The field column being processed. + */ + protected function processViewsDataForLongText(array &$views_field, $field_column_name, $field_base_name) { + // Connect the text field to its formatter. + if ($field_column_name == 'value') { + $views_field['field']['format'] = $field_base_name . '__format'; + $views_field['field']['id'] = 'markup'; + } + } + + /** * Gets the table of an entity type to be used as base table in views. * * @todo Given that the base_table is pretty much useless as you often have to