Commit dcc880bc authored by webchick's avatar webchick

Issue #2326719 by plach, effulgentsia: Move pseudo-private table mapping...

Issue #2326719 by plach, effulgentsia: Move pseudo-private table mapping functions from ContentEntityDatabaseStorage to public API of DefaultTableMapping.
parent ec2b048e
......@@ -10,10 +10,8 @@
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\Core\Entity\Query\QueryException;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\FieldStorageConfigInterface;
/**
......@@ -116,11 +114,14 @@ public function addField($field, $type, $langcode) {
if ($field_storage instanceof FieldStorageConfigInterface) {
// Find the field column.
$column = $field_storage->getMainPropertyName();
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $this->entityManager->getStorage($entity_type_id)->getTableMapping();
if ($key < $count) {
$next = $specifiers[$key + 1];
// Is this a field column?
$columns = $field_storage->getColumns();
if (isset($columns[$next]) || in_array($next, FieldStorageConfig::getReservedColumns())) {
if (isset($columns[$next]) || in_array($next, $table_mapping->getReservedColumns())) {
// Use it.
$column = $next;
// Do not process it again.
......@@ -142,7 +143,7 @@ public function addField($field, $type, $langcode) {
}
}
$table = $this->ensureFieldTable($index_prefix, $field_storage, $type, $langcode, $base_table, $entity_id_field, $field_id_field);
$sql_column = ContentEntityDatabaseStorage::_fieldColumnName($field_storage, $column);
$sql_column = $table_mapping->getFieldColumnName($field_storage, $column);
}
// This is an entity base field (non-configurable field).
else {
......@@ -220,11 +221,13 @@ protected function ensureEntityTable($index_prefix, $property, $type, $langcode,
protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $base_table, $entity_id_field, $field_id_field) {
$field_name = $field->getName();
if (!isset($this->fieldTables[$index_prefix . $field_name])) {
$table = $this->sqlQuery->getMetaData('age') == EntityStorageInterface::FIELD_LOAD_CURRENT ? ContentEntityDatabaseStorage::_fieldTableName($field) : ContentEntityDatabaseStorage::_fieldRevisionTableName($field);
$entity_type_id = $this->sqlQuery->getMetaData('entity_type');
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $this->entityManager->getStorage($entity_type_id)->getTableMapping();
$table = $this->sqlQuery->getMetaData('age') == EntityStorageInterface::FIELD_LOAD_CURRENT ? $table_mapping->getDedicatedDataTableName($field) : $table_mapping->getDedicatedRevisionTableName($field);
if ($field->getCardinality() != 1) {
$this->sqlQuery->addMetaData('simple_query', FALSE);
}
$entity_type = $this->sqlQuery->getMetaData('entity_type');
$this->fieldTables[$index_prefix . $field_name] = $this->addJoin($type, $table, "%alias.$field_id_field = $base_table.$entity_id_field", $langcode);
}
return $this->fieldTables[$index_prefix . $field_name];
......
......@@ -7,6 +7,8 @@
namespace Drupal\Core\Entity\Sql;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
/**
* Defines a default table mapping class.
*/
......@@ -177,4 +179,101 @@ public function setExtraColumns($table_name, array $column_names) {
return $this;
}
/**
* {@inheritdoc}
*/
public function getReservedColumns() {
return array('deleted');
}
/**
* Generates a table name for a field data table.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
* The field storage definition.
* @param bool $is_deleted
* (optional) Whether the table name holding the values of a deleted field
* should be returned.
*
* @return string
* A string containing the generated name for the database table.
*/
public function getDedicatedDataTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) {
if ($is_deleted) {
// When a field is a deleted, the table is renamed to
// {field_deleted_data_FIELD_UUID}. To make sure we don't end up with
// table names longer than 64 characters, we hash the unique storage
// identifier and return the first 10 characters so we end up with a short
// unique ID.
return "field_deleted_data_" . substr(hash('sha256', $storage_definition->getUniqueStorageIdentifier()), 0, 10);
}
else {
return $this->generateFieldTableName($storage_definition, FALSE);
}
}
/**
* Generates a table name for a field revision archive table.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
* The field storage definition.
* @param bool $is_deleted
* (optional) Whether the table name holding the values of a deleted field
* should be returned.
*
* @return string
* A string containing the generated name for the database table.
*/
public function getDedicatedRevisionTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) {
if ($is_deleted) {
// When a field is a deleted, the table is renamed to
// {field_deleted_revision_FIELD_UUID}. To make sure we don't end up with
// table names longer than 64 characters, we hash the unique storage
// identifier and return the first 10 characters so we end up with a short
// unique ID.
return "field_deleted_revision_" . substr(hash('sha256', $storage_definition->getUniqueStorageIdentifier()), 0, 10);
}
else {
return $this->generateFieldTableName($storage_definition, TRUE);
}
}
/**
* Generates a safe and unambiguous field table name.
*
* The method accounts for a maximum table name length of 64 characters, and
* takes care of disambiguation.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
* The field storage definition.
* @param bool $revision
* TRUE for revision table, FALSE otherwise.
*
* @return string
* The final table name.
*/
protected function generateFieldTableName(FieldStorageDefinitionInterface $storage_definition, $revision) {
$separator = $revision ? '_revision__' : '__';
$table_name = $storage_definition->getTargetEntityTypeId() . $separator . $storage_definition->getName();
// Limit the string to 48 characters, keeping a 16 characters margin for db
// prefixes.
if (strlen($table_name) > 48) {
// Use a shorter separator, a truncated entity_type, and a hash of the
// field UUID.
$separator = $revision ? '_r__' : '__';
// Truncate to the same length for the current and revision tables.
$entity_type = substr($storage_definition->getTargetEntityTypeId(), 0, 34);
$field_hash = substr(hash('sha256', $storage_definition->getUniqueStorageIdentifier()), 0, 10);
$table_name = $entity_type . $separator . $field_hash;
}
return $table_name;
}
/**
* {@inheritdoc}
*/
public function getFieldColumnName(FieldStorageDefinitionInterface $storage_definition, $column) {
return in_array($column, $this->getReservedColumns()) ? $column : $storage_definition->getName() . '_' . $column;
}
}
......@@ -7,8 +7,20 @@
namespace Drupal\Core\Entity\Sql;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
/**
* Provides a common interface for mapping field columns to SQL tables.
*
* Warning: using methods provided here should be done only when writing code
* that is explicitly targeting a SQL-based entity storage. Typically this API
* is used by SQL storage classes, or other SQL-specific code like the Views
* integration code for the Entity SQL storage. Another example of legal usage
* of this API is when needing to write a query that \Drupal::entityQuery() does
* not support. Always retrieve entity identifiers and use them to load entities
* instead of accessing data stored in the database directly. Any other usage
* circumvents the entity system and is strongly discouraged, at least when
* writing contributed code.
*/
interface TableMappingInterface {
......@@ -70,4 +82,24 @@ public function getColumnNames($field_name);
*/
public function getExtraColumns($table_name);
/**
* A list of columns that can not be used as field type columns.
*
* @return array
*/
public function getReservedColumns();
/**
* Generates a column name for a field.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
* The field storage definition.
* @param string $column
* The name of the column.
*
* @return string
* A string containing a generated column name for a field data table that is
* unique among all other fields.
*/
public function getFieldColumnName(FieldStorageDefinitionInterface $storage_definition, $column);
}
......@@ -7,7 +7,6 @@
namespace Drupal\contact\Tests\Views;
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\views\Tests\ViewTestBase;
/**
......@@ -60,7 +59,7 @@ protected function setUp() {
public function testViewsData() {
// Test that the field is not exposed to views, since contact_message
// entities have no storage.
$table_name = ContentEntityDatabaseStorage::_fieldTableName($this->field_storage);
$table_name = 'contact_message__' . $this->field_storage->getName();
$data = $this->container->get('views.views_data')->get($table_name);
$this->assertFalse($data, 'The field is not exposed to Views.');
}
......
......@@ -5,7 +5,6 @@
* Provides views data for the entity_reference module.
*/
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\field\FieldStorageConfigInterface;
/**
......@@ -14,6 +13,7 @@
function entity_reference_field_views_data(FieldStorageConfigInterface $field_storage) {
$data = field_views_field_default_views_data($field_storage);
$entity_manager = \Drupal::entityManager();
$table_mapping = $entity_manager->getStorage($field_storage->getTargetEntityTypeId())->getTableMapping();
foreach ($data as $table_name => $table_data) {
// Add a relationship to the target entity type.
$target_entity_type_id = $field_storage->getSetting('target_type');
......@@ -38,13 +38,16 @@ function entity_reference_field_views_data(FieldStorageConfigInterface $field_st
// Provide a reverse relationship for the entity type that is referenced by
// the field.
$pseudo_field_name = 'reverse__' . $field_storage->getTargetEntityTypeId() . '__' . $field_storage->getName();
$entity_type_id = $field_storage->getTargetEntityTypeId();
$pseudo_field_name = 'reverse__' . $entity_type_id . '__' . $field_storage->getName();
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = \Drupal::entityManager()->getStorage($entity_type_id)->getTableMapping();
$data[$target_base_table][$pseudo_field_name]['relationship'] = array(
'title' => t('@label using @field_name', $args),
'help' => t('Relate each @label with a @field_name.', $args),
'id' => 'entity_reverse',
'field_name' => $field_storage->getName(),
'field table' => ContentEntityDatabaseStorage::_fieldTableName($field_storage),
'field table' => $table_mapping->getDedicatedDataTableName($field_storage),
'field field' => $field_storage->getName() . '_target_id',
'base' => $target_entity_type->getBaseTable(),
'base field' => $target_entity_type->getKey('id'),
......
......@@ -22,7 +22,7 @@ function field_views_data() {
$module_handler = \Drupal::moduleHandler();
foreach (\Drupal::entityManager()->getStorage('field_storage_config')->loadMultiple() as $field) {
if (_field_views_is_sql_entity_type($field)) {
if (_field_views_get_entity_type_storage($field)) {
$result = (array) $module_handler->invoke($field->module, 'field_views_data', array($field));
if (empty($result)) {
$result = field_views_field_default_views_data($field);
......@@ -48,7 +48,7 @@ function field_views_data() {
*/
function field_views_data_alter(&$data) {
foreach (\Drupal::entityManager()->getStorage('field_storage_config')->loadMultiple() as $field) {
if (_field_views_is_sql_entity_type($field)) {
if (_field_views_get_entity_type_storage($field)) {
$function = $field->module . '_field_views_data_views_data_alter';
if (function_exists($function)) {
$function($data, $field);
......@@ -63,12 +63,17 @@ function field_views_data_alter(&$data) {
* @param \Drupal\field\FieldStorageConfigInterface $field_storage
* The field storage definition.
*
* @return bool
* True if the entity type uses ContentEntityDatabaseStorage.
* @return \Drupal\Core\Entity\ContentEntityDatabaseStorage
* Returns the entity type storage if supported.
*/
function _field_views_is_sql_entity_type(FieldStorageConfigInterface $field_storage) {
function _field_views_get_entity_type_storage(FieldStorageConfigInterface $field_storage) {
$result = FALSE;
$entity_manager = \Drupal::entityManager();
return $entity_manager->hasDefinition($field_storage->entity_type) && $entity_manager->getStorage($field_storage->entity_type) instanceof ContentEntityDatabaseStorage;
if ($entity_manager->hasDefinition($field_storage->getTargetEntityTypeId())) {
$storage = $entity_manager->getStorage($field_storage->getTargetEntityTypeId());
$result = $storage instanceof ContentEntityDatabaseStorage ? $storage : FALSE;
}
return $result;
}
/**
......@@ -120,6 +125,11 @@ function field_views_field_default_views_data(FieldStorageConfigInterface $field
if (!$field_storage->getBundles()) {
return $data;
}
// Check whether the entity type storage is supported.
$storage = _field_views_get_entity_type_storage($field_storage);
if (!$storage) {
return $data;
}
$field_name = $field_storage->getName();
$field_columns = $field_storage->getColumns();
......@@ -127,7 +137,7 @@ function field_views_field_default_views_data(FieldStorageConfigInterface $field
// Grab information about the entity type tables.
// We need to join to both the base table and the data table, if available.
$entity_manager = \Drupal::entityManager();
$entity_type_id = $field_storage->entity_type;
$entity_type_id = $field_storage->getTargetEntityTypeId();
$entity_type = $entity_manager->getDefinition($entity_type_id);
if (!$base_table = $entity_type->getBaseTable()) {
// We cannot do anything if for some reason there is no base table.
......@@ -150,15 +160,18 @@ function field_views_field_default_views_data(FieldStorageConfigInterface $field
}
// Description of the field tables.
// @todo Generalize this code to make it work with any table layout. See
// https://drupal.org/node/2079019.
$table_mapping = $storage->getTableMapping();
$field_tables = array(
EntityStorageInterface::FIELD_LOAD_CURRENT => array(
'table' => ContentEntityDatabaseStorage::_fieldTableName($field_storage),
'table' => $table_mapping->getDedicatedDataTableName($field_storage),
'alias' => "{$entity_type_id}__{$field_name}",
),
);
if ($supports_revisions) {
$field_tables[EntityStorageInterface::FIELD_LOAD_REVISION] = array(
'table' => ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage),
'table' => $table_mapping->getDedicatedRevisionTableName($field_storage),
'alias' => "{$entity_type_id}_revision__{$field_name}",
);
}
......@@ -220,7 +233,7 @@ function field_views_field_default_views_data(FieldStorageConfigInterface $field
// Build the list of additional fields to add to queries.
$add_fields = array('delta', 'langcode', 'bundle');
foreach (array_keys($field_columns) as $column) {
$add_fields[] = ContentEntityDatabaseStorage::_fieldColumnName($field_storage, $column);
$add_fields[] = $table_mapping->getFieldColumnName($field_storage, $column);
}
// Determine the label to use for the field. We don't have a label available
// at the field level, so we just go through all instances and take the one
......@@ -344,11 +357,10 @@ function field_views_field_default_views_data(FieldStorageConfigInterface $field
else {
$group = t('@group (historical data)', array('@group' => $group_name));
}
$column_real_name = ContentEntityDatabaseStorage::_fieldColumnName($field_storage, $column);
$column_real_name = $table_mapping->getFieldColumnName($field_storage, $column);
// Load all the fields from the table by default.
$field_sql_schema = ContentEntityDatabaseStorage::_fieldSqlSchema($field_storage);
$additional_fields = array_keys($field_sql_schema[$table]['fields']);
$additional_fields = $table_mapping->getAllColumns($table);
$data[$table_alias][$column_real_name] = array(
'group' => $group,
......
......@@ -9,7 +9,6 @@
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
......@@ -353,9 +352,12 @@ public function clickSort($order) {
}
$this->ensureMyTable();
$field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->definition['entity_type']);
$entity_type_id = $this->definition['entity_type'];
$field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id);
$field_storage = $field_storage_definitions[$this->definition['field_name']];
$column = ContentEntityDatabaseStorage::_fieldColumnName($field_storage, $this->options['click_sort_column']);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $this->entityManager->getStorage($entity_type_id)->getTableMapping();
$column = $table_mapping->getFieldColumnName($field_storage, $this->options['click_sort_column']);
if (!isset($this->aliases[$column])) {
// Column is not in query; add a sort on it (without adding the column).
$this->aliases[$column] = $this->tableAlias . '.' . $column;
......
......@@ -7,7 +7,6 @@
namespace Drupal\field\Tests;
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\Core\Entity\EntityInterface;
use Drupal\field\Entity\FieldInstanceConfig;
......@@ -178,11 +177,13 @@ function testDeleteFieldInstance() {
$this->assertEqual($instance->bundle, $bundle, 'The deleted instance is for the correct bundle');
// Check that the actual stored content did not change during delete.
$schema = ContentEntityDatabaseStorage::_fieldSqlSchema($field_storage);
$table = ContentEntityDatabaseStorage::_fieldTableName($field_storage);
$column = ContentEntityDatabaseStorage::_fieldColumnName($field_storage, 'value');
$storage = \Drupal::entityManager()->getStorage($this->entity_type);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $storage->getTableMapping();
$table = $table_mapping->getDedicatedDataTableName($field_storage);
$column = $table_mapping->getFieldColumnName($field_storage, 'value');
$result = db_select($table, 't')
->fields('t', array_keys($schema[$table]['fields']))
->fields('t')
->execute();
foreach ($result as $row) {
$this->assertEqual($this->entities[$row->entity_id]->{$field_storage->name}->value, $row->$column);
......
......@@ -76,7 +76,8 @@ public function testEntityCountAndHasData() {
$storage = \Drupal::entityManager()->getStorage('entity_test');
if ($storage instanceof ContentEntityDatabaseStorage) {
// Count the actual number of rows in the field table.
$field_table_name = $storage->_fieldTableName($field_storage);
$table_mapping = $storage->getTableMapping();
$field_table_name = $table_mapping->getDedicatedDataTableName($field_storage);
$result = db_select($field_table_name, 't')
->fields('t')
->countQuery()
......
......@@ -6,7 +6,6 @@
*/
namespace Drupal\field\Tests\Views;
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
/**
* Tests the Field Views data.
......@@ -51,8 +50,10 @@ function testViewsData() {
// Check the table and the joins of the first field.
// Attached to node only.
$field_storage = $this->fieldStorages[0];
$current_table = ContentEntityDatabaseStorage::_fieldTableName($field_storage);
$revision_table = ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = \Drupal::entityManager()->getStorage('node')->getTableMapping();
$current_table = $table_mapping->getDedicatedDataTableName($field_storage);
$revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage);
$data[$current_table] = $views_data->get($current_table);
$data[$revision_table] = $views_data->get($revision_table);
......
......@@ -5,7 +5,6 @@
* Provide views data for file.module.
*/
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\field\FieldStorageConfigInterface;
/**
......@@ -39,9 +38,12 @@ function file_field_views_data(FieldStorageConfigInterface $field_storage) {
*/
function file_field_views_data_views_data_alter(array &$data, FieldStorageConfigInterface $field_storage) {
$entity_type_id = $field_storage->entity_type;
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
$entity_manager = \Drupal::entityManager();
$entity_type = $entity_manager->getDefinition($entity_type_id);
$field_name = $field_storage->getName();
$pseudo_field_name = 'reverse_' . $field_name . '_' . $entity_type_id;
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $entity_manager->getStorage($entity_type_id)->getTableMapping();
list($label) = field_views_field_label($entity_type_id, $field_name);
......@@ -51,7 +53,7 @@ function file_field_views_data_views_data_alter(array &$data, FieldStorageConfig
'id' => 'entity_reverse',
'field_name' => $field_name,
'entity_type' => $entity_type_id,
'field table' => ContentEntityDatabaseStorage::_fieldTableName($field_storage),
'field table' => $table_mapping->getDedicatedDataTableName($field_storage),
'field field' => $field_name . '_target_id',
'base' => $entity_type->getBaseTable(),
'base field' => $entity_type->getKey('id'),
......
......@@ -5,7 +5,6 @@
* Provide views data for image.module.
*/
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\field\FieldStorageConfigInterface;
/**
......@@ -37,10 +36,13 @@ function image_field_views_data(FieldStorageConfigInterface $field_storage) {
* Views integration to provide reverse relationships on image fields.
*/
function image_field_views_data_views_data_alter(array &$data, FieldStorageConfigInterface $field_storage) {
$entity_type_id = $field_storage->entity_type;
$entity_type_id = $field_storage->getTargetEntityTypeId();
$field_name = $field_storage->getName();
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
$entity_manager = \Drupal::entityManager();
$entity_type = $entity_manager->getDefinition($entity_type_id);
$pseudo_field_name = 'reverse_' . $field_name . '_' . $entity_type_id;
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $entity_manager->getStorage($entity_type_id)->getTableMapping();
list($label) = field_views_field_label($entity_type_id, $field_name);
......@@ -50,7 +52,7 @@ function image_field_views_data_views_data_alter(array &$data, FieldStorageConfi
'id' => 'entity_reverse',
'field_name' => $field_name,
'entity_type' => $entity_type_id,
'field table' => ContentEntityDatabaseStorage::_fieldTableName($field_storage),
'field table' => $table_mapping->getDedicatedDataTableName($field_storage),
'field field' => $field_name . '_target_id',
'base' => $entity_type->getBaseTable(),
'base field' => $entity_type->getKey('id'),
......
......@@ -49,7 +49,9 @@ public function testCustomBundleFieldCreateDelete() {
$this->assertNotNull($definition, 'Field definition found.');
// Make sure the table has been created.
$table = $this->entityManager->getStorage('entity_test')->_fieldTableName($definition);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $this->entityManager->getStorage('entity_test')->getTableMapping();
$table = $table_mapping->getDedicatedDataTableName($definition);
$this->assertTrue($this->database->schema()->tableExists($table), 'Table created');
$this->moduleHandler->uninstall(array('entity_bundle_field_test'), FALSE);
$this->assertFalse($this->database->schema()->tableExists($table), 'Table dropped');
......@@ -87,7 +89,9 @@ public function testCustomBundleFieldUsage() {
$this->assertEqual($entity->custom_field->value, 'cozy', 'Entity was updated correctly.');
$entity->delete();
$table = $storage->_fieldTableName($entity->getFieldDefinition('custom_field'));
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $storage->getTableMapping();
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_field'));
$result = $this->database->select($table, 'f')
->fields('f')
->condition('f.entity_id', $entity->id())
......@@ -100,7 +104,7 @@ public function testCustomBundleFieldUsage() {
$entity->save();
entity_test_delete_bundle('custom');
$table = $storage->_fieldTableName($entity->getFieldDefinition('custom_field'));
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_field'));
$result = $this->database->select($table, 'f')
->condition('f.entity_id', $entity->id())
->condition('deleted', 1)
......
......@@ -56,6 +56,8 @@ class FieldSqlStorageTest extends EntityUnitTestBase {
protected $instance;
/**
* Name of the data table of the field.
*
* @var string
*/
protected $table;
......@@ -67,6 +69,13 @@ class FieldSqlStorageTest extends EntityUnitTestBase {
*/
protected $revision_table;
/**
* The table mapping for the tested entity type.
*
* @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping
*/
protected $table_mapping;
protected function setUp() {
parent::setUp();
......@@ -88,8 +97,11 @@ protected function setUp() {
));
$this->instance->save();
$this->table = ContentEntityDatabaseStorage::_fieldTableName($this->fieldStorage);
$this->revision_table = ContentEntityDatabaseStorage::_fieldRevisionTableName($this->fieldStorage);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = \Drupal::entityManager()->getStorage($entity_type)->getTableMapping();
$this->table_mapping = $table_mapping;
$this->table = $table_mapping->getDedicatedDataTableName($this->fieldStorage);
$this->revision_table = $table_mapping->getDedicatedRevisionTableName($this->fieldStorage);
}
/**
......@@ -99,7 +111,7 @@ function testFieldLoad() {
$entity_type = $bundle = 'entity_test_rev';
$storage = $this->container->get('entity.manager')->getStorage($entity_type);
$columns = array('bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'langcode', ContentEntityDatabaseStorage::_fieldColumnName($this->fieldStorage, 'value'));
$columns = array('bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'langcode', $this->table_mapping->getFieldColumnName($this->fieldStorage, 'value'));
// Create an entity with four revisions.
$revision_ids = array();
......@@ -337,7 +349,7 @@ function testFieldUpdateFailure() {
// Create a text field.
$field_storage = entity_create('field_storage_config', array(
'name' => 'test_text',
'entity_type' => 'entity_test',
'entity_type' => 'entity_test_rev',
'type' => 'text',
'settings' => array('max_length' => 255),
));
......@@ -355,7 +367,11 @@ function testFieldUpdateFailure() {
}
// Ensure that the field tables are still there.
foreach (ContentEntityDatabaseStorage::_fieldSqlSchema($prior_field_storage) as $table_name => $table_info) {
$tables = array(
$this->table_mapping->getDedicatedDataTableName($prior_field_storage),
$this->table_mapping->getDedicatedRevisionTableName($prior_field_storage),
);
foreach ($tables as $table_name) {
$this->assertTrue(db_table_exists($table_name), t('Table %table exists.', array('%table' => $table_name)));
}
}
......@@ -378,7 +394,7 @@ function testFieldUpdateIndexesWithData() {
'bundle' => $entity_type,
));
$instance->save();
$tables = array(ContentEntityDatabaseStorage::_fieldTableName($field_storage), ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage));
$tables = array($this->table_mapping->getDedicatedDataTableName($field_storage), $this->table_mapping->getDedicatedRevisionTableName($field_storage));
// Verify the indexes we will create do not exist yet.
foreach ($tables as $table) {
......@@ -451,10 +467,10 @@ function testFieldSqlStorageForeignKeys() {
// Verify the SQL schema.
$schemas = ContentEntityDatabaseStorage::_fieldSqlSchema($field_storage);
$schema = $schemas[ContentEntityDatabaseStorage::_fieldTableName($field_storage)];
$schema = $schemas[$this->table_mapping->getDedicatedDataTableName($field_storage)];
$this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema');
$foreign_key = reset($schema['foreign keys']);
$foreign_key_column = ContentEntityDatabaseStorage::_fieldColumnName($field_storage, $foreign_key_name);
$foreign_key_column = $this->table_mapping->getFieldColumnName($field_storage, $foreign_key_name);
$this->assertEqual($foreign_key['table'], $foreign_key_name, 'Foreign key table name preserved in the schema');
$this->assertEqual($foreign_key['columns'][$foreign_key_column], 'id', 'Foreign key column name preserved in the schema');
}
......@@ -504,9 +520,9 @@ public function testTableNames() {
'type' => 'test_field',
));
$expected = 'short_entity_type__short_field_name';
$this->assertEqual(ContentEntityDatabaseStorage::_fieldTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedDataTableName($field_storage), $expected);
$expected = 'short_entity_type_revision__short_field_name';
$this->assertEqual(ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedRevisionTableName($field_storage), $expected);
// Short entity type, long field name
$entity_type = 'short_entity_type';
......@@ -517,9 +533,9 @@ public function testTableNames() {
'type' => 'test_field',
));
$expected = 'short_entity_type__' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedDataTableName($field_storage), $expected);
$expected = 'short_entity_type_r__' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedRevisionTableName($field_storage), $expected);
// Long entity type, short field name
$entity_type = 'long_entity_type_abcdefghijklmnopqrstuvwxyz';
......@@ -530,9 +546,9 @@ public function testTableNames() {
'type' => 'test_field',
));
$expected = 'long_entity_type_abcdefghijklmnopq__' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedDataTableName($field_storage), $expected);
$expected = 'long_entity_type_abcdefghijklmnopq_r__' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedRevisionTableName($field_storage), $expected);
// Long entity type and field name.
$entity_type = 'long_entity_type_abcdefghijklmnopqrstuvwxyz';
......@@ -543,17 +559,17 @@ public function testTableNames() {
'type' => 'test_field',
));
$expected = 'long_entity_type_abcdefghijklmnopq__' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedDataTableName($field_storage), $expected);
$expected = 'long_entity_type_abcdefghijklmnopq_r__' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage), $expected);
$this->assertEqual($this->table_mapping->getDedicatedRevisionTableName($field_storage), $expected);
// Try creating a second field and check there are no clashes.
$field_storage2 = entity_create('field_storage_config', array(
'entity_type' => $entity_type,
'name' => $field_name . '2',
'type' => 'test_field',
));
$this->assertNotEqual(ContentEntityDatabaseStorage::_fieldTableName($field_storage), ContentEntityDatabaseStorage::_fieldTableName($field_storage2));
$this->assertNotEqual(ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage), ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage2));
$this->assertNotEqual($this->table_mapping->getDedicatedDataTableName($field_storage), $this->table_mapping->getDedicatedDataTableName($field_storage2));
$this->assertNotEqual($this->table_mapping->getDedicatedRevisionTableName($field_storage), $this->table_mapping->getDedicatedRevisionTableName($field_storage2));
// Deleted field.
$field_storage = entity_create('field_storage_config', array(
......@@ -563,9 +579,9 @@ public function testTableNames() {
'deleted' => TRUE,
));
$expected = 'field_deleted_data_' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldTableName($field_storage, TRUE), $expected);
$this->assertEqual($this->table_mapping->getDedicatedDataTableName($field_storage, TRUE), $expected);
$expected = 'field_deleted_revision_' . substr(hash('sha256', $field_storage->uuid()), 0, 10);
$this->assertEqual(ContentEntityDatabaseStorage::_fieldRevisionTableName($field_storage, TRUE), $expected);
$this->assertEqual($this->table_mapping->getDedicatedRevisionTableName($field_storage, TRUE), $expected);
}