diff --git a/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php b/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php index 81c50bf..03c32c9 100644 --- a/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php +++ b/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php @@ -140,28 +140,29 @@ protected function getTables() { */ protected function addFieldSchema(array &$schema, $field_name, array $column_mapping) { $field_schema = $this->storageDefinitions[$field_name]->getSchema(); + $field_description = $this->storageDefinitions[$field_name]->getDescription(); foreach ($column_mapping as $field_column_name => $schema_field_name) { $column_schema = $field_schema['columns'][$field_column_name]; $schema['fields'][$schema_field_name] = $column_schema; - $schema['fields'][$schema_field_name]['description'] = $this->storageDefinitions[$field_name]->getDescription(); + $schema['fields'][$schema_field_name]['description'] = $field_description; // Only entity keys are required. $schema['fields'][$schema_field_name]['not null'] = (bool) $this->entityType->getKey($field_name); } if (!empty($field_schema['indexes'])) { - $indexes = $this->getFieldIndexes($field_name, $column_mapping); + $indexes = $this->getFieldIndexes($field_name, $field_schema, $column_mapping); $schema['indexes'] = array_merge($schema['indexes'], $indexes); } if (!empty($field_schema['unique keys'])) { - $unique_keys = $this->getFieldUniqueKeys($field_name, $column_mapping); + $unique_keys = $this->getFieldUniqueKeys($field_name, $field_schema, $column_mapping); $schema['unique keys'] = array_merge($schema['unique keys'], $unique_keys); } if (!empty($field_schema['foreign keys'])) { - $foreign_keys = $this->getFieldForeignKeys($field_name, $column_mapping); + $foreign_keys = $this->getFieldForeignKeys($field_name, $field_schema, $column_mapping); $schema['foreign keys'] = array_merge($schema['foreign keys'], $foreign_keys); } } @@ -171,14 +172,16 @@ protected function addFieldSchema(array &$schema, $field_name, array $column_map * * @param string $field_name * The name of the field. - * @param string[] $column_mappi + * @param array $field_schema + * The schema of the field. + * @param string[] $column_mapping * A mapping of field column names to database column names. * * @return array * The schema definition for the indexes. */ - protected function getFieldIndexes($field_name, array $column_mapping) { - return $this->getFieldSchemaData('indexes', $field_name, $column_mapping); + protected function getFieldIndexes($field_name, array $field_schema, array $column_mapping) { + return $this->getFieldSchemaData($field_name, $field_schema, $column_mapping, 'indexes'); } /** @@ -186,38 +189,41 @@ protected function getFieldIndexes($field_name, array $column_mapping) { * * @param string $field_name * The name of the field. - * @param string[] $column_mappi + * @param array $field_schema + * The schema of the field. + * @param string[] $column_mapping * A mapping of field column names to database column names. * * @return array * The schema definition for the unique keys. */ - protected function getFieldUniqueKeys($field_name, array $column_mapping) { - return $this->getFieldSchemaData('unique keys', $field_name, $column_mapping); + protected function getFieldUniqueKeys($field_name, array $field_schema, array $column_mapping) { + return $this->getFieldSchemaData($field_name, $field_schema, $column_mapping, 'unique keys'); } /** * Returns field schema data for the given key. * - * @param string $key - * The schema key, e.g. 'indexes' or 'unique keys'. * @param string $field_name * The name of the field. - * @param string[] $column_mappi + * @param array $field_schema + * The schema of the field. + * @param string[] $column_mapping * A mapping of field column names to database column names. + * @param string $schema_key + * The type of schema data. Either 'indexes' or 'unique keys'. * * @return array * The schema definition for the specified key. */ - protected function getFieldSchemaData($key, $field_name, array $column_mapping) { + protected function getFieldSchemaData($field_name, array $field_schema, array $column_mapping, $schema_key) { $data = array(); - $schema = $this->storageDefinitions[$field_name]->getSchema(); - foreach ($schema[$key] as $key => $columns) { + foreach ($field_schema[$schema_key] as $key => $columns) { // Similar to the database column naming, we use the field name as the - // index or unique key name for single-column fields and a combination - // of field and index or unique key name for multi-column fields. - $real_name = count($schema['columns']) == 1 + // index or unique key name for single-column fields and a combination of + // field and index or unique key name for multi-column fields. + $real_name = count($field_schema['columns']) == 1 ? 'field__' . $field_name : 'field__' . $field_name . '__' . $key; @@ -240,21 +246,24 @@ protected function getFieldSchemaData($key, $field_name, array $column_mapping) /** * Returns field foreign keys. * - * @param \Drupal\Core\Field\FieldDefinitionInterface $definition - * The field definition. + * @param string $field_name + * The name of the field. + * @param array $field_schema + * The schema of the field. + * @param string[] $column_mapping + * A mapping of field column names to database column names. * * @return array * The schema definition for the foreign keys. */ - protected function getFieldForeignKeys($field_name, array $column_mapping) { + protected function getFieldForeignKeys($field_name, array $field_schema, array $column_mapping) { $foreign_keys = array(); - $schema = $this->storageDefinitions[$field_name]->getSchema(); - foreach ($schema['foreign keys'] as $specifier => $specification) { + foreach ($field_schema['foreign keys'] as $specifier => $specification) { // Similar to the database column naming, we use the field name as the - // index or unique key name for single-column fields and a combination - // of field and index or unique key name for multi-column fields. - $real_name = count($schema['columns']) == 1 + // foreign key name for single-column fields and a combination of field + // and foreign key name for multi-column fields. + $real_name = count($field_schema['columns']) == 1 ? 'field__' . $field_name : 'field__' . $field_name . '__' . $specifier; $foreign_keys[$real_name]['table'] = $specification['table']; @@ -464,6 +473,8 @@ protected function processRevisionDataTable(array &$schema) { /** * Processes the specified entity key. * + * @param array $schema + * The table schema, passed by reference. * @param string $key * The entity key name. */ diff --git a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php index 0fa6e92..258c25a 100644 --- a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php +++ b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php @@ -124,6 +124,8 @@ public function getColumnMapping($field_name) { */ public function addFieldColumns($table_name, array $field_names) { $this->fieldNames[$table_name] = $field_names; + // Force the re-computation of the column list. + unset($this->allColumns[$table_name]); return $this; } @@ -149,6 +151,8 @@ public function getExtraColumns($table_name) { */ public function addExtraColumns($table_name, array $column_names) { $this->extraColumns[$table_name] = $column_names; + // Force the re-computation of the column list. + unset($this->allColumns[$table_name]); return $this; } diff --git a/core/tests/Drupal/Tests/Core/Entity/Schema/ContentEntitySchemaHandlerTest.php b/core/tests/Drupal/Tests/Core/Entity/Schema/ContentEntitySchemaHandlerTest.php index 7c5cd52..855a0dc 100644 --- a/core/tests/Drupal/Tests/Core/Entity/Schema/ContentEntitySchemaHandlerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/Schema/ContentEntitySchemaHandlerTest.php @@ -7,8 +7,8 @@ namespace Drupal\Tests\Core\Entity\Schema; use Drupal\Core\Entity\ContentEntityDatabaseStorage; -use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Schema\ContentEntitySchemaHandler; +use Drupal\Core\Entity\Sql\DefaultTableMapping; use Drupal\Tests\UnitTestCase; /** @@ -43,13 +43,6 @@ class ContentEntitySchemaHandlerTest extends UnitTestCase { protected $storage; /** - * A list of table names to use for the test. - * - * @var string[] - */ - protected $tableNames; - - /** * The mocked field definitions used in this test. * * @var \Drupal\Core\Field\FieldStorageDefinitionInterface[]|\PHPUnit_Framework_MockObject_MockObject[] @@ -103,7 +96,19 @@ public function setUp() { * @param bool $uuid_key * Whether or not the tested entity type should have a UUID key. * + * @covers ::__construct * @covers ::getSchema + * @covers ::getTables + * @covers ::initializeBaseTable + * @covers ::getEntityIndexName + * @covers ::addFieldSchema + * @covers ::getFieldIndexes + * @covers ::getFieldUniqueKeys + * @covers ::getFieldForeignKeys + * @covers ::getFieldSchemaData + * @covers ::addDefaultLangcodeSchema + * @covers ::processBaseTable + * @covers ::processIdentifierSchema * * @dataProvider providerTestGetSchemaLayoutBase */ @@ -119,7 +124,7 @@ public function testGetSchemaLayoutBase($uuid_key) { ->method('getTableLayout') ->will($this->returnValue(ContentEntityDatabaseStorage::LAYOUT_BASE)); - $this->setUpBaseLayoutFieldDefinitions(); + $this->setUpFieldDefinitions(); if ($uuid_key) { $this->setUpStorageDefinition('uuid', array( 'columns' => array( @@ -133,34 +138,110 @@ public function testGetSchemaLayoutBase($uuid_key) { $this->setUpSchemaHandler(); - $this->tableNames = array('entity_test'); - $this->setUpTableMapping(); + $table_mapping = new DefaultTableMapping($this->storageDefinitions); + $table_mapping->addFieldColumns('entity_test', array_keys($this->storageDefinitions)); + $table_mapping->addExtraColumns('entity_test', array('default_langcode')); + + $this->storage->expects($this->once()) + ->method('getTableMapping') + ->will($this->returnValue($table_mapping)); $expected = array( 'entity_test' => array( 'description' => 'The base table for entity_test entities.', 'fields' => array( 'id' => array( - 'type' => 'serial', 'description' => 'The id field.', + 'type' => 'serial', 'not null' => TRUE, ), 'name' => array( + 'description' => 'The name field.', 'type' => 'varchar', 'length' => 255, - 'description' => 'The name field.', 'not null' => FALSE, ), - 'type' => array( + 'description__value' => array( + 'description' => 'The description field.', + 'type' => 'text', + 'not null' => FALSE, + ), + 'description__format' => array( + 'description' => 'The description field.', + 'type' => 'varchar', + 'not null' => FALSE, + ), + 'owner' => array( + 'description' => 'The owner field.', + 'type' => 'int', + 'not null' => FALSE, + ), + 'translator' => array( + 'description' => 'The translator field.', + 'type' => 'int', + 'not null' => FALSE, + ), + 'location__country' => array( + 'description' => 'The location field.', + 'type' => 'varchar', + 'not null' => FALSE, + ), + 'location__state' => array( + 'description' => 'The location field.', 'type' => 'varchar', - 'length' => 32, - 'description' => 'The type field.', 'not null' => FALSE, ), + 'location__city' => array( + 'description' => 'The location field.', + 'type' => 'varchar', + 'not null' => FALSE, + ), + 'editor' => array( + 'description' => 'The editor field.', + 'type' => 'int', + 'not null' => FALSE, + ), + 'editor_revision__target_id' => array( + 'description' => 'The editor_revision field.', + 'type' => 'int', + 'not null' => FALSE, + ), + 'editor_revision__target_revision_id' => array( + 'description' => 'The editor_revision field.', + 'type' => 'int', + 'not null' => FALSE, + ), + 'default_langcode' => array( + 'description' => 'Boolean indicating whether field values are in the default entity language.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 1, + ), ), 'primary key' => array('id'), - 'indexes' => array(), - 'foreign keys' => array(), + 'indexes' => array( + 'field__owner' => array('owner'), + 'field__translator' => array(array('translator', 10)), + 'field__location__city' => array( + 'location__country', + 'location__state', + array('location__city', 10), + ), + ), + 'foreign keys' => array( + 'field__editor' => array( + 'table' => 'users', + 'columns' => array( + 'editor' => 'uid', + ), + ), + 'field__editor_revision__editor' => array( + 'table' => 'users', + 'columns' => array( + 'editor_revision__target_id' => 'uid', + ) + ) + ), ), ); if ($uuid_key) { @@ -195,8 +276,8 @@ public function providerTestGetSchemaLayoutBase() { /** * Sets up the field definitions that are used for the base storage layout. */ - protected function setUpBaseLayoutFieldDefinitions() { - // @see \Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem::schema() + protected function setUpFieldDefinitions() { + // Add a single-column field. $this->setUpStorageDefinition('id', array( 'columns' => array( 'value' => array( @@ -204,7 +285,7 @@ protected function setUpBaseLayoutFieldDefinitions() { ), ), )); - // @see \Drupal\Core\Field\Plugin\Field\FieldType\StringItem::schema() + // Add a field with a 'length' constraint. $this->setUpStorageDefinition('name', array( 'columns' => array( 'value' => array( @@ -213,12 +294,92 @@ protected function setUpBaseLayoutFieldDefinitions() { ), ), )); - // @see \Drupal\Core\Field\Plugin\Field\FieldType\StringItem::schema() - $this->setUpStorageDefinition('type', array( + // Add a multi-column field. + $this->setUpStorageDefinition('description', array( 'columns' => array( 'value' => array( + 'type' => 'text', + 'description' => 'The text value', + ), + 'format' => array( + 'type' => 'varchar', + 'description' => 'The text description', + ), + ), + )); + // Add a field with an index. + $this->setUpStorageDefinition('owner', array( + 'columns' => array( + 'target_id' => array( + 'description' => 'The ID of the target entity.', + '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( + 'description' => 'The ID of the target entity.', + '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', - 'length' => EntityTypeInterface::BUNDLE_MAX_LENGTH, + ), + 'city' => array( + 'type' => 'varchar', + ) + ), + 'indexes' => array( + '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( + 'editor' => 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( + 'editor' => array( + 'table' => 'users', + 'columns' => array( + 'target_id' => 'uid', + ), ), ), )); @@ -242,40 +403,6 @@ public function setUpSchemaHandler() { } /** - * Sets up the table mapping. - * - * This uses the field definitions set in static::$tablesNames, - * static::$fieldDefinitions. - */ - public function setUpTableMapping() { - $field_names = array_keys($this->storageDefinitions); - - $table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface'); - $table_mapping->expects($this->once()) - ->method('getTableNames') - ->will($this->returnValue($this->tableNames)); - - $table_mapping->expects($this->once()) - ->method('getFieldNames') - ->with(reset($this->tableNames)) - ->will($this->returnValue($field_names)); - $table_mapping->expects($this->any()) - ->method('getColumnMapping') - ->will($this->returnCallback(function ($field_name) { - return array('value' => $field_name); - })); - - $table_mapping->expects($this->once()) - ->method('getExtraColumns') - ->with('entity_test') - ->will($this->returnValue(array())); - - $this->storage->expects($this->once()) - ->method('getTableMapping') - ->will($this->returnValue($table_mapping)); - } - - /** * Sets up a field definition. * * @param string $field_name @@ -289,9 +416,12 @@ public function setUpStorageDefinition($field_name, array $schema) { $this->storageDefinitions[$field_name]->expects($this->once()) ->method('getDescription') ->will($this->returnValue("The $field_name field.")); - $this->storageDefinitions[$field_name]->expects($this->exactly(1)) + $this->storageDefinitions[$field_name]->expects($this->once()) ->method('getSchema') ->will($this->returnValue($schema)); + $this->storageDefinitions[$field_name]->expects($this->once()) + ->method('getColumns') + ->will($this->returnValue($schema['columns'])); } } diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/DefaultTableMappingTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/DefaultTableMappingTest.php new file mode 100644 index 0000000..c53dc32 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/DefaultTableMappingTest.php @@ -0,0 +1,267 @@ + 'Default table mapping', + 'description' => 'Check that the default table mapping works.', + 'group' => 'Entity', + ]; + } + + /** + * Tests DefaultTableMapping::getTableNames(). + * + * @covers ::getTableNames + */ + public function testGetTableNames() { + // The storage definitions are only used in getColumnMapping() so we do not + // need to provide any here. + $table_mapping = new DefaultTableMapping([]); + $this->assertSame([], $table_mapping->getTableNames()); + + $table_mapping->addFieldColumns('foo', []); + $this->assertSame(['foo'], $table_mapping->getTableNames()); + + $table_mapping->addFieldColumns('bar', []); + $this->assertSame(['foo', 'bar'], $table_mapping->getTableNames()); + + $table_mapping->addExtraColumns('baz', []); + $this->assertSame(['foo', 'bar', 'baz'], $table_mapping->getTableNames()); + + // Test that table names are not duplicated. + $table_mapping->addExtraColumns('foo', []); + $this->assertSame(['foo', 'bar', 'baz'], $table_mapping->getTableNames()); + } + + /** + * Tests DefaultTableMapping::getAllColumns(). + * + * @covers ::__construct() + * @covers ::getAllColumns() + * @covers ::getFieldNames() + * @covers ::getColumnMapping() + * @covers ::addFieldColumns() + * @covers ::getExtraColumns() + * @covers ::addExtraColumns() + */ + public function testGetAllColumns() { + // Set up single-column and multi-column definitions. + $definitions['id'] = $this->setUpDefinition(['value']); + $definitions['name'] = $this->setUpDefinition(['value']); + $definitions['type'] = $this->setUpDefinition(['value']); + $definitions['description'] = $this->setUpDefinition(['value', 'format']); + $definitions['owner'] = $this->setUpDefinition([ + 'target_id', + 'target_revision_id', + ]); + + $table_mapping = new DefaultTableMapping($definitions); + $expected = []; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + // Test adding field columns. + $table_mapping->addFieldColumns('test', ['id']); + $expected = ['id']; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + $table_mapping->addFieldColumns('test', ['id', 'name']); + $expected = ['id', 'name']; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + $table_mapping->addFieldColumns('test', ['id', 'name', 'type']); + $expected = ['id', 'name', 'type']; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + $table_mapping->addFieldColumns('test', [ + 'id', + 'name', + 'type', + 'description', + ]); + $expected = [ + 'id', + 'name', + 'type', + 'description__value', + 'description__format', + ]; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + $table_mapping->addFieldColumns('test', [ + 'id', + 'name', + 'type', + 'description', + 'owner', + ]); + $expected = [ + 'id', + 'name', + 'type', + 'description__value', + 'description__format', + 'owner__target_id', + 'owner__target_revision_id', + ]; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + // Test adding extra columns. + $table_mapping->addFieldColumns('test', []); + $table_mapping->addExtraColumns('test', ['default_langcode']); + $expected = ['default_langcode']; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + $table_mapping->addExtraColumns('test', [ + 'default_langcode', + 'default_revision', + ]); + $expected = ['default_langcode', 'default_revision']; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + + // Test adding both field and extra columns. + $table_mapping->addFieldColumns('test', [ + 'id', + 'name', + 'type', + 'description', + 'owner', + ]); + $table_mapping->addExtraColumns('test', [ + 'default_langcode', + 'default_revision', + ]); + $expected = [ + 'id', + 'name', + 'type', + 'description__value', + 'description__format', + 'owner__target_id', + 'owner__target_revision_id', + 'default_langcode', + 'default_revision', + ]; + $this->assertSame($expected, $table_mapping->getAllColumns('test')); + } + + /** + * Tests DefaultTableMapping::getFieldNames(). + * + * @covers ::getFieldNames() + * @covers ::addFieldColumns() + */ + public function testGetFieldNames() { + // The storage definitions are only used in getColumnMapping() so we do not + // need to provide any here. + $table_mapping = new DefaultTableMapping([]); + + // Test that requesting the list of field names for a table for which no + // fields have been added does not fail. + $this->assertSame([], $table_mapping->getFieldNames('foo')); + + $return = $table_mapping->addFieldColumns('foo', ['id', 'name', 'type']); + $this->assertSame($table_mapping, $return); + $expected = ['id', 'name', 'type']; + $this->assertSame($expected, $table_mapping->getFieldNames('foo')); + $this->assertSame([], $table_mapping->getFieldNames('bar')); + + $return = $table_mapping->addFieldColumns('bar', ['description', 'owner']); + $this->assertSame($table_mapping, $return); + $expected = ['description', 'owner']; + $this->assertSame($expected, $table_mapping->getFieldNames('bar')); + // Test that the previously added field names are unaffected. + $expected = ['id', 'name', 'type']; + $this->assertSame($expected, $table_mapping->getFieldNames('foo')); + } + + /** + * Tests DefaultTableMapping::getColumnMapping(). + * + * @covers ::__construct() + * @covers ::getColumnMapping + */ + public function testGetColumnMapping() { + $definitions['test'] = $this->setUpDefinition([]); + $table_mapping = new DefaultTableMapping($definitions); + $expected = []; + $this->assertSame($expected, $table_mapping->getColumnMapping('test')); + + $definitions['test'] = $this->setUpDefinition(['value']); + $table_mapping = new DefaultTableMapping($definitions); + $expected = ['value' => 'test']; + $this->assertSame($expected, $table_mapping->getColumnMapping('test')); + + $definitions['test'] = $this->setUpDefinition(['value', 'format']); + $table_mapping = new DefaultTableMapping($definitions); + $expected = ['value' => 'test__value', 'format' => 'test__format']; + $this->assertSame($expected, $table_mapping->getColumnMapping('test')); + } + + /** + * Tests DefaultTableMapping::getExtraColumns(). + * + * @covers ::getExtraColumns() + * @covers ::addExtraColumns() + */ + public function testGetExtraColumns() { + // The storage definitions are only used in getColumnMapping() so we do not + // need to provide any here. + $table_mapping = new DefaultTableMapping([]); + + // Test that requesting the list of field names for a table for which no + // fields have been added does not fail. + $this->assertSame([], $table_mapping->getExtraColumns('foo')); + + $return = $table_mapping->addExtraColumns('foo', ['id', 'name', 'type']); + $this->assertSame($table_mapping, $return); + $expected = ['id', 'name', 'type']; + $this->assertSame($expected, $table_mapping->getExtraColumns('foo')); + $this->assertSame([], $table_mapping->getExtraColumns('bar')); + + $return = $table_mapping->addExtraColumns('bar', ['description', 'owner']); + $this->assertSame($table_mapping, $return); + $expected = ['description', 'owner']; + $this->assertSame($expected, $table_mapping->getExtraColumns('bar')); + // Test that the previously added field names are unaffected. + $expected = ['id', 'name', 'type']; + $this->assertSame($expected, $table_mapping->getExtraColumns('foo')); + } + + /** + * Sets up a field storage definition for the test. + * + * @param array $column_names + * An array of column names for the storage definition. + * + * @return \Drupal\Core\Field\FieldStorageDefinitionInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected function setUpDefinition(array $column_names) { + $definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface'); + $definition->expects($this->any()) + ->method('getColumns') + ->will($this->returnValue(array_fill_keys($column_names, []))); + return $definition; + } + +} \ No newline at end of file