class SqlContentEntityStorageSchemaTest in Zircon Profile 8
Same name and namespace in other branches
- 8.0 core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php \Drupal\Tests\Core\Entity\Sql\SqlContentEntityStorageSchemaTest
@coversDefaultClass \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema @group Entity
Hierarchy
- class \Drupal\Tests\UnitTestCase extends \Drupal\Tests\PHPUnit_Framework_TestCase
- class \Drupal\Tests\Core\Entity\Sql\SqlContentEntityStorageSchemaTest
Expanded class hierarchy of SqlContentEntityStorageSchemaTest
File
- core/
tests/ Drupal/ Tests/ Core/ Entity/ Sql/ SqlContentEntityStorageSchemaTest.php, line 19 - Contains \Drupal\Tests\Core\Entity\Sql\SqlContentEntityStorageSchemaTest.
Namespace
Drupal\Tests\Core\Entity\SqlView source
class SqlContentEntityStorageSchemaTest extends UnitTestCase {
/**
* The mocked DB schema handler.
*
* @var \Drupal\Core\Database\Schema|\PHPUnit_Framework_MockObject_MockObject
*/
protected $dbSchemaHandler;
/**
* The mocked entity manager used in this test.
*
* @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityManager;
/**
* The mocked entity type used in this test.
*
* @var \Drupal\Core\Entity\ContentEntityTypeInterface
*/
protected $entityType;
/**
* The mocked SQL storage used in this test.
*
* @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage|\PHPUnit_Framework_MockObject_MockObject
*/
protected $storage;
/**
* The mocked field definitions used in this test.
*
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface[]|\PHPUnit_Framework_MockObject_MockObject[]
*/
protected $storageDefinitions;
/**
* The storage schema handler used in this test.
*
* @var \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema|\PHPUnit_Framework_MockObject_MockObject.
*/
protected $storageSchema;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->entityManager = $this
->getMock('Drupal\\Core\\Entity\\EntityManagerInterface');
$this->storage = $this
->getMockBuilder('Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorage')
->disableOriginalConstructor()
->getMock();
$this->storage
->expects($this
->any())
->method('getBaseTable')
->will($this
->returnValue('entity_test'));
// Add an ID field. This also acts as a test for a simple, single-column
// field.
$this
->setUpStorageDefinition('id', array(
'columns' => array(
'value' => array(
'type' => 'int',
),
),
));
}
/**
* Tests the schema for non-revisionable, non-translatable entities.
*
* @covers ::__construct
* @covers ::getEntitySchemaTables
* @covers ::initializeBaseTable
* @covers ::addTableDefaults
* @covers ::getEntityIndexName
* @covers ::getFieldIndexes
* @covers ::getFieldUniqueKeys
* @covers ::getFieldForeignKeys
* @covers ::getFieldSchemaData
* @covers ::processBaseTable
* @covers ::processIdentifierSchema
*/
public function testGetSchemaBase() {
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
),
));
// Add a field with a 'length' constraint.
$this
->setUpStorageDefinition('name', array(
'columns' => array(
'value' => array(
'type' => 'varchar',
'length' => 255,
),
),
));
// Add a multi-column field.
$this
->setUpStorageDefinition('description', array(
'columns' => array(
'value' => array(
'type' => 'text',
),
'format' => array(
'type' => 'varchar',
),
),
));
// Add a field with a unique key.
$this
->setUpStorageDefinition('uuid', array(
'columns' => array(
'value' => array(
'type' => 'varchar',
'length' => 128,
),
),
'unique keys' => array(
'value' => array(
'value',
),
),
));
// Add a field with a unique key, specified as column name and length.
$this
->setUpStorageDefinition('hash', array(
'columns' => array(
'value' => array(
'type' => 'varchar',
'length' => 20,
),
),
'unique keys' => array(
'value' => array(
array(
'value',
10,
),
),
),
));
// Add a field with a multi-column unique key.
$this
->setUpStorageDefinition('email', array(
'columns' => array(
'username' => array(
'type' => 'varchar',
),
'hostname' => array(
'type' => 'varchar',
),
'domain' => array(
'type' => 'varchar',
),
),
'unique keys' => array(
'email' => array(
'username',
'hostname',
array(
'domain',
3,
),
),
),
));
// Add a field with an index.
$this
->setUpStorageDefinition('owner', array(
'columns' => array(
'target_id' => array(
'type' => 'int',
),
),
'indexes' => array(
'target_id' => array(
'target_id',
),
),
));
// Add a field with an index, specified as column name and length.
$this
->setUpStorageDefinition('translator', array(
'columns' => array(
'target_id' => array(
'type' => 'int',
),
),
'indexes' => array(
'target_id' => array(
array(
'target_id',
10,
),
),
),
));
// Add a field with a multi-column index.
$this
->setUpStorageDefinition('location', array(
'columns' => array(
'country' => array(
'type' => 'varchar',
),
'state' => array(
'type' => 'varchar',
),
'city' => array(
'type' => 'varchar',
),
),
'indexes' => array(
'country_state_city' => array(
'country',
'state',
array(
'city',
10,
),
),
),
));
// Add a field with a foreign key.
$this
->setUpStorageDefinition('editor', array(
'columns' => array(
'target_id' => array(
'type' => 'int',
),
),
'foreign keys' => array(
'user_id' => array(
'table' => 'users',
'columns' => array(
'target_id' => 'uid',
),
),
),
));
// Add a multi-column field with a foreign key.
$this
->setUpStorageDefinition('editor_revision', array(
'columns' => array(
'target_id' => array(
'type' => 'int',
),
'target_revision_id' => array(
'type' => 'int',
),
),
'foreign keys' => array(
'user_id' => array(
'table' => 'users',
'columns' => array(
'target_id' => 'uid',
),
),
),
));
// Add a field with a really long index.
$this
->setUpStorageDefinition('long_index_name', array(
'columns' => array(
'long_index_name' => array(
'type' => 'int',
),
),
'indexes' => array(
'long_index_name_really_long_long_name' => array(
array(
'long_index_name',
10,
),
),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'serial',
'not null' => TRUE,
),
'name' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
),
'description__value' => array(
'type' => 'text',
'not null' => FALSE,
),
'description__format' => array(
'type' => 'varchar',
'not null' => FALSE,
),
'uuid' => array(
'type' => 'varchar',
'length' => 128,
'not null' => FALSE,
),
'hash' => array(
'type' => 'varchar',
'length' => 20,
'not null' => FALSE,
),
'email__username' => array(
'type' => 'varchar',
'not null' => FALSE,
),
'email__hostname' => array(
'type' => 'varchar',
'not null' => FALSE,
),
'email__domain' => array(
'type' => 'varchar',
'not null' => FALSE,
),
'owner' => array(
'type' => 'int',
'not null' => FALSE,
),
'translator' => array(
'type' => 'int',
'not null' => FALSE,
),
'location__country' => array(
'type' => 'varchar',
'not null' => FALSE,
),
'location__state' => array(
'type' => 'varchar',
'not null' => FALSE,
),
'location__city' => array(
'type' => 'varchar',
'not null' => FALSE,
),
'editor' => array(
'type' => 'int',
'not null' => FALSE,
),
'editor_revision__target_id' => array(
'type' => 'int',
'not null' => FALSE,
),
'editor_revision__target_revision_id' => array(
'type' => 'int',
'not null' => FALSE,
),
'long_index_name' => array(
'type' => 'int',
'not null' => FALSE,
),
),
'primary key' => array(
'id',
),
'unique keys' => array(
'entity_test_field__uuid__value' => array(
'uuid',
),
'entity_test_field__hash__value' => array(
array(
'hash',
10,
),
),
'entity_test_field__email__email' => array(
'email__username',
'email__hostname',
array(
'email__domain',
3,
),
),
),
'indexes' => array(
'entity_test_field__owner__target_id' => array(
'owner',
),
'entity_test_field__translator__target_id' => array(
array(
'translator',
10,
),
),
'entity_test_field__location__country_state_city' => array(
'location__country',
'location__state',
array(
'location__city',
10,
),
),
'entity_test__b588603cb9' => array(
array(
'long_index_name',
10,
),
),
),
'foreign keys' => array(
'entity_test_field__editor__user_id' => array(
'table' => 'users',
'columns' => array(
'editor' => 'uid',
),
),
'entity_test_field__editor_revision__user_id' => array(
'table' => 'users',
'columns' => array(
'editor_revision__target_id' => 'uid',
),
),
),
),
);
$this
->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns('entity_test', array(
'default_langcode',
));
$this->storage
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this
->assertNull($this->storageSchema
->onEntityTypeCreate($this->entityType));
}
/**
* Tests the schema for revisionable, non-translatable entities.
*
* @covers ::__construct
* @covers ::getEntitySchemaTables
* @covers ::initializeBaseTable
* @covers ::initializeRevisionTable
* @covers ::addTableDefaults
* @covers ::getEntityIndexName
* @covers ::processRevisionTable
* @covers ::processIdentifierSchema
*/
public function testGetSchemaRevisionable() {
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
'revision' => 'revision_id',
),
));
$this->storage
->expects($this
->exactly(2))
->method('getRevisionTable')
->will($this
->returnValue('entity_test_revision'));
$this
->setUpStorageDefinition('revision_id', array(
'columns' => array(
'value' => array(
'type' => 'int',
),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'serial',
'not null' => TRUE,
),
'revision_id' => array(
'type' => 'int',
'not null' => FALSE,
),
),
'primary key' => array(
'id',
),
'unique keys' => array(
'entity_test__revision_id' => array(
'revision_id',
),
),
'indexes' => array(),
'foreign keys' => array(
'entity_test__revision' => array(
'table' => 'entity_test_revision',
'columns' => array(
'revision_id' => 'revision_id',
),
),
),
),
'entity_test_revision' => array(
'description' => 'The revision table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'int',
'not null' => TRUE,
),
'revision_id' => array(
'type' => 'serial',
'not null' => TRUE,
),
),
'primary key' => array(
'revision_id',
),
'unique keys' => array(),
'indexes' => array(
'entity_test__id' => array(
'id',
),
),
'foreign keys' => array(
'entity_test__revisioned' => array(
'table' => 'entity_test',
'columns' => array(
'id' => 'id',
),
),
),
),
);
$this
->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setFieldNames('entity_test_revision', array_keys($this->storageDefinitions));
$this->storage
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this->storageSchema
->onEntityTypeCreate($this->entityType);
}
/**
* Tests the schema for non-revisionable, translatable entities.
*
* @covers ::__construct
* @covers ::getEntitySchemaTables
* @covers ::initializeDataTable
* @covers ::addTableDefaults
* @covers ::getEntityIndexName
* @covers ::processDataTable
*/
public function testGetSchemaTranslatable() {
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
'langcode' => 'langcode',
),
));
$this->storage
->expects($this
->any())
->method('getDataTable')
->will($this
->returnValue('entity_test_field_data'));
$this
->setUpStorageDefinition('langcode', array(
'columns' => array(
'value' => array(
'type' => 'varchar',
),
),
));
$this
->setUpStorageDefinition('default_langcode', array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'tiny',
),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'serial',
'not null' => TRUE,
),
'langcode' => array(
'type' => 'varchar',
'not null' => TRUE,
),
),
'primary key' => array(
'id',
),
'unique keys' => array(),
'indexes' => array(),
'foreign keys' => array(),
),
'entity_test_field_data' => array(
'description' => 'The data table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'int',
'not null' => TRUE,
),
'langcode' => array(
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array(
'id',
'langcode',
),
'unique keys' => array(),
'indexes' => array(
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
'table' => 'entity_test',
'columns' => array(
'id' => 'id',
),
),
),
),
);
$this
->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($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->storage
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this
->assertNull($this->storageSchema
->onEntityTypeCreate($this->entityType));
}
/**
* Tests the schema for revisionable, translatable entities.
*
* @covers ::__construct
* @covers ::getEntitySchemaTables
* @covers ::initializeDataTable
* @covers ::addTableDefaults
* @covers ::getEntityIndexName
* @covers ::initializeRevisionDataTable
* @covers ::processRevisionDataTable
*/
public function testGetSchemaRevisionableTranslatable() {
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
'revision' => 'revision_id',
'langcode' => 'langcode',
),
));
$this->storage
->expects($this
->exactly(3))
->method('getRevisionTable')
->will($this
->returnValue('entity_test_revision'));
$this->storage
->expects($this
->once())
->method('getDataTable')
->will($this
->returnValue('entity_test_field_data'));
$this->storage
->expects($this
->once())
->method('getRevisionDataTable')
->will($this
->returnValue('entity_test_revision_field_data'));
$this
->setUpStorageDefinition('revision_id', array(
'columns' => array(
'value' => array(
'type' => 'int',
),
),
));
$this
->setUpStorageDefinition('langcode', array(
'columns' => array(
'value' => array(
'type' => 'varchar',
),
),
));
$this
->setUpStorageDefinition('default_langcode', array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'tiny',
),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'serial',
'not null' => TRUE,
),
'revision_id' => array(
'type' => 'int',
'not null' => FALSE,
),
'langcode' => array(
'type' => 'varchar',
'not null' => TRUE,
),
),
'primary key' => array(
'id',
),
'unique keys' => array(
'entity_test__revision_id' => array(
'revision_id',
),
),
'indexes' => array(),
'foreign keys' => array(
'entity_test__revision' => array(
'table' => 'entity_test_revision',
'columns' => array(
'revision_id' => 'revision_id',
),
),
),
),
'entity_test_revision' => array(
'description' => 'The revision table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'int',
'not null' => TRUE,
),
'revision_id' => array(
'type' => 'serial',
'not null' => TRUE,
),
'langcode' => array(
'type' => 'varchar',
'not null' => TRUE,
),
),
'primary key' => array(
'revision_id',
),
'unique keys' => array(),
'indexes' => array(
'entity_test__id' => array(
'id',
),
),
'foreign keys' => array(
'entity_test__revisioned' => array(
'table' => 'entity_test',
'columns' => array(
'id' => 'id',
),
),
),
),
'entity_test_field_data' => array(
'description' => 'The data table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'int',
'not null' => TRUE,
),
'revision_id' => array(
'type' => 'int',
'not null' => TRUE,
),
'langcode' => array(
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array(
'id',
'langcode',
),
'unique keys' => array(),
'indexes' => array(
'entity_test__revision_id' => array(
'revision_id',
),
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
'table' => 'entity_test',
'columns' => array(
'id' => 'id',
),
),
),
),
'entity_test_revision_field_data' => array(
'description' => 'The revision data table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'int',
'not null' => TRUE,
),
'revision_id' => array(
'type' => 'int',
'not null' => TRUE,
),
'langcode' => array(
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array(
'revision_id',
'langcode',
),
'unique keys' => array(),
'indexes' => array(
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
'table' => 'entity_test',
'columns' => array(
'id' => 'id',
),
),
'entity_test__revision' => array(
'table' => 'entity_test_revision',
'columns' => array(
'revision_id' => 'revision_id',
),
),
),
),
);
$this
->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($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->storage
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this->storageSchema
->onEntityTypeCreate($this->entityType);
}
/**
* Tests the schema for a field dedicated table.
*
* @covers ::onFieldStorageDefinitionCreate
* @covers ::getDedicatedTableSchema
* @covers ::createDedicatedTableSchema
*/
public function testDedicatedTableSchema() {
$entity_type_id = 'entity_test';
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
),
));
// Setup a field having a dedicated schema.
$field_name = $this
->getRandomGenerator()
->name();
$this
->setUpStorageDefinition($field_name, array(
'columns' => array(
'shape' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
'color' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
),
'foreign keys' => array(
'color' => array(
'table' => 'color',
'columns' => array(
'color' => 'id',
),
),
),
'unique keys' => array(),
'indexes' => array(),
));
$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 = array(
$entity_type_id . '__' . $field_name => array(
'description' => "Data storage for {$entity_type_id} field {$field_name}.",
'fields' => array(
'bundle' => array(
'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' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
'default' => 0,
'description' => 'A boolean indicating whether this data item has been deleted',
),
'entity_id' => array(
'type' => 'int',
'unsigned' => true,
'not null' => true,
'description' => 'The entity id this data is attached to',
),
'revision_id' => array(
'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' => array(
'type' => 'varchar_ascii',
'length' => 32,
'not null' => true,
'default' => '',
'description' => 'The language code for this data item.',
),
'delta' => array(
'type' => 'int',
'unsigned' => true,
'not null' => true,
'description' => 'The sequence number for this data item, used for multi-value fields',
),
$field_name . '_shape' => array(
'type' => 'varchar',
'length' => 32,
'not null' => false,
),
$field_name . '_color' => array(
'type' => 'varchar',
'length' => 32,
'not null' => false,
),
),
'primary key' => array(
'entity_id',
'deleted',
'delta',
'langcode',
),
'indexes' => array(
'bundle' => array(
'bundle',
),
'revision_id' => array(
'revision_id',
),
),
'foreign keys' => array(
$field_name . '_color' => array(
'table' => 'color',
'columns' => array(
$field_name . '_color' => 'id',
),
),
),
),
);
$this
->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames($entity_type_id, array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns($entity_type_id, array(
'default_langcode',
));
$this->storage
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this
->assertNull($this->storageSchema
->onFieldStorageDefinitionCreate($field_storage));
}
/**
* Tests the schema for a field dedicated table for an entity with a string identifier.
*
* @covers ::onFieldStorageDefinitionCreate
* @covers ::getDedicatedTableSchema
* @covers ::createDedicatedTableSchema
*/
public function testDedicatedTableSchemaForEntityWithStringIdentifier() {
$entity_type_id = 'entity_test';
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
),
));
// Setup a field having a dedicated schema.
$field_name = $this
->getRandomGenerator()
->name();
$this
->setUpStorageDefinition($field_name, array(
'columns' => array(
'shape' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
'color' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
),
'foreign keys' => array(
'color' => array(
'table' => 'color',
'columns' => array(
'color' => 'id',
),
),
),
'unique keys' => array(),
'indexes' => array(),
));
$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 = array(
$entity_type_id . '__' . $field_name => array(
'description' => "Data storage for {$entity_type_id} field {$field_name}.",
'fields' => array(
'bundle' => array(
'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' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
'default' => 0,
'description' => 'A boolean indicating whether this data item has been deleted',
),
'entity_id' => array(
'type' => 'varchar_ascii',
'length' => 128,
'not null' => true,
'description' => 'The entity id this data is attached to',
),
'revision_id' => array(
'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' => array(
'type' => 'varchar_ascii',
'length' => 32,
'not null' => true,
'default' => '',
'description' => 'The language code for this data item.',
),
'delta' => array(
'type' => 'int',
'unsigned' => true,
'not null' => true,
'description' => 'The sequence number for this data item, used for multi-value fields',
),
$field_name . '_shape' => array(
'type' => 'varchar',
'length' => 32,
'not null' => false,
),
$field_name . '_color' => array(
'type' => 'varchar',
'length' => 32,
'not null' => false,
),
),
'primary key' => array(
'entity_id',
'deleted',
'delta',
'langcode',
),
'indexes' => array(
'bundle' => array(
'bundle',
),
'revision_id' => array(
'revision_id',
),
),
'foreign keys' => array(
$field_name . '_color' => array(
'table' => 'color',
'columns' => array(
$field_name . '_color' => 'id',
),
),
),
),
);
$this
->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames($entity_type_id, array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns($entity_type_id, array(
'default_langcode',
));
$this->storage
->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
->getMock('\\Drupal\\Core\\Entity\\EntityTypeInterface');
$updated_entity_type_definition
->expects($this
->any())
->method('getStorageClass')
->willReturn('\\Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema');
$original_entity_type_definition = $this
->getMock('\\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
->getMock('\\Drupal\\Core\\Entity\\EntityTypeInterface');
$original_entity_type_definition_other_nonexisting
->expects($this
->any())
->method('getStorageClass')
->willReturn('bar');
$original_entity_type_definition_other_existing = $this
->getMock('\\Drupal\\Core\\Entity\\EntityTypeInterface');
$original_entity_type_definition_other_existing
->expects($this
->any())
->method('getStorageClass')
->willReturn('\\Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema');
return [
// Case 1: same storage class, ::hasData() === TRUE.
[
$updated_entity_type_definition,
$original_entity_type_definition,
TRUE,
TRUE,
TRUE,
],
// Case 2: same storage class, ::hasData() === FALSE.
[
$updated_entity_type_definition,
$original_entity_type_definition,
FALSE,
TRUE,
FALSE,
],
// Case 3: different storage class, original storage class does not exist.
[
$updated_entity_type_definition,
$original_entity_type_definition_other_nonexisting,
NULL,
TRUE,
TRUE,
],
// Case 4: different storage class, original storage class exists,
// ::hasData() === TRUE.
[
$updated_entity_type_definition,
$original_entity_type_definition_other_existing,
TRUE,
TRUE,
TRUE,
],
// Case 5: different storage class, original storage class exists,
// ::hasData() === FALSE.
[
$updated_entity_type_definition,
$original_entity_type_definition_other_existing,
FALSE,
TRUE,
FALSE,
],
// Case 6: same storage class, ::hasData() === TRUE, no structure changes.
[
$updated_entity_type_definition,
$original_entity_type_definition,
TRUE,
FALSE,
FALSE,
],
// Case 7: different storage class, original storage class exists,
//::hasData() === TRUE, no structure changes.
[
$updated_entity_type_definition,
$original_entity_type_definition_other_existing,
TRUE,
FALSE,
FALSE,
],
];
}
/**
* @covers ::requiresEntityDataMigration
*
* @dataProvider providerTestRequiresEntityDataMigration
*/
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(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
),
));
$original_storage = $this
->getMockBuilder('Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorage')
->disableOriginalConstructor()
->getMock();
$original_storage
->expects($this
->exactly(is_null($original_storage_has_data) || !$shared_table_structure_changed ? 0 : 1))
->method('hasData')
->willReturn($original_storage_has_data);
// Assert hasData() is never called on the new storage definition.
$this->storage
->expects($this
->never())
->method('hasData');
$connection = $this
->getMockBuilder('Drupal\\Core\\Database\\Connection')
->disableOriginalConstructor()
->getMock();
$this->entityManager
->expects($this
->any())
->method('createHandlerInstance')
->willReturn($original_storage);
$this->storageSchema = $this
->getMockBuilder('Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema')
->setConstructorArgs(array(
$this->entityManager,
$this->entityType,
$this->storage,
$connection,
))
->setMethods(array(
'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));
}
/**
* Data provider for ::testRequiresEntityStorageSchemaChanges().
*/
public function providerTestRequiresEntityStorageSchemaChanges() {
$cases = [];
$updated_entity_type_definition = $this
->getMock('\\Drupal\\Core\\Entity\\ContentEntityTypeInterface');
$original_entity_type_definition = $this
->getMock('\\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');
// Storage class changes should not impact this at all, and should not be
// checked.
$updated = clone $updated_entity_type_definition;
$original = clone $original_entity_type_definition;
$updated
->expects($this
->never())
->method('getStorageClass');
$original
->expects($this
->never())
->method('getStorageClass');
// Case 1: No shared table changes should not require change.
$cases[] = [
$updated,
$original,
FALSE,
FALSE,
FALSE,
];
// Case 2: A change in the entity schema should result in required changes.
$cases[] = [
$updated,
$original,
TRUE,
TRUE,
FALSE,
];
// Case 3: Has shared table changes should result in required changes.
$cases[] = [
$updated,
$original,
TRUE,
FALSE,
TRUE,
];
// Case 4: Changing translation should result in required changes.
$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,
];
// Case 5: Changing revisionable should result in required changes.
$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;
}
/**
* @covers ::requiresEntityStorageSchemaChanges
*
* @dataProvider providerTestRequiresEntityStorageSchemaChanges
*/
public function testRequiresEntityStorageSchemaChanges(ContentEntityTypeInterface $updated, ContentEntityTypeInterface $original, $requires_change, $change_schema, $change_shared_table) {
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
),
));
$this
->setUpStorageSchema();
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns('entity_test', array(
'default_langcode',
));
$this->storage
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
// Setup storage schema.
if ($change_schema) {
$this->storageSchema
->expects($this
->once())
->method('loadEntitySchemaData')
->willReturn(array());
}
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));
}
/**
* Sets up the storage schema object to test.
*
* This uses the field definitions set in $this->storageDefinitions.
*
* @param array $expected
* (optional) An associative array describing the expected entity schema to
* be created. Defaults to expecting nothing.
*/
protected function setUpStorageSchema(array $expected = array()) {
$this->entityManager
->expects($this
->any())
->method('getDefinition')
->with($this->entityType
->id())
->will($this
->returnValue($this->entityType));
$this->entityManager
->expects($this
->any())
->method('getFieldStorageDefinitions')
->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
->getMock('Drupal\\Core\\KeyValueStore\\KeyValueStoreInterface');
$this->storageSchema = $this
->getMockBuilder('Drupal\\Core\\Entity\\Sql\\SqlContentEntityStorageSchema')
->setConstructorArgs(array(
$this->entityManager,
$this->entityType,
$this->storage,
$connection,
))
->setMethods(array(
'installedStorageSchema',
'loadEntitySchemaData',
'hasSharedTableNameChanges',
'isTableEmpty',
))
->getMock();
$this->storageSchema
->expects($this
->any())
->method('installedStorageSchema')
->will($this
->returnValue($key_value));
$this->storageSchema
->expects($this
->any())
->method('isTableEmpty')
->willReturn(FALSE);
}
/**
* Sets up a field definition.
*
* @param string $field_name
* The field name.
* @param array $schema
* The schema array of the field definition, as returned from
* FieldStorageDefinitionInterface::getSchema().
*/
public function setUpStorageDefinition($field_name, array $schema) {
$this->storageDefinitions[$field_name] = $this
->getMock('Drupal\\Tests\\Core\\Field\\TestBaseFieldDefinitionInterface');
$this->storageDefinitions[$field_name]
->expects($this
->any())
->method('isBaseField')
->will($this
->returnValue(TRUE));
// getName() is called once for each table.
$this->storageDefinitions[$field_name]
->expects($this
->any())
->method('getName')
->will($this
->returnValue($field_name));
// getSchema() is called once for each table.
$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']));
// Add property definitions.
if (!empty($schema['columns'])) {
$property_definitions = array();
foreach ($schema['columns'] as $column => $info) {
$property_definitions[$column] = $this
->getMock('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));
}
}
/**
* ::onEntityTypeUpdate
*/
public function testonEntityTypeUpdateWithNewIndex() {
$this->entityType = $original_entity_type = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array(
'id' => 'id',
),
));
// Add a field with a really long index.
$this
->setUpStorageDefinition('long_index_name', array(
'columns' => array(
'long_index_name' => array(
'type' => 'int',
),
),
'indexes' => array(
'long_index_name_really_long_long_name' => array(
array(
'long_index_name',
10,
),
),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
'fields' => array(
'id' => array(
'type' => 'serial',
'not null' => TRUE,
),
'long_index_name' => array(
'type' => 'int',
'not null' => FALSE,
),
),
'indexes' => array(
'entity_test__b588603cb9' => array(
array(
'long_index_name',
10,
),
),
),
),
);
$this
->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping
->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping
->setExtraColumns('entity_test', array(
'default_langcode',
));
$this->storage
->expects($this
->any())
->method('getTableMapping')
->will($this
->returnValue($table_mapping));
$this->storageSchema
->expects($this
->any())
->method('loadEntitySchemaData')
->willReturn([
'entity_test' => [
'indexes' => [
// A changed index definition.
'entity_test__b588603cb9' => [
'longer_index_name',
],
// An index that has been removed.
'entity_test__removed_field' => [
'removed_field',
],
],
],
]);
// The original indexes should be dropped before the new one is added.
$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']);
// If the parameters don't match, the assertions above will throw an
// exception.
return TRUE;
}));
$this
->assertNull($this->storageSchema
->onEntityTypeUpdate($this->entityType, $original_entity_type));
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
SqlContentEntityStorageSchemaTest:: |
protected | property | The mocked DB schema handler. | |
SqlContentEntityStorageSchemaTest:: |
protected | property | The mocked entity manager used in this test. | |
SqlContentEntityStorageSchemaTest:: |
protected | property | The mocked entity type used in this test. | |
SqlContentEntityStorageSchemaTest:: |
protected | property | The mocked SQL storage used in this test. | |
SqlContentEntityStorageSchemaTest:: |
protected | property | The mocked field definitions used in this test. | |
SqlContentEntityStorageSchemaTest:: |
protected | property | The storage schema handler used in this test. | |
SqlContentEntityStorageSchemaTest:: |
public | function | ||
SqlContentEntityStorageSchemaTest:: |
public | function | Data provider for ::testRequiresEntityStorageSchemaChanges(). | |
SqlContentEntityStorageSchemaTest:: |
protected | function |
Overrides UnitTestCase:: |
|
SqlContentEntityStorageSchemaTest:: |
public | function | Sets up a field definition. | |
SqlContentEntityStorageSchemaTest:: |
protected | function | Sets up the storage schema object to test. | |
SqlContentEntityStorageSchemaTest:: |
public | function | Tests the schema for a field dedicated table. | |
SqlContentEntityStorageSchemaTest:: |
public | function | Tests the schema for a field dedicated table for an entity with a string identifier. | |
SqlContentEntityStorageSchemaTest:: |
public | function | Tests the schema for non-revisionable, non-translatable entities. | |
SqlContentEntityStorageSchemaTest:: |
public | function | Tests the schema for revisionable, non-translatable entities. | |
SqlContentEntityStorageSchemaTest:: |
public | function | Tests the schema for revisionable, translatable entities. | |
SqlContentEntityStorageSchemaTest:: |
public | function | Tests the schema for non-revisionable, translatable entities. | |
SqlContentEntityStorageSchemaTest:: |
public | function | ::onEntityTypeUpdate | |
SqlContentEntityStorageSchemaTest:: |
public | function | @covers ::requiresEntityDataMigration | |
SqlContentEntityStorageSchemaTest:: |
public | function | @covers ::requiresEntityStorageSchemaChanges | |
UnitTestCase:: |
protected | property | The random generator. | |
UnitTestCase:: |
protected | property | The app root. | |
UnitTestCase:: |
protected | function | Asserts if two arrays are equal by sorting them first. | |
UnitTestCase:: |
protected | function | Mocks a block with a block plugin. | |
UnitTestCase:: |
protected | function | Returns a stub class resolver. | |
UnitTestCase:: |
public | function | Returns a stub config factory that behaves according to the passed in array. | |
UnitTestCase:: |
public | function | Returns a stub config storage that returns the supplied configuration. | |
UnitTestCase:: |
protected | function | Sets up a container with a cache tags invalidator. | |
UnitTestCase:: |
protected | function | Gets the random generator for the utility methods. | |
UnitTestCase:: |
public | function | Returns a stub translation manager that just returns the passed string. | |
UnitTestCase:: |
public | function | Generates a unique random string containing letters and numbers. |