diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 19ad14fca9..585f5eda42 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -1320,23 +1320,34 @@ protected function getEntityKey($key) { * {@inheritdoc} */ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { + /* @var $fields \Drupal\Core\Field\BaseFieldDefinition[] */ $fields = []; + $storage_schema_version = $entity_type->get('storage_schema_version'); if ($entity_type->hasKey('id')) { $fields[$entity_type->getKey('id')] = BaseFieldDefinition::create('integer') ->setLabel(new TranslatableMarkup('ID')) ->setReadOnly(TRUE) ->setSetting('unsigned', TRUE); + if ($storage_schema_version >= 2) { + $fields[$entity_type->getKey('id')]->setStorageRequired(TRUE); + } } if ($entity_type->hasKey('uuid')) { $fields[$entity_type->getKey('uuid')] = BaseFieldDefinition::create('uuid') ->setLabel(new TranslatableMarkup('UUID')) ->setReadOnly(TRUE); + if ($storage_schema_version >= 2) { + $fields[$entity_type->getKey('uuid')]->setStorageRequired(TRUE); + } } if ($entity_type->hasKey('revision')) { $fields[$entity_type->getKey('revision')] = BaseFieldDefinition::create('integer') ->setLabel(new TranslatableMarkup('Revision ID')) ->setReadOnly(TRUE) ->setSetting('unsigned', TRUE); + if ($storage_schema_version >= 2) { + $fields[$entity_type->getKey('revision')]->setStorageRequired(TRUE); + } } if ($entity_type->hasKey('langcode')) { $fields[$entity_type->getKey('langcode')] = BaseFieldDefinition::create('language') @@ -1354,6 +1365,9 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { if ($entity_type->isTranslatable()) { $fields[$entity_type->getKey('langcode')]->setTranslatable(TRUE); } + if ($storage_schema_version >= 2) { + $fields[$entity_type->getKey('langcode')]->setStorageRequired(TRUE); + } } if ($entity_type->hasKey('bundle')) { if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) { diff --git a/core/lib/Drupal/Core/Entity/EntityFieldManager.php b/core/lib/Drupal/Core/Entity/EntityFieldManager.php index ef6ac0e41a..986718abaa 100644 --- a/core/lib/Drupal/Core/Entity/EntityFieldManager.php +++ b/core/lib/Drupal/Core/Entity/EntityFieldManager.php @@ -227,6 +227,9 @@ protected function buildBaseFieldDefinitions($entity_type_id) { ->setTranslatable(TRUE) ->setRevisionable(TRUE) ->setDefaultValue(TRUE); + if ($entity_type->get('storage_schema_version') >= 2) { + $base_field_definitions[$keys['default_langcode']]->setStorageRequired(TRUE); + } } } @@ -238,10 +241,12 @@ protected function buildBaseFieldDefinitions($entity_type_id) { $base_field_definitions[$field_name] = BaseFieldDefinition::create('boolean') ->setLabel($this->t('Default revision')) ->setDescription($this->t('A flag indicating whether this was a default revision when it was saved.')) - ->setStorageRequired(TRUE) ->setInternal(TRUE) ->setTranslatable(FALSE) ->setRevisionable(TRUE); + if ($entity_type->get('storage_schema_version') >= 2) { + $base_field_definitions[$field_name]->setStorageRequired(TRUE); + } } // Make sure that revisionable and translatable entity types are correctly diff --git a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php index 1f36625828..8f0b1b57f1 100644 --- a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php +++ b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php @@ -32,13 +32,20 @@ public static function publishedBaseFieldDefinitions(EntityTypeInterface $entity throw new UnsupportedEntityTypeDefinitionException('The entity type ' . $entity_type->id() . ' does not have a "published" entity key.'); } - return [ - $entity_type->getKey('published') => BaseFieldDefinition::create('boolean') - ->setLabel(new TranslatableMarkup('Published')) - ->setRevisionable(TRUE) - ->setTranslatable(TRUE) - ->setDefaultValue(TRUE), - ]; + $field_definitions = BaseFieldDefinition::create('boolean') + ->setLabel(new TranslatableMarkup('Published')) + ->setRevisionable(TRUE) + ->setTranslatable(TRUE) + ->setDefaultValue(TRUE); + if ($entity_type->get('storage_schema_version') >= 2) { + // The published field cannot be made required, as that makes it + // impossible to create unpublished entities using the user interface in + // case the checkbox widget is used. + // @todo Change this to setRequired() once + // https://www.drupal.org/project/drupal/issues/2619328 is fixed. + $field_definitions->setStorageRequired(TRUE); + } + return [$entity_type->getKey('published') => $field_definitions]; } /** diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php index 71aea12b80..1466ec1ac6 100644 --- a/core/lib/Drupal/Core/Entity/EntityType.php +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -282,6 +282,13 @@ class EntityType extends PluginDefinition implements EntityTypeInterface { */ protected $constraints = []; + /** + * The storage schema version. + * + * @var int + */ + protected $storage_schema_version = 1; + /** * Any additional properties and values. * diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index b2d1d29167..83214f803b 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -1436,9 +1436,6 @@ protected function processRevisionTable(ContentEntityTypeInterface $entity_type, * A partial schema array for the base table. */ protected function processDataTable(ContentEntityTypeInterface $entity_type, array &$schema) { - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['fields'][$entity_type->getKey('default_langcode')]['not null'] = TRUE; } /** @@ -1453,9 +1450,6 @@ protected function processDataTable(ContentEntityTypeInterface $entity_type, arr * A partial schema array for the base table. */ protected function processRevisionDataTable(ContentEntityTypeInterface $entity_type, array &$schema) { - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['fields'][$entity_type->getKey('default_langcode')]['not null'] = TRUE; } /** @@ -1573,6 +1567,14 @@ protected function createSharedTableSchema(FieldStorageDefinitionInterface $stor // @todo Fix this in https://www.drupal.org/node/2929120. $entity_schema = $this->getEntitySchema($this->entityType); foreach ($schema[$table_name]['fields'] as $name => $specifier) { + // Serial fields are incorrectly stored as 'int' in the field + // schema. + // @todo Remove this in + // https://www.drupal.org/project/drupal/issues/2928906 + if (($specifier['type'] === 'int') && ($entity_schema[$table_name]['fields'][$name]['type'] === 'serial')) { + $specifier['type'] = 'serial'; + } + // Check if the field is part of the primary keys and pass along // this information when adding the field. // @see \Drupal\Core\Database\Schema::addField() @@ -2039,7 +2041,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st } $field_name = $storage_definition->getName(); - $base_table = $this->storage->getBaseTable(); + $properties = $storage_definition->getPropertyDefinitions(); // Define the initial values, if any. $initial_value = $initial_value_from_field = []; @@ -2071,31 +2073,37 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st } } - // A shared table contains rows for entities where the field is empty - // (since other fields stored in the same table might not be empty), thus - // the only columns that can be 'not null' are those for required - // properties of required fields. For now, we only hardcode 'not null' to a - // few "entity keys", in order to keep their indexes optimized. - // @todo Fix this in https://www.drupal.org/node/2841291. - $not_null_keys = $this->entityType->getKeys(); - // Label and the 'revision_translation_affected' fields are not necessarily - // required. - unset($not_null_keys['label'], $not_null_keys['revision_translation_affected']); + $schema_version = $this->entityType->get('storage_schema_version') ?: 1; + if ($schema_version >= 2) { + // A shared table contains rows for entities where the field is empty + // (since other fields stored in the same table might not be empty), thus + // the only columns that can be 'not null' are those for required + // properties of required fields. + $field_storage_is_required = $storage_definition->isStorageRequired(); + } + else { + // The legacy behavior is that only entity keys are 'not null'. + $not_null_keys = $this->entityType->getKeys(); + // Label and the 'revision_translation_affected' fields are not + // necessarily required. + unset($not_null_keys['label'], $not_null_keys['revision_translation_affected']); + $field_storage_is_required = in_array($field_name, $not_null_keys); + } // Because entity ID and revision ID are both serial fields in the base and // revision table respectively, the revision ID is not known yet, when // inserting data into the base table. Instead the revision ID in the base // table is updated after the data has been inserted into the revision // table. For this reason the revision ID field cannot be marked as NOT // NULL. - if ($table_name == $base_table) { - unset($not_null_keys['revision']); + if ($table_name == $this->storage->getBaseTable() && $field_name === $this->entityType->getKey('revision')) { + $field_storage_is_required = FALSE; } 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]['not null'] = in_array($field_name, $not_null_keys); + $schema['fields'][$schema_field_name]['not null'] = $field_storage_is_required && $properties[$field_column_name]->isRequired(); // Use the initial value of the field storage, if available. if ($initial_value && isset($initial_value[$field_column_name])) { diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php index 037c9f91fb..e26431ff09 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php @@ -106,6 +106,7 @@ public function convertToRevisionable(array &$sandbox, array $fields_to_update = ->setTargetBundle(NULL) ->setLabel(t('Revision ID')) ->setReadOnly(TRUE) + ->setStorageRequired(TRUE) ->setSetting('unsigned', TRUE); // Add the 'revision_default' field. diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php index 86c4389597..510a83b519 100644 --- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php +++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php @@ -555,7 +555,12 @@ public function testNonLangcodeEntityTypeModeration() { $entity_type->set('entity_keys', $keys); \Drupal::state()->set('entity_test_rev.entity_type', $entity_type); - // Update the entity type in order to remove the 'langcode' field. + // Update the entity type in order to remove the 'langcode' field, while + // ensuring that the field manager will return the field storage definitions + // for the updated entity type. For that we clear the cache of the entity + // type manager, so that the entity type is newly retrieved and exchanged by + // entity_test_entity_type_alter() with the one that we've put in the state. + \Drupal::service('entity_type.manager')->clearCachedDefinitions(); \Drupal::entityDefinitionUpdateManager()->updateFieldableEntityType($entity_type, \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type->id())); $workflow = $this->createEditorialWorkflow(); diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php index 771d81a9ad..ea6fbffb22 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php @@ -47,6 +47,7 @@ * "delete-form" = "/entity_test/delete/entity_test/{entity_test}", * }, * field_ui_base_route = "entity.entity_test.admin_form", + * storage_schema_version = 2, * ) * * Note that this entity type annotation intentionally omits the "create" link diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php index eda9c988f4..eb3b632532 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php @@ -37,6 +37,7 @@ * "edit-form" = "/entity_test_admin_routes/manage/{entity_test_admin_routes}/edit", * "delete-form" = "/entity_test/delete/entity_test_admin_routes/{entity_test_admin_routes}", * }, + * storage_schema_version = 2, * ) */ class EntityTestAdminRoutes extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php index 7fe9ce2112..de3de9b9ea 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php @@ -38,6 +38,7 @@ * "delete-form" = "/entity_test/delete/entity_test_base_field_display/{entity_test_base_field_display}/edit", * }, * field_ui_base_route = "entity.entity_test_base_field_display.admin_form", + * storage_schema_version = 2, * ) */ class EntityTestBaseFieldDisplay extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php index 7bcde6c7d5..1a9afdeaf3 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php @@ -34,7 +34,8 @@ * }, * links = { * "add-form" = "/entity_test_bundle/add", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestBundle extends ConfigEntityBundleBase implements EntityDescriptionInterface { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php index dfbb9f04b8..0e249b2b49 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php @@ -20,7 +20,8 @@ * "id" = "id", * "uuid" = "uuid", * "bundle" = "type" - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestCache extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php index 3ace146575..c7521f2fc8 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php @@ -26,7 +26,8 @@ * constraints = { * "EntityTestComposite" = {}, * "EntityTestEntityLevel" = {}, - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestCompositeConstraint extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php index 187effe504..d524c3d843 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php @@ -25,6 +25,7 @@ * links = { * "add-form" = "/entity_test_computed_field/add", * }, + * storage_schema_version = 2, * ) */ class EntityTestComputedField extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php index ea23d7968f..4a2ab34b28 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php @@ -23,7 +23,8 @@ * "uuid" = "uuid", * "bundle" = "type", * "label" = "name" - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestConstraintViolation extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php index a91e2cb9fb..88204b606b 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php @@ -23,7 +23,8 @@ * persistent_cache = FALSE, * constraints = { * "NotNull" = {} - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestConstraints extends EntityTest implements EntityChangedInterface { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php index 71c806b1ed..d1b333a298 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php @@ -12,7 +12,8 @@ * entity_keys = { * "id" = "id", * "bundle" = "type" - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestDefaultAccess extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php index 2639d3eaac..b6bc3c1d23 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php @@ -17,7 +17,8 @@ * "uuid" = "uuid", * "bundle" = "type", * "langcode" = "langcode" - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestDefaultValue extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php index 9160c1fddf..6ada5be886 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php @@ -35,6 +35,7 @@ * "label" = "name", * "langcode" = "langcode", * }, + * storage_schema_version = 2, * ) */ class EntityTestFieldMethods extends EntityTestMul { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php index aaca0ae10b..067aab0086 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php @@ -15,7 +15,8 @@ * "id" = "id", * "uuid" = "uuid", * "bundle" = "type" - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestFieldOverride extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php index 1b4597fda8..eec5345281 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php @@ -20,7 +20,8 @@ * "label" = "name", * "bundle" = "type", * "langcode" = "langcode", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestLabel extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php index e3fd77e0af..4ad90585cc 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php @@ -16,7 +16,8 @@ * "bundle" = "type", * "uuid" = "uuid", * "langcode" = "langcode", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestLabelCallback extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php index eb72fa55fc..228b653a11 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php @@ -19,6 +19,7 @@ * "langcode" = "langcode", * }, * admin_permission = "administer entity_test content", + * storage_schema_version = 2, * ) */ class EntityTestMapField extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php index 0c1ca9a533..7811ec8dbc 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php @@ -42,6 +42,7 @@ * "delete-form" = "/entity_test/delete/entity_test_mul/{entity_test_mul}", * }, * field_ui_base_route = "entity.entity_test_mul.admin_form", + * storage_schema_version = 2, * ) */ class EntityTestMul extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php index dd3da09dce..bf1185f2fb 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php @@ -43,6 +43,7 @@ * "delete-form" = "/entity_test/delete/entity_test_mul_changed/{entity_test_mul_changed}", * }, * field_ui_base_route = "entity.entity_test_mul_changed.admin_form", + * storage_schema_version = 2, * ) */ class EntityTestMulChanged extends EntityTestMul implements EntityChangedInterface { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php index bcbb54196b..a4c7b3059d 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php @@ -37,6 +37,7 @@ * "delete-form" = "/entity_test/delete/entity_test_mul_default_value/{entity_test_mul_default_value}", * }, * field_ui_base_route = "entity.entity_test_mul.admin_form", + * storage_schema_version = 2, * ) */ class EntityTestMulDefaultValue extends EntityTestMul { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php index 94948a344e..4edf4bf8ee 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php @@ -40,6 +40,7 @@ * "delete-form" = "/entity_test/delete/entity_test_mul_langcode_key/{entity_test_mul_langcode_key}", * }, * field_ui_base_route = "entity.entity_test_mul_langcode_key.admin_form", + * storage_schema_version = 2, * ) */ class EntityTestMulLangcodeKey extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php index eeafa14d15..44194ae24c 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php @@ -45,7 +45,8 @@ * "delete-form" = "/entity_test/delete/entity_test_mulrev/{entity_test_mulrev}", * "edit-form" = "/entity_test_mulrev/manage/{entity_test_mulrev}/edit", * "revision" = "/entity_test_mulrev/{entity_test_mulrev}/revision/{entity_test_mulrev_revision}/view", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestMulRev extends EntityTestRev { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php index 13a169df49..3c5907dc19 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php @@ -43,7 +43,8 @@ * "delete-form" = "/entity_test/delete/entity_test_mulrev_changed/{entity_test_mulrev_changed}", * "edit-form" = "/entity_test_mulrev_changed/manage/{entity_test_mulrev_changed}/edit", * "revision" = "/entity_test_mulrev_changed/{entity_test_mulrev_changed}/revision/{entity_test_mulrev_changed_revision}/view", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestMulRevChanged extends EntityTestMulChanged { @@ -58,6 +59,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setLabel(t('Revision ID')) ->setDescription(t('The version id of the test entity.')) ->setReadOnly(TRUE) + ->setStorageRequired(TRUE) ->setSetting('unsigned', TRUE); $fields['revision_translation_affected'] = BaseFieldDefinition::create('boolean') diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php index a22954bde2..ef23815655 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php @@ -27,6 +27,7 @@ * "revision_created" = "revision_created", * "revision_log_message" = "revision_log_message" * }, + * storage_schema_version = 2, * ) */ class EntityTestMulRevChangedWithRevisionLog extends EntityTestMulRevChanged implements RevisionLogInterface { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php index 8fa69a32b1..f1de517c08 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php @@ -49,7 +49,8 @@ * "delete-multiple-form" = "/entity_test/delete", * "edit-form" = "/entity_test_mulrevpub/manage/{entity_test_mulrevpub}/edit", * "revision" = "/entity_test_mulrevpub/{entity_test_mulrevpub}/revision/{entity_test_mulrevpub_revision}/view", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestMulRevPub extends EntityTestMulRev implements EntityPublishedInterface { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBasefield.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBasefield.php index b5bf2c2526..e417033f75 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBasefield.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBasefield.php @@ -21,7 +21,8 @@ * "bundle" = "type", * "label" = "name", * "langcode" = "langcode", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestMultiValueBasefield extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php index c3845c6bd4..54ee683046 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php @@ -18,7 +18,8 @@ * "bundle" = "type", * "label" = "name", * "langcode" = "langcode", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestNew extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php index 0369a64abc..91a505153b 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php @@ -20,6 +20,7 @@ * links = { * "add-form" = "/entity_test_no_bundle/add", * }, + * storage_schema_version = 2, * ) */ class EntityTestNoBundle extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php index 1ad93845c0..4daaed9eb8 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php @@ -19,6 +19,7 @@ * links = { * "add-form" = "/entity_test_no_id/add", * }, + * storage_schema_version = 2, * ) */ class EntityTestNoId extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php index 809eb1b001..7a8c08f154 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php @@ -19,6 +19,7 @@ * "uuid" = "uuid", * "bundle" = "type", * }, + * storage_schema_version = 2, * ) */ class EntityTestNoLabel extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php index 8d0ddac482..6b6b69c300 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php @@ -22,6 +22,7 @@ * "label" = "name", * "langcode" = "langcode", * }, + * storage_schema_version = 2, * ) */ class EntityTestNoUuid extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php index e99505eed3..8160aa1343 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php @@ -45,7 +45,8 @@ * "delete-multiple-form" = "/entity_test_rev/delete_multiple", * "edit-form" = "/entity_test_rev/manage/{entity_test_rev}/edit", * "revision" = "/entity_test_rev/{entity_test_rev}/revision/{entity_test_rev_revision}/view", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestRev extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php index 85a5e66769..fe3dbbd80f 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php @@ -35,6 +35,7 @@ * "edit-form" = "/entity_test_string_id/manage/{entity_test_string_id}", * }, * field_ui_base_route = "entity.entity_test_string_id.admin_form", + * storage_schema_version = 2, * ) */ class EntityTestStringId extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php index 6cf9050d24..11ec271f55 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php @@ -20,7 +20,8 @@ * "label" = "name", * "bundle" = "type", * "langcode" = "langcode", - * } + * }, + * storage_schema_version = 2, * ) */ class EntityTestViewBuilder extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php index 42d26e0e0a..71576109de 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php @@ -45,6 +45,7 @@ * "delete-form" = "/entity_test_with_bundle/{entity_test_with_bundle}/delete", * "create" = "/entity_test_with_bundle", * }, + * storage_schema_version = 2, * ) */ class EntityTestWithBundle extends ContentEntityBase { diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php index 4921dcf481..0783df3c8e 100644 --- a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php +++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php @@ -31,10 +31,12 @@ public static function defaultStorageSettings() { */ public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { $properties['shape'] = DataDefinition::create('string') - ->setLabel(t('Shape')); + ->setLabel(t('Shape')) + ->setRequired(TRUE); $properties['color'] = DataDefinition::create('string') - ->setLabel(t('Color')); + ->setLabel(t('Color')) + ->setRequired(TRUE); return $properties; } diff --git a/core/modules/system/tests/modules/entity_test_update/entity_test_update.module b/core/modules/system/tests/modules/entity_test_update/entity_test_update.module index 8702f24d97..9b3b028b25 100644 --- a/core/modules/system/tests/modules/entity_test_update/entity_test_update.module +++ b/core/modules/system/tests/modules/entity_test_update/entity_test_update.module @@ -29,6 +29,18 @@ function entity_test_update_entity_base_field_info(EntityTypeInterface $entity_t } } +/** + * Implements hook_entity_base_field_info_alter(). + */ +function entity_test_update_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) { + if ($entity_type->id() === 'entity_test_update') { + $field_names = \Drupal::state()->get('entity_test_update.required_field_storage_definitions', []); + foreach ($field_names as $field_name) { + $fields[$field_name]->setStorageRequired(TRUE); + } + } +} + /** * Implements hook_entity_field_storage_info(). */ diff --git a/core/modules/user/src/EntityOwnerTrait.php b/core/modules/user/src/EntityOwnerTrait.php index ad55d0f3dc..55ba68667e 100644 --- a/core/modules/user/src/EntityOwnerTrait.php +++ b/core/modules/user/src/EntityOwnerTrait.php @@ -32,14 +32,17 @@ public static function ownerBaseFieldDefinitions(EntityTypeInterface $entity_typ if (!$entity_type->hasKey('owner')) { throw new UnsupportedEntityTypeDefinitionException('The entity type ' . $entity_type->id() . ' does not have an "owner" entity key.'); } - - return [ - $entity_type->getKey('owner') => BaseFieldDefinition::create('entity_reference') - ->setLabel(new TranslatableMarkup('User ID')) - ->setSetting('target_type', 'user') - ->setTranslatable($entity_type->isTranslatable()) - ->setDefaultValueCallback(static::class . '::getDefaultEntityOwner'), - ]; + $field_definitions = BaseFieldDefinition::create('entity_reference') + ->setLabel(new TranslatableMarkup('User ID')) + ->setSetting('target_type', 'user') + ->setTranslatable($entity_type->isTranslatable()) + ->setDefaultValueCallback(static::class . '::getDefaultEntityOwner'); + if ($entity_type->get('storage_schema_version') >= 2) { + // This cannot be marked required, because we support submitting an + // empty textfield which will set the owner to the anonymous user. + $field_definitions->setStorageRequired(TRUE); + } + return [$entity_type->getKey('owner') => $field_definitions]; } /** diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php index 9dab3359b7..62c12cbc76 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntitySchemaTest.php @@ -146,6 +146,7 @@ public function testPrimaryKeyUpdate($entity_type_id, $field_name) { $field = BaseFieldDefinition::create('integer') ->setLabel('ID') ->setReadOnly(TRUE) + ->setStorageRequired(TRUE) ->setSetting('unsigned', TRUE); break; @@ -153,12 +154,14 @@ public function testPrimaryKeyUpdate($entity_type_id, $field_name) { $field = BaseFieldDefinition::create('integer') ->setLabel('Revision ID') ->setReadOnly(TRUE) + ->setStorageRequired(TRUE) ->setSetting('unsigned', TRUE); break; case 'langcode': $field = BaseFieldDefinition::create('language') - ->setLabel('Language'); + ->setLabel('Language') + ->setStorageRequired(TRUE); if ($entity_type->isRevisionable()) { $field->setRevisionable(TRUE); } diff --git a/core/tests/Drupal/KernelTests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/core/tests/Drupal/KernelTests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php index 6a5a96767a..64eddace35 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php @@ -77,23 +77,18 @@ public function testOnFieldStorageDefinitionUpdateShared() { $actual = $this->installedStorageSchema->get('entity_test.field_schema_data.shape'); $this->assertSame($expected, $actual); - // Make the field an entity key, so that it will get marked as NOT NULL. - $entity_type = $this->entityDefinitionUpdateManager->getEntityType('entity_test'); - $original_keys = $entity_type->getKeys(); - $entity_type->set('entity_keys', $original_keys + ['shape' => 'shape']); - $this->entityDefinitionUpdateManager->updateEntityType($entity_type); - - // Update the field and make sure the schema got updated. + // Make the field storage required, so that its schema columns will get + // marked as NOT NULL. + $field->setStorageRequired(TRUE); $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($field); $expected['entity_test']['fields']['shape__shape']['not null'] = TRUE; $expected['entity_test']['fields']['shape__color']['not null'] = TRUE; $actual = $this->installedStorageSchema->get('entity_test.field_schema_data.shape'); $this->assertSame($expected, $actual); - // Remove the entity key again and check that the schema got reverted. - $entity_type->set('entity_keys', $original_keys); - $this->entityDefinitionUpdateManager->updateEntityType($entity_type); - + // Make the field not storage required again and check that the schema got + // reverted. + $field->setStorageRequired(FALSE); $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($field); $expected['entity_test']['fields']['shape__shape']['not null'] = FALSE; $expected['entity_test']['fields']['shape__color']['not null'] = FALSE; @@ -109,17 +104,14 @@ public function testOnFieldStorageDefinitionUpdateShared() { ], ])->save(); - $entity_type->set('entity_keys', $original_keys + ['shape' => 'shape']); - $this->entityDefinitionUpdateManager->updateEntityType($entity_type); - + $field->setStorageRequired(TRUE); $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($field); $expected['entity_test']['fields']['shape__shape']['not null'] = TRUE; $expected['entity_test']['fields']['shape__color']['not null'] = TRUE; $actual = $this->installedStorageSchema->get('entity_test.field_schema_data.shape'); $this->assertSame($expected, $actual); - $entity_type->set('entity_keys', $original_keys); - $this->entityDefinitionUpdateManager->updateEntityType($entity_type); + $field->setStorageRequired(FALSE); $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($field); $expected['entity_test']['fields']['shape__shape']['not null'] = FALSE; $expected['entity_test']['fields']['shape__color']['not null'] = FALSE; diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php index 87b8a68fc1..fdf695da6b 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityFieldManagerTest.php @@ -286,6 +286,8 @@ public function testGetBaseFieldDefinitionsTranslatableEntityTypeDefaultLangcode $this->entityType->isTranslatable()->willReturn(TRUE); + $this->entityType->get('storage_schema_version')->willReturn(NULL); + $definitions = $this->entityFieldManager->getBaseFieldDefinitions('test_entity_type'); $this->assertTrue(isset($definitions[$default_langcode_key])); @@ -329,6 +331,7 @@ public function testGetBaseFieldDefinitionsTranslatableEntityTypeLangcode($provi $this->entityType->isTranslatable()->willReturn(TRUE); $this->entityType->getLabel()->willReturn('Test'); + $this->entityType->get('storage_schema_version')->willReturn(NULL); $this->setExpectedException(\LogicException::class, 'The Test entity type cannot be translatable as it does not define a translatable "langcode" field.'); $this->entityFieldManager->getBaseFieldDefinitions('test_entity_type'); @@ -455,6 +458,7 @@ public function testGetBaseFieldDefinitionsInvalidDefinition() { $this->entityType->isTranslatable()->willReturn(TRUE); $this->entityType->getLabel()->willReturn('the_label'); + $this->entityType->get('storage_schema_version')->willReturn(NULL); $this->setExpectedException(\LogicException::class); $this->entityFieldManager->getBaseFieldDefinitions('test_entity_type'); diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php index ad30bcae79..1fa29d9f13 100644 --- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php @@ -93,6 +93,7 @@ protected function setUp() { 'columns' => [ 'value' => [ 'type' => 'int', + 'not null' => TRUE, ], ], ]); @@ -425,7 +426,7 @@ public function testGetSchemaRevisionable() { ->method('getRevisionMetadataKeys') ->will($this->returnValue([])); - $this->storage->expects($this->exactly(1)) + $this->storage->expects($this->atLeastOnce()) ->method('getRevisionTable') ->will($this->returnValue('entity_test_revision')); @@ -529,6 +530,7 @@ public function testGetSchemaTranslatable() { 'columns' => [ 'value' => [ 'type' => 'varchar', + 'not null' => TRUE, ], ], ]); @@ -538,6 +540,7 @@ public function testGetSchemaTranslatable() { 'value' => [ 'type' => 'int', 'size' => 'tiny', + 'not null' => TRUE, ], ], ]); @@ -646,7 +649,7 @@ public function testGetSchemaRevisionableTranslatable() { ->method('isTranslatable') ->will($this->returnValue(TRUE)); - $this->storage->expects($this->exactly(2)) + $this->storage->expects($this->atLeastOnce()) ->method('getRevisionTable') ->will($this->returnValue('entity_test_revision')); @@ -654,6 +657,7 @@ public function testGetSchemaRevisionableTranslatable() { 'columns' => [ 'value' => [ 'type' => 'int', + 'not null' => TRUE, ], ], ]); @@ -661,6 +665,7 @@ public function testGetSchemaRevisionableTranslatable() { 'columns' => [ 'value' => [ 'type' => 'varchar', + 'not null' => TRUE, ], ], ]); @@ -669,6 +674,7 @@ public function testGetSchemaRevisionableTranslatable() { 'value' => [ 'type' => 'int', 'size' => 'tiny', + 'not null' => TRUE, ], ], ]); @@ -1456,6 +1462,9 @@ public function setUpStorageDefinition($field_name, array $schema) { $this->storageDefinitions[$field_name]->expects($this->any()) ->method('getColumns') ->will($this->returnValue($schema['columns'])); + $this->storageDefinitions[$field_name]->expects($this->any()) + ->method('isStorageRequired') + ->will($this->returnValue(TRUE)); // Add property definitions. if (!empty($schema['columns'])) { $property_definitions = []; diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php index a548c74ddb..dbced3aa44 100644 --- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php @@ -19,6 +19,7 @@ use Drupal\Core\Entity\Sql\DefaultTableMapping; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; use Drupal\Core\Language\Language; +use Drupal\Core\TypedData\DataDefinition; use Drupal\Tests\UnitTestCase; /** @@ -41,6 +42,13 @@ class SqlContentEntityStorageTest extends UnitTestCase { */ protected $entityType; + /** + * An array of property definitions used for this test, keyed by property name. + * + * @var \Drupal\Core\TypedData\DataDefinitionInterface[]|\PHPUnit_Framework_MockObject_MockObject[] + */ + protected $propertyDefinitions = []; + /** * An array of field definitions used for this test, keyed by field name. * @@ -361,13 +369,18 @@ public function testSetTableMapping() { * @covers ::onEntityTypeCreate * @covers ::getTableMapping */ - public function testOnEntityTypeCreate() { + public function testOnEntityTypeCreateVersion1() { $columns = [ 'value' => [ 'type' => 'int', ], ]; + $this->propertyDefinitions['value'] = $this->createMock(DataDefinition::class); + $this->propertyDefinitions['value']->expects($this->any()) + ->method('isRequired') + ->will($this->returnValue(TRUE)); + $this->fieldDefinitions = $this->mockFieldDefinitions(['id']); $this->fieldDefinitions['id']->expects($this->any()) ->method('getColumns') @@ -375,6 +388,9 @@ public function testOnEntityTypeCreate() { $this->fieldDefinitions['id']->expects($this->once()) ->method('getSchema') ->will($this->returnValue(['columns' => $columns])); + $this->fieldDefinitions['id']->expects($this->any()) + ->method('getPropertyDefinitions') + ->will($this->returnValue($this->propertyDefinitions)); $this->entityType->expects($this->once()) ->method('getKeys') @@ -451,6 +467,138 @@ public function testOnEntityTypeCreate() { $storage->onEntityTypeCreate($this->entityType); } + /** + * Tests ContentEntityDatabaseStorage::onEntityTypeCreate(). + * + * @covers ::__construct + * @covers ::onEntityTypeCreate + * @covers ::getTableMapping + */ + public function testOnEntityTypeCreateVersion2() { + $columns = [ + 'value' => [ + 'type' => 'int', + ], + ]; + + $this->propertyDefinitions['value'] = $this->createMock(DataDefinition::class); + $this->propertyDefinitions['value']->expects($this->any()) + ->method('isRequired') + ->will($this->returnValue(TRUE)); + + $this->fieldDefinitions = $this->mockFieldDefinitions(['id']); + $this->fieldDefinitions['id']->expects($this->any()) + ->method('getColumns') + ->will($this->returnValue($columns)); + $this->fieldDefinitions['id']->expects($this->once()) + ->method('getSchema') + ->will($this->returnValue(['columns' => $columns])); + $this->fieldDefinitions['id']->expects($this->any()) + ->method('getPropertyDefinitions') + ->will($this->returnValue($this->propertyDefinitions)); + $this->fieldDefinitions['id']->expects($this->any()) + ->method('isStorageRequired') + ->will($this->returnValue(TRUE)); + + $this->entityType->expects($this->any()) + ->method('get') + ->with('storage_schema_version') + ->willReturn(2); + $this->entityType->expects($this->any()) + ->method('hasKey') + ->will($this->returnValueMap([ + // SqlContentEntityStorageSchema::initializeBaseTable() + ['revision', FALSE], + // SqlContentEntityStorageSchema::processBaseTable() + ['id', TRUE], + ])); + $this->entityType->expects($this->any()) + ->method('hasKey') + ->will($this->returnValueMap([ + // SqlContentEntityStorageSchema::initializeBaseTable() + ['revision', FALSE], + // SqlContentEntityStorageSchema::processBaseTable() + ['id', TRUE], + ])); + $this->entityType->expects($this->any()) + ->method('getKey') + ->will($this->returnValueMap([ + // EntityStorageBase::__construct() + ['id', 'id'], + // ContentEntityStorageBase::__construct() + ['uuid', NULL], + ['bundle', NULL], + // SqlContentEntityStorageSchema::initializeBaseTable() + ['id' => 'id'], + // SqlContentEntityStorageSchema::processBaseTable() + ['id' => 'id'], + ])); + + $this->setUpEntityStorage(); + + $expected = [ + 'description' => 'The base table for entity_test entities.', + 'fields' => [ + 'id' => [ + 'type' => 'serial', + 'not null' => TRUE, + ], + ], + 'primary key' => ['id'], + 'unique keys' => [], + 'indexes' => [], + 'foreign keys' => [], + ]; + + $schema_handler = $this->getMockBuilder('Drupal\Core\Database\Schema') + ->disableOriginalConstructor() + ->getMock(); + $schema_handler->expects($this->any()) + ->method('createTable') + ->with($this->equalTo('entity_test'), $this->equalTo($expected)); + + $this->connection->expects($this->once()) + ->method('schema') + ->will($this->returnValue($schema_handler)); + + $storage = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorage') + ->setConstructorArgs([ + $this->entityType, + $this->connection, + $this->entityFieldManager, + $this->cache, + $this->languageManager, + new MemoryCache(), + $this->entityTypeBundleInfo, + $this->entityTypeManager, + ]) + ->setMethods(['getStorageSchema']) + ->getMock(); + + $key_value = $this->createMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface'); + $schema_handler = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema') + ->setConstructorArgs([ + $this->entityTypeManager, + $this->entityType, + $storage, + $this->connection, + $this->entityFieldManager, + ]) + ->setMethods(['installedStorageSchema', 'createSharedTableSchema']) + ->getMock(); + $schema_handler + ->expects($this->any()) + ->method('installedStorageSchema') + ->will($this->returnValue($key_value)); + + $storage + ->expects($this->any()) + ->method('getStorageSchema') + ->will($this->returnValue($schema_handler)); + + $storage->onEntityTypeCreate($this->entityType); + } + /** * Tests getTableMapping() with an empty entity type. * diff --git a/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php b/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php index 953c90209f..afd19f7d1f 100644 --- a/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php +++ b/core/tests/Drupal/Tests/Core/Field/TestBaseFieldDefinitionInterface.php @@ -4,9 +4,10 @@ use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Field\RequiredFieldStorageDefinitionInterface; /** * Defines a test interface to mock entity base field definitions. */ -interface TestBaseFieldDefinitionInterface extends FieldDefinitionInterface, FieldStorageDefinitionInterface { +interface TestBaseFieldDefinitionInterface extends FieldDefinitionInterface, FieldStorageDefinitionInterface, RequiredFieldStorageDefinitionInterface { }