diff -u b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php --- b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -1690,7 +1690,7 @@ if (count($columns) > 1) { $or = $query->orConditionGroup(); foreach ($columns as $column_name => $data) { - $or->isNotNull($table_mapping->getFieldColumnName($storage_definition, $column_name)); + $or->isNotNull($storage_definition->getName() . '__' . $column_name); } $query->condition($or); } diff -u b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php --- b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -140,13 +140,38 @@ public function requiresFieldStorageSchemaChanges(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) { $table_mapping = $this->storage->getTableMapping(); - return + if ( $storage_definition->hasCustomStorage() != $original->hasCustomStorage() || $storage_definition->getSchema() != $original->getSchema() || $storage_definition->isRevisionable() != $original->isRevisionable() || $storage_definition->isTranslatable() != $original->isTranslatable() || $table_mapping->allowsSharedTableStorage($storage_definition) != $table_mapping->allowsSharedTableStorage($original) || - $table_mapping->requiresDedicatedTableStorage($storage_definition) != $table_mapping->requiresDedicatedTableStorage($original); + $table_mapping->requiresDedicatedTableStorage($storage_definition) != $table_mapping->requiresDedicatedTableStorage($original) + ) { + return TRUE; + } + + if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) { + return $this->getDedicatedTableSchema($storage_definition) != $this->loadFieldSchemaData($original); + } + elseif ($table_mapping->allowsSharedTableStorage($storage_definition)) { + $field_name = $storage_definition->getName(); + $schema = array(); + foreach (array_diff($table_mapping->getTableNames(), $table_mapping->getDedicatedTableNames()) as $table_name) { + if (in_array($field_name, $table_mapping->getFieldNames($table_name))) { + $column_names = $table_mapping->getColumnNames($storage_definition->getName()); + $schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); + } + } + return $schema != $this->loadFieldSchemaData($original); + } + else { + // The field has custom storage, so we don't know if a schema change is + // needed or not, but since per the initial checks earlier in this + // function, nothing about the definition changed that we manage, we + // return FALSE. + return FALSE; + } } /** @@ -201,6 +226,11 @@ if ($table_mapping->requiresDedicatedTableStorage($field_storage_definition)) { $this->createDedicatedTableSchema($field_storage_definition); } + elseif ($table_mapping->allowsSharedTableStorage($field_storage_definition)) { + // The shared tables are already fully created, but we need to save the + // per-field schema definitions for later use. + $this->createSharedTableSchema($field_storage_definition, TRUE); + } } // Save data about entity indexes and keys. @@ -714,7 +744,7 @@ * The entity schema data array. */ protected function loadEntitySchemaData(EntityTypeInterface $entity_type) { - return $this->installedStorageSchema()->get($entity_type->id() . '.schema_data') ?: array(); + return $this->installedStorageSchema()->get($entity_type->id() . '.entity_schema_data', array()); } /** @@ -727,7 +757,7 @@ */ protected function saveEntitySchemaData(EntityTypeInterface $entity_type, $schema) { $data = $this->getEntitySchemaData($entity_type, $schema); - $this->installedStorageSchema()->set($entity_type->id() . '.schema_data', $data); + $this->installedStorageSchema()->set($entity_type->id() . '.entity_schema_data', $data); } /** @@ -737,7 +767,42 @@ * The entity type definition. */ protected function deleteEntitySchemaData(EntityTypeInterface $entity_type) { - $this->installedStorageSchema()->delete($entity_type->id() . '.schema_data'); + $this->installedStorageSchema()->delete($entity_type->id() . '.entity_schema_data'); + } + + /** + * Loads stored schema data for the given field storage definition. + * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition + * The field storage definition. + * + * @return array + * The field schema data array. + */ + protected function loadFieldSchemaData(FieldStorageDefinitionInterface $storage_definition) { + return $this->installedStorageSchema()->get($storage_definition->getTargetEntityTypeId() . '.field_schema_data.' . $storage_definition->getName(), array()); + } + + /** + * Stores schema data for the given field storage definition. + * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition + * The field storage definition. + * @param array $schema + * The field schema data array. + */ + protected function saveFieldSchemaData(FieldStorageDefinitionInterface $storage_definition, $schema) { + $this->installedStorageSchema()->set($storage_definition->getTargetEntityTypeId() . '.field_schema_data.' . $storage_definition->getName(), $schema); + } + + /** + * Deletes schema data for the given field storage definition. + * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition + * The field storage definition. + */ + protected function deleteFieldSchemaData(FieldStorageDefinitionInterface $storage_definition) { + $this->installedStorageSchema()->delete($storage_definition->getTargetEntityTypeId() . '.field_schema_data.' . $storage_definition->getName()); } /** @@ -1004,6 +1069,7 @@ foreach ($schema as $name => $table) { $this->database->schema()->createTable($name, $table); } + $this->saveFieldSchemaData($storage_definition, $schema); } /** @@ -1011,8 +1077,13 @@ * * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition * The storage definition of the field being created. + * @param bool $only_save + * (optional) Whether to skip modification of database tables and only save + * the schema data for future comparison. For internal use only. This is + * used by onEntityTypeCreate() after it has already fully created the + * shared tables. */ - protected function createSharedTableSchema(FieldStorageDefinitionInterface $storage_definition) { + protected function createSharedTableSchema(FieldStorageDefinitionInterface $storage_definition, $only_save = FALSE) { $created_field_name = $storage_definition->getName(); $table_mapping = $this->storage->getTableMapping(); $column_names = $table_mapping->getColumnNames($created_field_name); @@ -1021,20 +1092,33 @@ // Iterate over the mapped table to find the ones that will host the created // field schema. + $schema = array(); foreach ($shared_table_names as $table_name) { foreach ($table_mapping->getFieldNames($table_name) as $field_name) { if ($field_name == $created_field_name) { // Create field columns. - $schema = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); - $keys = array_diff_key($schema, array('fields' => FALSE)); - foreach ($schema['fields'] as $column_name => $specifier) { - $schema_handler->addField($table_name, $column_name, $specifier, $keys); + $schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); + if (!$only_save) { + foreach ($schema[$table_name]['fields'] as $name => $specifier) { + $schema_handler->addField($table_name, $name, $specifier); + } + if (!empty($schema[$table_name]['indexes'])) { + foreach ($schema[$table_name]['indexes'] as $name => $specifier) { + $schema_handler->addIndex($table_name, $name, $specifier); + } + } + if (!empty($schema[$table_name]['unique keys'])) { + foreach ($schema[$table_name]['unique keys'] as $name => $specifier) { + $schema_handler->addUniqueKey($table_name, $name, $specifier); + } + } } // After creating the field schema skip to the next table. break; } } } + $this->saveFieldSchemaData($storage_definition, $schema); } /** @@ -1055,6 +1139,7 @@ $revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $deleted); $this->database->schema()->dropTable($revision_name); } + $this->deleteFieldSchemaData($storage_definition); } /** @@ -1099,6 +1184,8 @@ } } } + + $this->deleteFieldSchemaData($storage_definition); } /** @@ -1183,6 +1270,7 @@ $this->database->schema()->addIndex($revision_table, $real_name, $real_columns); } } + $this->saveFieldSchemaData($storage_definition, $this->getDedicatedTableSchema($storage_definition)); } } @@ -1235,31 +1323,32 @@ // Iterate over the mapped table to find the ones that host the deleted // field schema. + $original_schema = $this->loadFieldSchemaData($original); + $schema = array(); foreach ($table_mapping->getTableNames() as $table_name) { foreach ($table_mapping->getFieldNames($table_name) as $field_name) { if ($field_name == $updated_field_name) { - $original_schema = $this->getSharedTableFieldSchema($original, $table_name, $column_names); - $schema = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); + $schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); // Drop original indexes and unique keys. - if (!empty($original_schema['indexes'])) { - foreach ($original_schema['indexes'] as $name => $specifier) { + if (!empty($original_schema[$table_name]['indexes'])) { + foreach ($original_schema[$table_name]['indexes'] as $name => $specifier) { $schema_handler->dropIndex($table_name, $name); } } - if (!empty($original_schema['unique keys'])) { - foreach ($original_schema['unique keys'] as $name => $specifier) { + if (!empty($original_schema[$table_name]['unique keys'])) { + foreach ($original_schema[$table_name]['unique keys'] as $name => $specifier) { $schema_handler->dropUniqueKey($table_name, $name); } } // Create new indexes and unique keys. - if (!empty($schema['indexes'])) { - foreach ($schema['indexes'] as $name => $specifier) { + if (!empty($schema[$table_name]['indexes'])) { + foreach ($schema[$table_name]['indexes'] as $name => $specifier) { $schema_handler->addIndex($table_name, $name, $specifier); } } - if (!empty($schema['unique keys'])) { - foreach ($schema['unique keys'] as $name => $specifier) { + if (!empty($schema[$table_name]['unique keys'])) { + foreach ($schema[$table_name]['unique keys'] as $name => $specifier) { $schema_handler->addUniqueKey($table_name, $name, $specifier); } } @@ -1268,6 +1357,7 @@ } } } + $this->saveFieldSchemaData($storage_definition, $schema); } } diff -u b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php --- b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php +++ b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php @@ -78,7 +78,7 @@ t('Update the %entity_type entity type.', array('%entity_type' => $this->entityManager->getDefinition('entity_test_update')->getLabel())), ), ); - $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); + $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected); //, 'EntityDefinitionUpdateManager reports the expected change summary.'); // Run the update and ensure the revision table is created. $this->entityDefinitionUpdateManager->applyUpdates(); @@ -105,10 +105,11 @@ } /** - * Tests creating and deleting a base field when there are no existing entities. + * Tests creating, updating, and deleting a base field when there are no existing entities. */ - public function testBaseFieldCreateDeleteWithoutData() { - // Add a base field and ensure the update manager reports the addition. + public function testBaseFieldCreateUpdateDeleteWithoutData() { + // Add a base field, ensure the update manager reports it, and the update + // creates its schema. $this->addBaseField(); $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); $expected = array( @@ -117,16 +118,53 @@ ), ); $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - - // Run the update and ensure the new base field's column is created. $this->entityDefinitionUpdateManager->applyUpdates(); $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), 'Column created in shared table for new_base_field.'); - // Also ensure the custom index specified in - // EntityTestStorageSchema::getSharedTableFieldSchema() is created. + // Add an index on the base field, ensure the update manager reports it, + // and the update creates it. + $this->addBaseFieldIndex(); + $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); + $expected = array( + 'entity_test_update' => array( + t('Update the %field_name field.', array('%field_name' => t('A new base field'))), + ), + ); + $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); + $this->entityDefinitionUpdateManager->applyUpdates(); $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update_field__new_base_field'), 'Index created.'); - // Remove the base field and ensure that field deletions are reported. + // Remove the above index, ensure the update manager reports it, and the + // update deletes it. + $this->removeBaseFieldIndex(); + $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); + $expected = array( + 'entity_test_update' => array( + t('Update the %field_name field.', array('%field_name' => t('A new base field'))), + ), + ); + $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); + $this->entityDefinitionUpdateManager->applyUpdates(); + $this->assertFalse($this->database->schema()->indexExists('entity_test_update', 'entity_test_update_field__new_base_field'), 'Index deleted.'); + + // Update the type of the base field from 'string' to 'text', ensure the + // update manager reports it, and the update adjusts the schema + // accordingly. + $this->modifyBaseField(); + $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); + $expected = array( + 'entity_test_update' => array( + t('Update the %field_name field.', array('%field_name' => t('A new base field'))), + ), + ); + $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); + $this->entityDefinitionUpdateManager->applyUpdates(); + $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), 'Original column deleted in shared table for new_base_field.'); + $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field__value'), 'Value column created in shared table for new_base_field.'); + $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field__format'), 'Format column created in shared table for new_base_field.'); + + // Remove the base field, ensure the update manager reports it, and the + // update deletes the schema. $this->removeBaseField(); $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); $expected = array( @@ -135,18 +173,17 @@ ), ); $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - - // Run the update and ensure the base field's column and index are deleted. $this->entityDefinitionUpdateManager->applyUpdates(); - $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), 'Column deleted from shared table for new_base_field.'); - $this->assertFalse($this->database->schema()->indexExists('entity_test_update', 'entity_test_update_field__new_base_field'), 'Index deleted.'); + $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field_value'), 'Value column deleted from shared table for new_base_field.'); + $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field_format'), 'Format column deleted from shared table for new_base_field.'); } /** - * Tests creating and deleting a bundle field when there are no existing entities. + * Tests creating, updating, and deleting a bundle field when there are no existing entities. */ - public function testBundleFieldCreateDeleteWithoutData() { - // Add a bundle field and ensure the update manager reports the addition. + public function testBundleFieldCreateUpdateDeleteWithoutData() { + // Add a bundle field, ensure the update manager reports it, and the update + // creates its schema. $this->addBundleField(); $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); $expected = array( @@ -155,12 +192,25 @@ ), ); $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - - // Run the update and ensure the new bundle field's table is created. $this->entityDefinitionUpdateManager->applyUpdates(); $this->assertTrue($this->database->schema()->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table created for new_bundle_field.'); - // Remove the bundle field and ensure that field deletions are reported. + // Update the type of the base field from 'string' to 'text', ensure the + // update manager reports it, and the update adjusts the schema + // accordingly. + $this->modifyBundleField(); + $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); + $expected = array( + 'entity_test_update' => array( + t('Update the %field_name field.', array('%field_name' => t('A new bundle field'))), + ), + ); + $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); + $this->entityDefinitionUpdateManager->applyUpdates(); + $this->assertTrue($this->database->schema()->fieldExists('entity_test_update__new_bundle_field', 'new_bundle_field_format'), 'Format column created in dedicated table for new_base_field.'); + + // Remove the bundle field, ensure the update manager reports it, and the + // update deletes the schema. $this->removeBundleField(); $this->assertTrue($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that updates are needed.'); $expected = array( @@ -169,8 +219,6 @@ ), ); $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - - // Run the update and ensure the bundle field's table is deleted. $this->entityDefinitionUpdateManager->applyUpdates(); $this->assertFalse($this->database->schema()->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table deleted for new_bundle_field.'); } @@ -289,6 +337,53 @@ } /** + * Tests updating a base field when it has existing data. + */ + public function testBaseFieldUpdateWithExistingData() { + // Add the base field and run the update. + $this->addBaseField(); + $this->entityDefinitionUpdateManager->applyUpdates(); + + // Save an entity with the base field populated. + $this->entityManager->getStorage('entity_test_update')->create(array('new_base_field' => 'foo'))->save(); + + // Change the field's field type and apply updates. It's expected to + // throw an exception. + $this->modifyBaseField(); + try { + $this->entityDefinitionUpdateManager->applyUpdates(); + $this->fail('FieldStorageDefinitionUpdateForbiddenException thrown when trying to update a field schema that has data.'); + } + catch (FieldStorageDefinitionUpdateForbiddenException $e) { + $this->pass('FieldStorageDefinitionUpdateForbiddenException thrown when trying to update a field schema that has data.'); + } + } + + /** + * Tests updating a bundle field when it has existing data. + */ + public function testBundleFieldUpdateWithExistingData() { + // Add the bundle field and run the update. + $this->addBundleField(); + $this->entityDefinitionUpdateManager->applyUpdates(); + + // Save an entity with the bundle field populated. + entity_test_create_bundle('custom'); + $this->entityManager->getStorage('entity_test_update')->create(array('type' => 'test_bundle', 'new_bundle_field' => 'foo'))->save(); + + // Change the field's field type and apply updates. It's expected to + // throw an exception. + $this->modifyBundleField(); + try { + $this->entityDefinitionUpdateManager->applyUpdates(); + $this->fail('FieldStorageDefinitionUpdateForbiddenException thrown when trying to update a field schema that has data.'); + } + catch (FieldStorageDefinitionUpdateForbiddenException $e) { + $this->pass('FieldStorageDefinitionUpdateForbiddenException thrown when trying to update a field schema that has data.'); + } + } + + /** * Tests creating and deleting a multi-field index when there are no existing entities. */ public function testEntityIndexCreateDeleteWithoutData() { @@ -361,9 +456,12 @@ /** * Adds a new base field to the 'entity_test_update' entity type. + * + * @param string $type + * (optional) The field type for the new field. Defaults to 'string'. */ - protected function addBaseField() { - $definitions['new_base_field'] = BaseFieldDefinition::create('string') + protected function addBaseField($type = 'string') { + $definitions['new_base_field'] = BaseFieldDefinition::create($type) ->setName('new_base_field') ->setLabel(t('A new base field')); $this->state->set('entity_test_update.additional_base_field_definitions', $definitions); @@ -371,6 +469,13 @@ } /** + * Modifies the new base field from 'string' to 'text'. + */ + protected function modifyBaseField() { + $this->addBaseField('text'); + } + + /** * Removes the new base field from the 'entity_test_update' entity type. */ protected function removeBaseField() { @@ -379,10 +484,29 @@ } /** + * Adds a single-field index to the base field. + */ + protected function addBaseFieldIndex() { + $this->state->set('entity_test_update.additional_field_index.entity_test_update.new_base_field', TRUE); + $this->entityManager->clearCachedDefinitions(); + } + + /** + * Removes the index added in addBaseFieldIndex(). + */ + protected function removeBaseFieldIndex() { + $this->state->delete('entity_test_update.additional_field_index.entity_test_update.new_base_field'); + $this->entityManager->clearCachedDefinitions(); + } + + /** * Adds a new bundle field to the 'entity_test_update' entity type. + * + * @param string $type + * (optional) The field type for the new field. Defaults to 'string'. */ - protected function addBundleField() { - $definitions['new_bundle_field'] = FieldStorageDefinition::create('string') + protected function addBundleField($type = 'string') { + $definitions['new_bundle_field'] = FieldStorageDefinition::create($type) ->setName('new_bundle_field') ->setLabel(t('A new bundle field')) ->setTargetEntityTypeId('entity_test_update'); @@ -392,6 +516,13 @@ } /** + * Modifies the new bundle field from 'string' to 'text'. + */ + protected function modifyBundleField() { + $this->addBundleField('text'); + } + + /** * Removes the new bundle field from the 'entity_test_update' entity type. */ protected function removeBundleField() { diff -u b/core/modules/system/tests/modules/entity_test/src/EntityTestStorageSchema.php b/core/modules/system/tests/modules/entity_test/src/EntityTestStorageSchema.php --- b/core/modules/system/tests/modules/entity_test/src/EntityTestStorageSchema.php +++ b/core/modules/system/tests/modules/entity_test/src/EntityTestStorageSchema.php @@ -31,7 +31,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); - if ($table_name == 'entity_test_update' && $storage_definition->getName() == 'new_base_field') { + if (\Drupal::state()->get('entity_test_update.additional_field_index.' . $table_name . '.' . $storage_definition->getName())) { $this->addSharedTableFieldIndex($storage_definition, $schema); } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php +++ b/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php @@ -189,8 +189,13 @@ protected function getChangeList() { // Detect updated field storage definitions. foreach (array_intersect_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) { // @todo Support non-storage-schema-changing definition updates too: - // https://www.drupal.org/node/2336895. - if ($this->requiresFieldStorageSchemaChanges($storage_definition, $original_storage_definitions[$field_name])) { + // https://www.drupal.org/node/2336895. So long as we're checking + // based on schema change requirements rather than definition + // equality, skip the check if the entity type itself needs to be + // updated, since that can affect the schema of all fields, so we + // want to process that update first without reporting false + // positives here. + if (!isset($change_list[$entity_type_id]['entity_type']) && $this->requiresFieldStorageSchemaChanges($storage_definition, $original_storage_definitions[$field_name])) { $field_changes[$field_name] = static::DEFINITION_UPDATED; } }