View source
<?php
namespace Drupal\Tests\Core\Entity\Sql;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\Sql\DefaultTableMapping;
use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
use Drupal\Tests\UnitTestCase;
class SqlContentEntityStorageSchemaTest extends UnitTestCase {
protected $dbSchemaHandler;
protected $entityTypeManager;
protected $entityFieldManager;
protected $entityLastInstalledSchemaRepository;
protected $entityType;
protected $storage;
protected $storageDefinitions;
protected $storageSchema;
protected function setUp() {
$this->entityTypeManager = $this
->createMock(EntityTypeManager::class);
$this->entityFieldManager = $this
->createMock(EntityFieldManager::class);
$this->entityLastInstalledSchemaRepository = $this
->createMock(EntityLastInstalledSchemaRepositoryInterface::class);
$this->storage = $this
->getMockBuilder('Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorage')
->disableOriginalConstructor()
->getMock();
$this->storage
->expects($this
->any())
->method('getBaseTable')
->will($this
->returnValue('entity_test'));
$this
->setUpStorageDefinition('id', [
'columns' => [
'value' => [
'type' => 'int',
],
],
]);
}
public function testGetSchemaBase() {
$this->entityType = new ContentEntityType([
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
],
]);
$this
->setUpStorageDefinition('name', [
'columns' => [
'value' => [
'type' => 'varchar',
'length' => 255,
],
],
]);
$this
->setUpStorageDefinition('description', [
'columns' => [
'value' => [
'type' => 'text',
],
'format' => [
'type' => 'varchar',
],
],
]);
$this
->setUpStorageDefinition('uuid', [
'columns' => [
'value' => [
'type' => 'varchar',
'length' => 128,
],
],
'unique keys' => [
'value' => [
'value',
],
],
]);
$this
->setUpStorageDefinition('hash', [
'columns' => [
'value' => [
'type' => 'varchar',
'length' => 20,
],
],
'unique keys' => [
'value' => [
[
'value',
10,
],
],
],
]);
$this
->setUpStorageDefinition('email', [
'columns' => [
'username' => [
'type' => 'varchar',
],
'hostname' => [
'type' => 'varchar',
],
'domain' => [
'type' => 'varchar',
],
],
'unique keys' => [
'email' => [
'username',
'hostname',
[
'domain',
3,
],
],
],
]);
$this
->setUpStorageDefinition('owner', [
'columns' => [
'target_id' => [
'type' => 'int',
],
],
'indexes' => [
'target_id' => [
'target_id',
],
],
]);
$this
->setUpStorageDefinition('translator', [
'columns' => [
'target_id' => [
'type' => 'int',
],
],
'indexes' => [
'target_id' => [
[
'target_id',
10,
],
],
],
]);
$this
->setUpStorageDefinition('location', [
'columns' => [
'country' => [
'type' => 'varchar',
],
'state' => [
'type' => 'varchar',
],
'city' => [
'type' => 'varchar',
],
],
'indexes' => [
'country_state_city' => [
'country',
'state',
[
'city',
10,
],
],
],
]);
$this
->setUpStorageDefinition('editor', [
'columns' => [
'target_id' => [
'type' => 'int',
],
],
'foreign keys' => [
'user_id' => [
'table' => 'users',
'columns' => [
'target_id' => 'uid',
],
],
],
]);
$this
->setUpStorageDefinition('editor_revision', [
'columns' => [
'target_id' => [
'type' => 'int',
],
'target_revision_id' => [
'type' => 'int',
],
],
'foreign keys' => [
'user_id' => [
'table' => 'users',
'columns' => [
'target_id' => 'uid',
],
],
],
]);
$this
->setUpStorageDefinition('long_index_name', [
'columns' => [
'long_index_name' => [
'type' => 'int',
],
],
'indexes' => [
'long_index_name_really_long_long_name' => [
[
'long_index_name',
10,
],
],
],
]);
$expected = [
'entity_test' => [
'description' => 'The base table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
],
'name' => [
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
],
'description__value' => [
'type' => 'text',
'not null' => FALSE,
],
'description__format' => [
'type' => 'varchar',
'not null' => FALSE,
],
'uuid' => [
'type' => 'varchar',
'length' => 128,
'not null' => FALSE,
],
'hash' => [
'type' => 'varchar',
'length' => 20,
'not null' => FALSE,
],
'email__username' => [
'type' => 'varchar',
'not null' => FALSE,
],
'email__hostname' => [
'type' => 'varchar',
'not null' => FALSE,
],
'email__domain' => [
'type' => 'varchar',
'not null' => FALSE,
],
'owner' => [
'type' => 'int',
'not null' => FALSE,
],
'translator' => [
'type' => 'int',
'not null' => FALSE,
],
'location__country' => [
'type' => 'varchar',
'not null' => FALSE,
],
'location__state' => [
'type' => 'varchar',
'not null' => FALSE,
],
'location__city' => [
'type' => 'varchar',
'not null' => FALSE,
],
'editor' => [
'type' => 'int',
'not null' => FALSE,
],
'editor_revision__target_id' => [
'type' => 'int',
'not null' => FALSE,
],
'editor_revision__target_revision_id' => [
'type' => 'int',
'not null' => FALSE,
],
'long_index_name' => [
'type' => 'int',
'not null' => FALSE,
],
],
'primary key' => [
'id',
],
'unique keys' => [
'entity_test_field__uuid__value' => [
'uuid',
],
'entity_test_field__hash__value' => [
[
'hash',
10,
],
],
'entity_test_field__email__email' => [
'email__username',
'email__hostname',
[
'email__domain',
3,
],
],
],
'indexes' => [
'entity_test_field__owner__target_id' => [
'owner',
],
'entity_test_field__translator__target_id' => [
[
'translator',
10,
],
],
'entity_test_field__location__country_state_city' => [
'location__country',
'location__state',
[
'location__city',
10,
],
],
'entity_test__b588603cb9' => [
[
'long_index_name',
10,
],
],
],
'foreign keys' => [
'entity_test_field__editor__user_id' => [
'table' => 'users',
'columns' => [
'editor' => 'uid',
],
],
'entity_test_field__editor_revision__user_id' => [
'table' => 'users',
'columns' => [
'editor_revision__target_id' => 'uid',
],
],
],
],
];
$this
->setUpStorageSchema($expected);
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns('entity_test', [
'default_langcode',
]);
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this
->assertNull($this->storageSchema
->onEntityTypeCreate($this->entityType));
}
public function testGetSchemaRevisionable() {
$this->entityType = $this
->getMockBuilder('Drupal\\Core\\Entity\\ContentEntityType')
->setConstructorArgs([
[
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
'revision' => 'revision_id',
],
],
])
->setMethods([
'getRevisionMetadataKeys',
])
->getMock();
$this->entityType
->expects($this
->any())
->method('getRevisionMetadataKeys')
->will($this
->returnValue([]));
$this->storage
->expects($this
->exactly(9))
->method('getRevisionTable')
->will($this
->returnValue('entity_test_revision'));
$this
->setUpStorageDefinition('revision_id', [
'columns' => [
'value' => [
'type' => 'int',
],
],
]);
$expected = [
'entity_test' => [
'description' => 'The base table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
],
'revision_id' => [
'type' => 'int',
'not null' => FALSE,
],
],
'primary key' => [
'id',
],
'unique keys' => [
'entity_test__revision_id' => [
'revision_id',
],
],
'indexes' => [],
'foreign keys' => [
'entity_test__revision' => [
'table' => 'entity_test_revision',
'columns' => [
'revision_id' => 'revision_id',
],
],
],
],
'entity_test_revision' => [
'description' => 'The revision table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'int',
'not null' => TRUE,
],
'revision_id' => [
'type' => 'serial',
'not null' => TRUE,
],
],
'primary key' => [
'revision_id',
],
'unique keys' => [],
'indexes' => [
'entity_test__id' => [
'id',
],
],
'foreign keys' => [
'entity_test__revisioned' => [
'table' => 'entity_test',
'columns' => [
'id' => 'id',
],
],
],
],
];
$this
->setUpStorageSchema($expected);
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setFieldNames('entity_test_revision', array_keys($this->storageDefinitions));
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this->storageSchema
->onEntityTypeCreate($this->entityType);
}
public function testGetSchemaTranslatable() {
$this->entityType = new ContentEntityType([
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
'langcode' => 'langcode',
],
'translatable' => TRUE,
]);
$this->storage
->expects($this
->any())
->method('getDataTable')
->will($this
->returnValue('entity_test_field_data'));
$this
->setUpStorageDefinition('langcode', [
'columns' => [
'value' => [
'type' => 'varchar',
],
],
]);
$this
->setUpStorageDefinition('default_langcode', [
'columns' => [
'value' => [
'type' => 'int',
'size' => 'tiny',
],
],
]);
$expected = [
'entity_test' => [
'description' => 'The base table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
],
'langcode' => [
'type' => 'varchar',
'not null' => TRUE,
],
],
'primary key' => [
'id',
],
'unique keys' => [],
'indexes' => [],
'foreign keys' => [],
],
'entity_test_field_data' => [
'description' => 'The data table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'int',
'not null' => TRUE,
],
'langcode' => [
'type' => 'varchar',
'not null' => TRUE,
],
'default_langcode' => [
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
],
],
'primary key' => [
'id',
'langcode',
],
'unique keys' => [],
'indexes' => [
'entity_test__id__default_langcode__langcode' => [
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
],
],
'foreign keys' => [
'entity_test' => [
'table' => 'entity_test',
'columns' => [
'id' => 'id',
],
],
],
],
];
$this
->setUpStorageSchema($expected);
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$non_data_fields = array_keys($this->storageDefinitions);
unset($non_data_fields[array_search('default_langcode', $non_data_fields)]);
$table_mapping
->setFieldNames('entity_test', $non_data_fields);
$table_mapping
->setFieldNames('entity_test_field_data', array_keys($this->storageDefinitions));
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this
->assertNull($this->storageSchema
->onEntityTypeCreate($this->entityType));
}
public function testGetSchemaRevisionableTranslatable() {
$this->entityType = $this
->getMockBuilder('Drupal\\Core\\Entity\\ContentEntityType')
->setConstructorArgs([
[
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
'revision' => 'revision_id',
'langcode' => 'langcode',
],
'revision_data_table' => 'entity_test_revision_field_data',
],
])
->setMethods([
'isRevisionable',
'isTranslatable',
'getRevisionMetadataKeys',
])
->getMock();
$this->entityType
->expects($this
->any())
->method('isRevisionable')
->will($this
->returnValue(TRUE));
$this->entityType
->expects($this
->any())
->method('isTranslatable')
->will($this
->returnValue(TRUE));
$this->storage
->expects($this
->exactly(30))
->method('getRevisionTable')
->will($this
->returnValue('entity_test_revision'));
$this
->setUpStorageDefinition('revision_id', [
'columns' => [
'value' => [
'type' => 'int',
],
],
]);
$this
->setUpStorageDefinition('langcode', [
'columns' => [
'value' => [
'type' => 'varchar',
],
],
]);
$this
->setUpStorageDefinition('default_langcode', [
'columns' => [
'value' => [
'type' => 'int',
'size' => 'tiny',
],
],
]);
$expected = [
'entity_test' => [
'description' => 'The base table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
],
'revision_id' => [
'type' => 'int',
'not null' => FALSE,
],
'langcode' => [
'type' => 'varchar',
'not null' => TRUE,
],
],
'primary key' => [
'id',
],
'unique keys' => [
'entity_test__revision_id' => [
'revision_id',
],
],
'indexes' => [],
'foreign keys' => [
'entity_test__revision' => [
'table' => 'entity_test_revision',
'columns' => [
'revision_id' => 'revision_id',
],
],
],
],
'entity_test_revision' => [
'description' => 'The revision table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'int',
'not null' => TRUE,
],
'revision_id' => [
'type' => 'serial',
'not null' => TRUE,
],
'langcode' => [
'type' => 'varchar',
'not null' => TRUE,
],
],
'primary key' => [
'revision_id',
],
'unique keys' => [],
'indexes' => [
'entity_test__id' => [
'id',
],
],
'foreign keys' => [
'entity_test__revisioned' => [
'table' => 'entity_test',
'columns' => [
'id' => 'id',
],
],
],
],
'entity_test_field_data' => [
'description' => 'The data table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'int',
'not null' => TRUE,
],
'revision_id' => [
'type' => 'int',
'not null' => TRUE,
],
'langcode' => [
'type' => 'varchar',
'not null' => TRUE,
],
'default_langcode' => [
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
],
],
'primary key' => [
'id',
'langcode',
],
'unique keys' => [],
'indexes' => [
'entity_test__revision_id' => [
'revision_id',
],
'entity_test__id__default_langcode__langcode' => [
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
],
],
'foreign keys' => [
'entity_test' => [
'table' => 'entity_test',
'columns' => [
'id' => 'id',
],
],
],
],
'entity_test_revision_field_data' => [
'description' => 'The revision data table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'int',
'not null' => TRUE,
],
'revision_id' => [
'type' => 'int',
'not null' => TRUE,
],
'langcode' => [
'type' => 'varchar',
'not null' => TRUE,
],
'default_langcode' => [
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
],
],
'primary key' => [
'revision_id',
'langcode',
],
'unique keys' => [],
'indexes' => [
'entity_test__id__default_langcode__langcode' => [
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
],
],
'foreign keys' => [
'entity_test' => [
'table' => 'entity_test',
'columns' => [
'id' => 'id',
],
],
'entity_test__revision' => [
'table' => 'entity_test_revision',
'columns' => [
'revision_id' => 'revision_id',
],
],
],
],
];
$this
->setUpStorageSchema($expected);
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$non_data_fields = array_keys($this->storageDefinitions);
unset($non_data_fields[array_search('default_langcode', $non_data_fields)]);
$table_mapping
->setFieldNames('entity_test', $non_data_fields);
$table_mapping
->setFieldNames('entity_test_revision', $non_data_fields);
$table_mapping
->setFieldNames('entity_test_field_data', array_keys($this->storageDefinitions));
$table_mapping
->setFieldNames('entity_test_revision_field_data', array_keys($this->storageDefinitions));
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this->storageSchema
->onEntityTypeCreate($this->entityType);
}
public function testDedicatedTableSchema() {
$entity_type_id = 'entity_test';
$this->entityType = new ContentEntityType([
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
],
]);
$field_name = $this
->getRandomGenerator()
->name();
$this
->setUpStorageDefinition($field_name, [
'columns' => [
'shape' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
'color' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
'area' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
'depth' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
],
'foreign keys' => [
'color' => [
'table' => 'color',
'columns' => [
'color' => 'id',
],
],
],
'unique keys' => [
'area' => [
'area',
],
'shape' => [
[
'shape',
10,
],
],
],
'indexes' => [
'depth' => [
'depth',
],
'color' => [
[
'color',
3,
],
],
],
]);
$field_storage = $this->storageDefinitions[$field_name];
$field_storage
->expects($this
->any())
->method('getType')
->will($this
->returnValue('shape'));
$field_storage
->expects($this
->any())
->method('getTargetEntityTypeId')
->will($this
->returnValue($entity_type_id));
$field_storage
->expects($this
->any())
->method('isMultiple')
->will($this
->returnValue(TRUE));
$this->storageDefinitions['id']
->expects($this
->any())
->method('getType')
->will($this
->returnValue('integer'));
$expected = [
$entity_type_id . '__' . $field_name => [
'description' => "Data storage for {$entity_type_id} field {$field_name}.",
'fields' => [
'bundle' => [
'type' => 'varchar_ascii',
'length' => 128,
'not null' => TRUE,
'default' => '',
'description' => 'The field instance bundle to which this row belongs, used when deleting a field instance',
],
'deleted' => [
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
'description' => 'A boolean indicating whether this data item has been deleted',
],
'entity_id' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The entity id this data is attached to',
],
'revision_id' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The entity revision id this data is attached to, which for an unversioned entity type is the same as the entity id',
],
'langcode' => [
'type' => 'varchar_ascii',
'length' => 32,
'not null' => TRUE,
'default' => '',
'description' => 'The language code for this data item.',
],
'delta' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The sequence number for this data item, used for multi-value fields',
],
$field_name . '_shape' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
$field_name . '_color' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
$field_name . '_area' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
$field_name . '_depth' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
],
'primary key' => [
'entity_id',
'deleted',
'delta',
'langcode',
],
'indexes' => [
'bundle' => [
'bundle',
],
'revision_id' => [
'revision_id',
],
$field_name . '_depth' => [
$field_name . '_depth',
],
$field_name . '_color' => [
[
$field_name . '_color',
3,
],
],
],
'unique keys' => [
$field_name . '_area' => [
$field_name . '_area',
],
$field_name . '_shape' => [
[
$field_name . '_shape',
10,
],
],
],
'foreign keys' => [
$field_name . '_color' => [
'table' => 'color',
'columns' => [
$field_name . '_color' => 'id',
],
],
],
],
];
$this
->setUpStorageSchema($expected);
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames($entity_type_id, array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns($entity_type_id, [
'default_langcode',
]);
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this
->assertNull($this->storageSchema
->onFieldStorageDefinitionCreate($field_storage));
}
public function testDedicatedTableSchemaForEntityWithStringIdentifier() {
$entity_type_id = 'entity_test';
$this->entityType = new ContentEntityType([
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
],
]);
$field_name = $this
->getRandomGenerator()
->name();
$this
->setUpStorageDefinition($field_name, [
'columns' => [
'shape' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
'color' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
],
'foreign keys' => [
'color' => [
'table' => 'color',
'columns' => [
'color' => 'id',
],
],
],
'unique keys' => [],
'indexes' => [],
]);
$field_storage = $this->storageDefinitions[$field_name];
$field_storage
->expects($this
->any())
->method('getType')
->will($this
->returnValue('shape'));
$field_storage
->expects($this
->any())
->method('getTargetEntityTypeId')
->will($this
->returnValue($entity_type_id));
$field_storage
->expects($this
->any())
->method('isMultiple')
->will($this
->returnValue(TRUE));
$this->storageDefinitions['id']
->expects($this
->any())
->method('getType')
->will($this
->returnValue('string'));
$expected = [
$entity_type_id . '__' . $field_name => [
'description' => "Data storage for {$entity_type_id} field {$field_name}.",
'fields' => [
'bundle' => [
'type' => 'varchar_ascii',
'length' => 128,
'not null' => TRUE,
'default' => '',
'description' => 'The field instance bundle to which this row belongs, used when deleting a field instance',
],
'deleted' => [
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
'description' => 'A boolean indicating whether this data item has been deleted',
],
'entity_id' => [
'type' => 'varchar_ascii',
'length' => 128,
'not null' => TRUE,
'description' => 'The entity id this data is attached to',
],
'revision_id' => [
'type' => 'varchar_ascii',
'length' => 128,
'not null' => TRUE,
'description' => 'The entity revision id this data is attached to, which for an unversioned entity type is the same as the entity id',
],
'langcode' => [
'type' => 'varchar_ascii',
'length' => 32,
'not null' => TRUE,
'default' => '',
'description' => 'The language code for this data item.',
],
'delta' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'The sequence number for this data item, used for multi-value fields',
],
$field_name . '_shape' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
$field_name . '_color' => [
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
],
],
'primary key' => [
'entity_id',
'deleted',
'delta',
'langcode',
],
'indexes' => [
'bundle' => [
'bundle',
],
'revision_id' => [
'revision_id',
],
],
'foreign keys' => [
$field_name . '_color' => [
'table' => 'color',
'columns' => [
$field_name . '_color' => 'id',
],
],
],
],
];
$this
->setUpStorageSchema($expected);
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames($entity_type_id, array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns($entity_type_id, [
'default_langcode',
]);
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this
->assertNull($this->storageSchema
->onFieldStorageDefinitionCreate($field_storage));
}
public function providerTestRequiresEntityDataMigration() {
$updated_entity_type_definition = $this
->createMock('\\Drupal\\Core\\Entity\\EntityTypeInterface');
$updated_entity_type_definition
->expects($this
->any())
->method('getStorageClass')
->willReturn('\\Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema');
$original_entity_type_definition = $this
->createMock('\\Drupal\\Core\\Entity\\EntityTypeInterface');
$original_entity_type_definition
->expects($this
->any())
->method('getStorageClass')
->willReturn('\\Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema');
$original_entity_type_definition_other_nonexisting = $this
->createMock('\\Drupal\\Core\\Entity\\EntityTypeInterface');
$original_entity_type_definition_other_nonexisting
->expects($this
->any())
->method('getStorageClass')
->willReturn('bar');
$original_entity_type_definition_other_existing = $this
->createMock('\\Drupal\\Core\\Entity\\EntityTypeInterface');
$original_entity_type_definition_other_existing
->expects($this
->any())
->method('getStorageClass')
->willReturn('\\Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema');
return [
[
$updated_entity_type_definition,
$original_entity_type_definition,
TRUE,
TRUE,
TRUE,
],
[
$updated_entity_type_definition,
$original_entity_type_definition,
FALSE,
TRUE,
FALSE,
],
[
$updated_entity_type_definition,
$original_entity_type_definition_other_nonexisting,
NULL,
TRUE,
TRUE,
],
[
$updated_entity_type_definition,
$original_entity_type_definition_other_existing,
TRUE,
TRUE,
TRUE,
],
[
$updated_entity_type_definition,
$original_entity_type_definition_other_existing,
FALSE,
TRUE,
FALSE,
],
[
$updated_entity_type_definition,
$original_entity_type_definition,
TRUE,
FALSE,
FALSE,
],
[
$updated_entity_type_definition,
$original_entity_type_definition_other_existing,
TRUE,
FALSE,
FALSE,
],
];
}
public function testRequiresEntityDataMigration($updated_entity_type_definition, $original_entity_type_definition, $original_storage_has_data, $shared_table_structure_changed, $migration_required) {
$this->entityType = new ContentEntityType([
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
],
]);
$this->storage
->expects($this
->exactly(is_null($original_storage_has_data) || !$shared_table_structure_changed ? 0 : 1))
->method('hasData')
->willReturn($original_storage_has_data);
$connection = $this
->getMockBuilder('Drupal\\Core\\Database\\Connection')
->disableOriginalConstructor()
->getMock();
$this->entityLastInstalledSchemaRepository
->expects($this
->any())
->method('getLastInstalledDefinition')
->willReturn($this->entityType);
$this->entityLastInstalledSchemaRepository
->expects($this
->any())
->method('getLastInstalledFieldStorageDefinitions')
->willReturn($this->storageDefinitions);
$this->storageSchema = $this
->getMockBuilder('Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema')
->setConstructorArgs([
$this->entityTypeManager,
$this->entityType,
$this->storage,
$connection,
$this->entityFieldManager,
$this->entityLastInstalledSchemaRepository,
])
->setMethods([
'installedStorageSchema',
'hasSharedTableStructureChange',
])
->getMock();
$this->storageSchema
->expects($this
->any())
->method('hasSharedTableStructureChange')
->with($updated_entity_type_definition, $original_entity_type_definition)
->willReturn($shared_table_structure_changed);
$this
->assertEquals($migration_required, $this->storageSchema
->requiresEntityDataMigration($updated_entity_type_definition, $original_entity_type_definition));
}
public function providerTestRequiresEntityStorageSchemaChanges() {
$cases = [];
$updated_entity_type_definition = $this
->createMock('\\Drupal\\Core\\Entity\\ContentEntityTypeInterface');
$original_entity_type_definition = $this
->createMock('\\Drupal\\Core\\Entity\\ContentEntityTypeInterface');
$updated_entity_type_definition
->expects($this
->any())
->method('id')
->willReturn('entity_test');
$updated_entity_type_definition
->expects($this
->any())
->method('getKey')
->willReturn('id');
$original_entity_type_definition
->expects($this
->any())
->method('id')
->willReturn('entity_test');
$original_entity_type_definition
->expects($this
->any())
->method('getKey')
->willReturn('id');
$updated = clone $updated_entity_type_definition;
$original = clone $original_entity_type_definition;
$updated
->expects($this
->never())
->method('getStorageClass');
$original
->expects($this
->never())
->method('getStorageClass');
$cases[] = [
$updated,
$original,
FALSE,
FALSE,
FALSE,
];
$cases[] = [
$updated,
$original,
TRUE,
TRUE,
FALSE,
];
$cases[] = [
$updated,
$original,
TRUE,
FALSE,
TRUE,
];
$updated = clone $updated_entity_type_definition;
$updated
->expects($this
->once())
->method('isTranslatable')
->willReturn(FALSE);
$original = clone $original_entity_type_definition;
$original
->expects($this
->once())
->method('isTranslatable')
->willReturn(TRUE);
$cases[] = [
$updated,
$original,
TRUE,
FALSE,
FALSE,
];
$updated = clone $updated_entity_type_definition;
$updated
->expects($this
->once())
->method('isRevisionable')
->willReturn(FALSE);
$original = clone $original_entity_type_definition;
$original
->expects($this
->once())
->method('isRevisionable')
->willReturn(TRUE);
$cases[] = [
$updated,
$original,
TRUE,
FALSE,
FALSE,
];
return $cases;
}
public function testRequiresEntityStorageSchemaChanges(ContentEntityTypeInterface $updated, ContentEntityTypeInterface $original, $requires_change, $change_schema, $change_shared_table) {
$this->entityType = new ContentEntityType([
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
],
]);
$this
->setUpStorageSchema();
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns('entity_test', [
'default_langcode',
]);
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
if ($change_schema) {
$this->storageSchema
->expects($this
->once())
->method('loadEntitySchemaData')
->willReturn([]);
}
else {
$expected = [
'entity_test' => [
'primary key' => [
'id',
],
],
];
$this->storageSchema
->expects($this
->any())
->method('loadEntitySchemaData')
->willReturn($expected);
}
if ($change_shared_table) {
$this->storageSchema
->expects($this
->once())
->method('hasSharedTableNameChanges')
->willReturn(TRUE);
}
$this
->assertEquals($requires_change, $this->storageSchema
->requiresEntityStorageSchemaChanges($updated, $original));
}
protected function setUpStorageSchema(array $expected = []) {
$this->entityTypeManager
->expects($this
->any())
->method('getDefinition')
->with($this->entityType
->id())
->will($this
->returnValue($this->entityType));
$this->entityTypeManager
->expects($this
->any())
->method('getActiveDefinition')
->with($this->entityType
->id())
->will($this
->returnValue($this->entityType));
$this->entityFieldManager
->expects($this
->any())
->method('getFieldStorageDefinitions')
->with($this->entityType
->id())
->will($this
->returnValue($this->storageDefinitions));
$this->entityFieldManager
->expects($this
->any())
->method('getActiveFieldStorageDefinitions')
->with($this->entityType
->id())
->will($this
->returnValue($this->storageDefinitions));
$this->dbSchemaHandler = $this
->getMockBuilder('Drupal\\Core\\Database\\Schema')
->disableOriginalConstructor()
->getMock();
if ($expected) {
$invocation_count = 0;
$expected_table_names = array_keys($expected);
$expected_table_schemas = array_values($expected);
$this->dbSchemaHandler
->expects($this
->any())
->method('createTable')
->with($this
->callback(function ($table_name) use (&$invocation_count, $expected_table_names) {
return $expected_table_names[$invocation_count] == $table_name;
}), $this
->callback(function ($table_schema) use (&$invocation_count, $expected_table_schemas) {
return $expected_table_schemas[$invocation_count] == $table_schema;
}))
->will($this
->returnCallback(function () use (&$invocation_count) {
$invocation_count++;
}));
}
$connection = $this
->getMockBuilder('Drupal\\Core\\Database\\Connection')
->disableOriginalConstructor()
->getMock();
$connection
->expects($this
->any())
->method('schema')
->will($this
->returnValue($this->dbSchemaHandler));
$key_value = $this
->createMock('Drupal\\Core\\KeyValueStore\\KeyValueStoreInterface');
$this->entityLastInstalledSchemaRepository
->expects($this
->any())
->method('getLastInstalledDefinition')
->willReturn($this->entityType);
$this->entityLastInstalledSchemaRepository
->expects($this
->any())
->method('getLastInstalledFieldStorageDefinitions')
->willReturn($this->storageDefinitions);
$this->storageSchema = $this
->getMockBuilder('Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema')
->setConstructorArgs([
$this->entityTypeManager,
$this->entityType,
$this->storage,
$connection,
$this->entityFieldManager,
$this->entityLastInstalledSchemaRepository,
])
->setMethods([
'installedStorageSchema',
'loadEntitySchemaData',
'hasSharedTableNameChanges',
'isTableEmpty',
'getTableMapping',
])
->getMock();
$this->storageSchema
->expects($this
->any())
->method('installedStorageSchema')
->will($this
->returnValue($key_value));
$this->storageSchema
->expects($this
->any())
->method('isTableEmpty')
->willReturn(FALSE);
}
public function setUpStorageDefinition($field_name, array $schema) {
$this->storageDefinitions[$field_name] = $this
->createMock('Drupal\\Tests\\Core\\Field\\TestBaseFieldDefinitionInterface');
$this->storageDefinitions[$field_name]
->expects($this
->any())
->method('isBaseField')
->will($this
->returnValue(TRUE));
$this->storageDefinitions[$field_name]
->expects($this
->any())
->method('getName')
->will($this
->returnValue($field_name));
$this->storageDefinitions[$field_name]
->expects($this
->any())
->method('getSchema')
->will($this
->returnValue($schema));
$this->storageDefinitions[$field_name]
->expects($this
->any())
->method('getColumns')
->will($this
->returnValue($schema['columns']));
if (!empty($schema['columns'])) {
$property_definitions = [];
foreach ($schema['columns'] as $column => $info) {
$property_definitions[$column] = $this
->createMock('Drupal\\Core\\TypedData\\DataDefinitionInterface');
$property_definitions[$column]
->expects($this
->any())
->method('isRequired')
->will($this
->returnValue(!empty($info['not null'])));
}
$this->storageDefinitions[$field_name]
->expects($this
->any())
->method('getPropertyDefinitions')
->will($this
->returnValue($property_definitions));
}
}
public function testonEntityTypeUpdateWithNewIndex() {
$this->entityType = $original_entity_type = new ContentEntityType([
'id' => 'entity_test',
'entity_keys' => [
'id' => 'id',
],
]);
$this
->setUpStorageDefinition('long_index_name', [
'columns' => [
'long_index_name' => [
'type' => 'int',
],
],
'indexes' => [
'long_index_name_really_long_long_name' => [
[
'long_index_name',
10,
],
],
],
]);
$expected = [
'entity_test' => [
'description' => 'The base table for entity_test entities.',
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
],
'long_index_name' => [
'type' => 'int',
'not null' => FALSE,
],
],
'indexes' => [
'entity_test__b588603cb9' => [
[
'long_index_name',
10,
],
],
],
],
];
$this
->setUpStorageSchema($expected);
$table_mapping = new TestSqlContentDefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns('entity_test', [
'default_langcode',
]);
$this->storageSchema
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this->storageSchema
->expects($this
->any())
->method('loadEntitySchemaData')
->willReturn([
'entity_test' => [
'indexes' => [
'entity_test__b588603cb9' => [
'longer_index_name',
],
'entity_test__removed_field' => [
'removed_field',
],
],
],
]);
$this->dbSchemaHandler
->expects($this
->at(0))
->method('dropIndex')
->with('entity_test', 'entity_test__b588603cb9');
$this->dbSchemaHandler
->expects($this
->at(1))
->method('dropIndex')
->with('entity_test', 'entity_test__removed_field');
$this->dbSchemaHandler
->expects($this
->atLeastOnce())
->method('fieldExists')
->willReturn(TRUE);
$this->dbSchemaHandler
->expects($this
->atLeastOnce())
->method('addIndex')
->with('entity_test', 'entity_test__b588603cb9', [
[
'long_index_name',
10,
],
], $this
->callback(function ($actual_value) use ($expected) {
$this
->assertEquals($expected['entity_test']['indexes'], $actual_value['indexes']);
$this
->assertEquals($expected['entity_test']['fields'], $actual_value['fields']);
return TRUE;
}));
$this
->assertNull($this->storageSchema
->onEntityTypeUpdate($this->entityType, $original_entity_type));
}
public function testCastValue($expected, $value, array $schema) {
$this
->assertSame($expected, SqlContentEntityStorageSchema::castValue($schema, $value));
}
public function providerSchemaCastValue() {
$cases = [];
$cases[] = [
NULL,
NULL,
[
'not null' => FALSE,
],
];
$cases[] = [
0,
NULL,
[
'not null' => TRUE,
'type' => 'int',
],
];
$cases[] = [
0,
NULL,
[
'not null' => TRUE,
'type' => 'serial',
],
];
$cases[] = [
0.0,
NULL,
[
'not null' => TRUE,
'type' => 'float',
],
];
$cases[] = [
'',
NULL,
[
'not null' => TRUE,
'type' => 'varchar',
],
];
$cases[] = [
1,
'1.001',
[
'type' => 'int',
],
];
$cases[] = [
2,
2.6,
[
'type' => 'int',
],
];
$cases[] = [
3,
'3.6',
[
'type' => 'serial',
],
];
$cases[] = [
1.001,
'1.001',
[
'type' => 'float',
],
];
$cases[] = [
2.6,
2.6,
[
'type' => 'float',
],
];
$cases[] = [
'1',
1,
[
'type' => 'varchar',
],
];
$cases[] = [
'2',
'2',
[
'type' => 'varchar',
],
];
return $cases;
}
}
class TestSqlContentDefaultTableMapping extends DefaultTableMapping {
public function setFieldNames($table_name, array $field_names) {
return parent::setFieldNames($table_name, $field_names);
}
public function setExtraColumns($table_name, array $column_names) {
return parent::setExtraColumns($table_name, $column_names);
}
}