/** * Tests DefaultTableMapping::getFieldTableName(). * * @covers ::getFieldTableName */ public function testGetFieldTableName() { // Test the field table name for a single-valued base field, which is stored // in the entity's base table. $expected = 'entity_test_mulrev'; $this->assertEquals($this->tableMapping->getFieldTableName('uuid'), $expected); // Test the field table name for a translatable and revisionable base field, // which is stored in the entity's data table. $expected = 'entity_test_mulrev_property_data'; $this->assertEquals($this->tableMapping->getFieldTableName('name'), $expected); // Test the field table name for a multi-valued base field, which is stored // in a dedicated table. $expected = 'entity_test_mulrev__multivalued_base_field'; $this->assertEquals($this->tableMapping->getFieldTableName('multivalued_base_field'), $expected); }
/** * {@inheritdoc} */ public function getTableMapping() { if (!isset($this->tableMapping)) { $definitions = array_filter($this->getFieldStorageDefinitions(), function (FieldStorageDefinitionInterface $definition) { // @todo Remove the check for FieldDefinitionInterface::isMultiple() when // multiple-value base fields are supported in // https://drupal.org/node/2248977. return !$definition->hasCustomStorage() && !$definition->isMultiple(); }); $this->tableMapping = new DefaultTableMapping($definitions); $key_fields = array_values(array_filter(array($this->idKey, $this->revisionKey, $this->bundleKey, $this->uuidKey, $this->langcodeKey))); $all_fields = array_keys($definitions); $revisionable_fields = array_keys(array_filter($definitions, function (FieldStorageDefinitionInterface $definition) { return $definition->isRevisionable(); })); // Make sure the key fields come first in the list of fields. $all_fields = array_merge($key_fields, array_diff($all_fields, $key_fields)); // Nodes have all three of these fields, while custom blocks only have // log. // @todo Provide automatic definitions for revision metadata fields in // https://drupal.org/node/2248983. $revision_metadata_fields = array_intersect(array('revision_timestamp', 'revision_uid', 'revision_log'), $all_fields); $revisionable = $this->entityType->isRevisionable(); // @todo Remove the data table check once all entity types are using // entity query and we have a views data controller. See: // - https://drupal.org/node/2068325 // - https://drupal.org/node/1740492 $translatable = $this->entityType->getDataTable() && $this->entityType->isTranslatable(); if (!$revisionable && !$translatable) { // The base layout stores all the base field values in the base table. $this->tableMapping->setFieldNames($this->baseTable, $all_fields); } elseif ($revisionable && !$translatable) { // The revisionable layout stores all the base field values in the base // table, except for revision metadata fields. Revisionable fields // denormalized in the base table but also stored in the revision table // together with the entity ID and the revision ID as identifiers. $this->tableMapping->setFieldNames($this->baseTable, array_diff($all_fields, $revision_metadata_fields)); $revision_key_fields = array($this->idKey, $this->revisionKey); $this->tableMapping->setFieldNames($this->revisionTable, array_merge($revision_key_fields, $revisionable_fields)); } elseif (!$revisionable && $translatable) { // Multilingual layouts store key field values in the base table. The // other base field values are stored in the data table, no matter // whether they are translatable or not. The data table holds also a // denormalized copy of the bundle field value to allow for more // performant queries. This means that only the UUID is not stored on // the data table. $this->tableMapping->setFieldNames($this->baseTable, $key_fields)->setFieldNames($this->dataTable, array_values(array_diff($all_fields, array($this->uuidKey))))->setExtraColumns($this->dataTable, array('default_langcode')); } elseif ($revisionable && $translatable) { // The revisionable multilingual layout stores key field values in the // base table, except for language, which is stored in the revision // table along with revision metadata. The revision data table holds // data field values for all the revisionable fields and the data table // holds the data field values for all non-revisionable fields. The data // field values of revisionable fields are denormalized in the data // table, as well. $this->tableMapping->setFieldNames($this->baseTable, array_values(array_diff($key_fields, array($this->langcodeKey)))); // Like in the multilingual, non-revisionable case the UUID is not // in the data table. Additionally, do not store revision metadata // fields in the data table. $data_fields = array_values(array_diff($all_fields, array($this->uuidKey), $revision_metadata_fields)); $this->tableMapping->setFieldNames($this->dataTable, $data_fields)->setExtraColumns($this->dataTable, array('default_langcode')); $revision_base_fields = array_merge(array($this->idKey, $this->revisionKey, $this->langcodeKey), $revision_metadata_fields); $this->tableMapping->setFieldNames($this->revisionTable, $revision_base_fields); $revision_data_key_fields = array($this->idKey, $this->revisionKey, $this->langcodeKey); $revision_data_fields = array_diff($revisionable_fields, $revision_metadata_fields); $this->tableMapping->setFieldNames($this->revisionDataTable, array_merge($revision_data_key_fields, $revision_data_fields))->setExtraColumns($this->revisionDataTable, array('default_langcode')); } } return $this->tableMapping; }
/** * Puts the views data for a single field onto the views data. * * @param string $table * The table of the field to handle. * @param string $field_name * The name of the field to handle. * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition defined in Entity::baseFieldDefinitions() * @param \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping * The table mapping information * @param array $table_data * A reference to a specific entity table (for example data_table) inside * the views data. */ protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterface $field_definition, TableMappingInterface $table_mapping, &$table_data) { // Create a dummy instance to retrieve property definitions. $field_column_mapping = $table_mapping->getColumnNames($field_name); $field_schema = $this->getFieldStorageDefinitions()[$field_name]->getSchema(); $field_definition_type = $field_definition->getType(); // Add all properties to views table data. We need an entry for each // column of each field, with the first one given special treatment. // @todo Introduce concept of the "main" column for a field, rather than // assuming the first one is the main column. See also what the // mapSingleFieldViewsData() method does with $first. $multiple = count($field_column_mapping) > 1; $first = TRUE; foreach ($field_column_mapping as $field_column_name => $schema_field_name) { $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); $table_data[$views_field_name]['entity field'] = $field_name; $first = FALSE; } }