diff --git a/core/modules/comment/src/Tests/CommentValidationTest.php b/core/modules/comment/src/Tests/CommentValidationTest.php index 61457f4..c22e15b 100644 --- a/core/modules/comment/src/Tests/CommentValidationTest.php +++ b/core/modules/comment/src/Tests/CommentValidationTest.php @@ -29,7 +29,6 @@ class CommentValidationTest extends EntityUnitTestBase { */ protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); $this->installEntitySchema('comment'); $this->installSchema('comment', array('comment_entity_statistics')); } diff --git a/core/modules/config/src/Tests/ConfigImportRecreateTest.php b/core/modules/config/src/Tests/ConfigImportRecreateTest.php index 964128f..30dfd7d 100644 --- a/core/modules/config/src/Tests/ConfigImportRecreateTest.php +++ b/core/modules/config/src/Tests/ConfigImportRecreateTest.php @@ -37,6 +37,7 @@ protected function setUp() { parent::setUp(); $this->installEntitySchema('node'); + $this->installConfig(array('field')); $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging')); @@ -85,12 +86,12 @@ public function testRecreateEntity() { $content_type->save(); $this->configImporter->reset(); - // A node type, a field storage, a field, an entity view display and an - // entity form display will be recreated. + // A node type, a field, an entity view display and an entity form display + // will be recreated. $creates = $this->configImporter->getUnprocessedConfiguration('create'); $deletes = $this->configImporter->getUnprocessedConfiguration('delete'); - $this->assertEqual(5, count($creates), 'There are 5 configuration items to create.'); - $this->assertEqual(5, count($deletes), 'There are 5 configuration items to delete.'); + $this->assertEqual(4, count($creates), 'There are 4 configuration items to create.'); + $this->assertEqual(4, count($deletes), 'There are 4 configuration items to delete.'); $this->assertEqual(0, count($this->configImporter->getUnprocessedConfiguration('update')), 'There are no configuration items to update.'); $this->assertIdentical($creates, array_reverse($deletes), 'Deletes and creates contain the same configuration names in opposite orders due to dependencies.'); diff --git a/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php b/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php index 7dc7cd6..14ce9fd 100644 --- a/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php +++ b/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php @@ -44,6 +44,7 @@ protected function setUp() { $this->installEntitySchema('user'); $this->installEntitySchema('node'); + $this->installConfig(array('field')); // Set up the ConfigImporter object for testing. $storage_comparer = new StorageComparer( diff --git a/core/modules/editor/src/Tests/EditorFileUsageTest.php b/core/modules/editor/src/Tests/EditorFileUsageTest.php index fb62a09..1a6d844 100644 --- a/core/modules/editor/src/Tests/EditorFileUsageTest.php +++ b/core/modules/editor/src/Tests/EditorFileUsageTest.php @@ -25,7 +25,6 @@ class EditorFileUsageTest extends EntityUnitTestBase { protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); $this->installEntitySchema('file'); $this->installSchema('node', array('node_access')); $this->installSchema('file', array('file_usage')); diff --git a/core/modules/field/config/schema/field.schema.yml b/core/modules/field/config/schema/field.schema.yml index 862f40a..184dc2f 100644 --- a/core/modules/field/config/schema/field.schema.yml +++ b/core/modules/field/config/schema/field.schema.yml @@ -47,6 +47,9 @@ field.storage.*.*: sequence: - type: ignore label: 'Index' + persist_with_no_fields: + type: boolean + label: 'Persist field storage with no fields' field.field.*.*.*: type: field_config_base diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php index ec75234..87f4400 100644 --- a/core/modules/field/src/Entity/FieldConfig.php +++ b/core/modules/field/src/Entity/FieldConfig.php @@ -215,11 +215,12 @@ public static function postDelete(EntityStorageInterface $storage, array $fields return; } - // Delete field storages that have no more fields. + // Delete the associated field storages if they are not used anymore and are + // not persistent. $storages_to_delete = array(); foreach ($fields as $field) { $storage_definition = $field->getFieldStorageDefinition(); - if (!$field->deleted && empty($field->noFieldDelete) && !$field->isUninstalling() && count($storage_definition->getBundles()) == 0) { + if (!$field->deleted && empty($field->noFieldDelete) && !$field->isUninstalling() && $storage_definition->isDeletable()) { // Key by field UUID to avoid deleting the same storage twice. $storages_to_delete[$storage_definition->uuid()] = $storage_definition; } diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index 29794c7..6b89e38 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -134,6 +134,21 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI public $locked = FALSE; /** + * Flag indicating whether the field storage should be deleted when orphaned. + * + * By default field storages for configurable fields are removed when there + * are no remaining fields using them. If multiple modules provide bundles + * which need to use the same field storage then setting this to TRUE will + * preserve the field storage regardless of what happens to the bundles. The + * classic use case for this is node body field storage since Book, Forum, the + * Standard profile and bundle (node type) creation through the UI all use + * same field storage. + * + * @var bool + */ + protected $persist_with_no_fields = FALSE; + + /** * The custom storage indexes for the field data storage. * * This set of indexes is merged with the "default" indexes specified by the @@ -733,4 +748,13 @@ public static function loadByName($entity_type_id, $field_name) { return \Drupal::entityManager()->getStorage('field_storage_config')->load($entity_type_id . '.' . $field_name); } + /** + * {@inheritdoc} + */ + public function isDeletable() { + // The field storage is not deleted, is configured to be removed when there + // are no fields and the field storage has no bundles. + return !$this->deleted && !$this->persist_with_no_fields && count($this->getBundles()) == 0; + } + } diff --git a/core/modules/field/src/FieldStorageConfigInterface.php b/core/modules/field/src/FieldStorageConfigInterface.php index 4f4eb04..de0406b 100644 --- a/core/modules/field/src/FieldStorageConfigInterface.php +++ b/core/modules/field/src/FieldStorageConfigInterface.php @@ -31,4 +31,12 @@ public function getBundles(); */ public function isLocked(); + /** + * Checks if the field storage can be deleted. + * + * @return bool + * TRUE if the field storage can be deleted. + */ + public function isDeletable(); + } diff --git a/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import.yml b/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import.yml index 33fdf52..01e9b2a 100644 --- a/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import.yml +++ b/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import.yml @@ -16,3 +16,4 @@ dependencies: module: - entity_test - text +persist_with_no_fields: false diff --git a/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import_2.yml b/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import_2.yml index 69874a4..7ba8659 100644 --- a/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import_2.yml +++ b/core/modules/field/tests/modules/field_test_config/config/install/field.storage.entity_test.field_test_import_2.yml @@ -16,3 +16,4 @@ dependencies: module: - entity_test - text +persist_with_no_fields: false diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging.yml b/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging.yml index 495049a..4477f26 100644 --- a/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging.yml +++ b/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging.yml @@ -17,3 +17,4 @@ dependencies: module: - entity_test - text +persist_with_no_fields: false diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging_2.yml b/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging_2.yml index 6b8ef2c..5460ecc 100644 --- a/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging_2.yml +++ b/core/modules/field/tests/modules/field_test_config/staging/field.storage.entity_test.field_test_import_staging_2.yml @@ -17,3 +17,4 @@ dependencies: module: - entity_test - text +persist_with_no_fields: false diff --git a/core/modules/field_ui/src/FieldOverview.php b/core/modules/field_ui/src/FieldOverview.php index 290d655..c780936 100644 --- a/core/modules/field_ui/src/FieldOverview.php +++ b/core/modules/field_ui/src/FieldOverview.php @@ -16,6 +16,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; use Drupal\Core\Url; +use Drupal\field\FieldStorageConfigInterface; use Drupal\field_ui\OverviewBase; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\field\Entity\FieldStorageConfig; @@ -218,15 +219,14 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t ); } - // Additional row: re-use existing field. - $existing_fields = $this->getExistingFieldOptions(); + // Additional row: re-use existing field storages. + $existing_fields = $this->getExistingFieldStorageOptions(); if ($existing_fields) { // Build list of options. $existing_field_options = array(); foreach ($existing_fields as $field_name => $info) { - $text = $this->t('@type: @field (@label)', array( + $text = $this->t('@type: @field', array( '@type' => $info['type_label'], - '@label' => $info['label'], '@field' => $info['field'], )); $existing_field_options[$field_name] = Unicode::truncate($text, 80, FALSE, TRUE); @@ -485,45 +485,31 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } /** - * Returns an array of existing fields to be added to a bundle. + * Returns an array of existing field storages that can be added to a bundle. * * @return array - * An array of existing fields keyed by field name. + * An array of existing field storages keyed by name. */ - protected function getExistingFieldOptions() { + protected function getExistingFieldStorageOptions() { $options = array(); - - // Collect candidate fields: all fields of field storages for this - // entity type that are not already present in the current bundle. - $field_map = \Drupal::entityManager()->getFieldMap(); - $field_ids = array(); - if (!empty($field_map[$this->entity_type])) { - foreach ($field_map[$this->entity_type] as $field_name => $data) { - if (!in_array($this->bundle, $data['bundles'])) { - $bundle = reset($data['bundles']); - $field_ids[] = $this->entity_type . '.' . $bundle . '.' . $field_name; - } - } - } - - // Load the fields and build the list of options. - if ($field_ids) { - $field_types = $this->fieldTypeManager->getDefinitions(); - $fields = $this->entityManager->getStorage('field_config')->loadMultiple($field_ids); - foreach ($fields as $field) { - // Do not show: - // - locked fields, - // - fields that should not be added via user interface. - $field_type = $field->getType(); - $field_storage = $field->getFieldStorageDefinition(); - if (empty($field_storage->locked) && empty($field_types[$field_type]['no_ui'])) { - $options[$field->getName()] = array( - 'type' => $field_type, - 'type_label' => $field_types[$field_type]['label'], - 'field' => $field->getName(), - 'label' => $field->getLabel(), - ); - } + // Load the field_storages and build the list of options. + $field_types = $this->fieldTypeManager->getDefinitions(); + foreach ($this->entityManager->getFieldStorageDefinitions($this->entity_type) as $field_name => $field_storage) { + // Do not show: + // - non-configurable field storages, + // - locked field_storages, + // - field_storages that should not be added via user interface, + // - field_storages that already have a field in the bundle. + $field_type = $field_storage->getType(); + if ($field_storage instanceof FieldStorageConfigInterface + && !$field_storage->isLocked() + && empty($field_types[$field_type]['no_ui']) + && !in_array($this->bundle, $field_storage->getBundles(), TRUE)) { + $options[$field_name] = array( + 'type' => $field_type, + 'type_label' => $field_types[$field_type]['label'], + 'field' => $field_name, + ); } } diff --git a/core/modules/field_ui/src/Tests/EntityDisplayTest.php b/core/modules/field_ui/src/Tests/EntityDisplayTest.php index 5150f58..e6effec 100644 --- a/core/modules/field_ui/src/Tests/EntityDisplayTest.php +++ b/core/modules/field_ui/src/Tests/EntityDisplayTest.php @@ -21,6 +21,7 @@ class EntityDisplayTest extends KernelTestBase { protected function setUp() { parent::setUp(); + $this->installEntitySchema('node'); $this->installConfig(array('field')); } @@ -268,8 +269,6 @@ public function testBaseFieldComponent() { * Tests renaming and deleting a bundle. */ public function testRenameDeleteBundle() { - $this->installEntitySchema('node'); - // Create a node bundle, display and form display object. entity_create('node_type', array('type' => 'article'))->save(); entity_get_display('node', 'article', 'default')->save(); diff --git a/core/modules/field_ui/src/Tests/EntityFormDisplayTest.php b/core/modules/field_ui/src/Tests/EntityFormDisplayTest.php index 768c142..057d575 100644 --- a/core/modules/field_ui/src/Tests/EntityFormDisplayTest.php +++ b/core/modules/field_ui/src/Tests/EntityFormDisplayTest.php @@ -21,7 +21,6 @@ class EntityFormDisplayTest extends KernelTestBase { protected function setUp() { parent::setUp(); - $this->installConfig(array('field')); } /** diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php index 2379899..be5226d 100644 --- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php @@ -72,6 +72,7 @@ function testCRUDFields() { $this->cardinalitySettings(); $this->fieldListAdminPage(); $this->deleteField(); + $this->addPersistentFieldStorage(); } /** @@ -226,6 +227,30 @@ protected function deleteField() { } /** + * Tests that persistent field storage appears in the field UI. + */ + protected function addPersistentFieldStorage() { + $field_storage = FieldStorageConfig::loadByName('node', $this->field_name); + // Persist the field storage even if there are no fields. + $field_storage->set('persist_with_no_fields', TRUE)->save(); + // Delete all instances of the field. + foreach ($field_storage->getBundles() as $node_type) { + // Delete all the body field instances. + $this->drupalPostForm('admin/structure/types/manage/' . $node_type . '/fields/node.' . $node_type . '.' . $this->field_name, array(), t('Delete field')); + $this->drupalPostForm(NULL, array(), t('Delete')); + } + // Check "Re-use existing field" appears. + $this->drupalGet('admin/structure/types/manage/page/fields'); + $this->assertRaw(t('Re-use existing field'), '"Re-use existing field" was found.'); + // Add a new field for the orphaned storage. + $edit = array( + 'fields[_add_existing_field][label]' => $this->randomMachineName(), + 'fields[_add_existing_field][field_name]' => $this->field_name, + ); + $this->fieldUIAddExistingField("admin/structure/types/manage/page", $edit); + } + + /** * Asserts field settings are as expected. * * @param $bundle diff --git a/core/modules/forum/config/install/field.storage.taxonomy_term.forum_container.yml b/core/modules/forum/config/install/field.storage.taxonomy_term.forum_container.yml index abf4e8e..b442e27 100644 --- a/core/modules/forum/config/install/field.storage.taxonomy_term.forum_container.yml +++ b/core/modules/forum/config/install/field.storage.taxonomy_term.forum_container.yml @@ -16,3 +16,4 @@ dependencies: module: - options - taxonomy +persist_with_no_fields: false diff --git a/core/modules/hal/src/Tests/EntityTest.php b/core/modules/hal/src/Tests/EntityTest.php index 47aa4d3..a115146 100644 --- a/core/modules/hal/src/Tests/EntityTest.php +++ b/core/modules/hal/src/Tests/EntityTest.php @@ -30,7 +30,6 @@ protected function setUp() { \Drupal::service('router.builder')->rebuild(); $this->installSchema('system', array('sequences')); $this->installSchema('comment', array('comment_entity_statistics')); - $this->installEntitySchema('node'); $this->installEntitySchema('comment'); $this->installEntitySchema('taxonomy_term'); } diff --git a/core/modules/hal/src/Tests/NormalizerTestBase.php b/core/modules/hal/src/Tests/NormalizerTestBase.php index e7b59d6..58852ac 100644 --- a/core/modules/hal/src/Tests/NormalizerTestBase.php +++ b/core/modules/hal/src/Tests/NormalizerTestBase.php @@ -64,6 +64,25 @@ protected function setUp() { $this->installSchema('system', array('url_alias', 'router')); $this->installEntitySchema('user'); $this->installEntitySchema('entity_test'); + // If the concrete test sub-class installs node.module, ensure that the node + // entity schema is created before the field configurations are installed, + // because the node entity tables need to be created before the body field + // storage tables. This prevents trying to create the body field tables + // twice. + $class = get_class($this); + while ($class) { + if (property_exists($class, 'modules')) { + // Only check the modules, if the $modules property was not inherited. + $rp = new \ReflectionProperty($class, 'modules'); + if ($rp->class == $class) { + if (in_array('node', $class::$modules, TRUE)) { + $this->installEntitySchema('node'); + break; + } + } + } + $class = get_parent_class($class); + } $this->installConfig(array('field', 'language')); // Add German as a language. diff --git a/core/modules/node/config/install/field.storage.node.body.yml b/core/modules/node/config/install/field.storage.node.body.yml new file mode 100644 index 0000000..5b75885 --- /dev/null +++ b/core/modules/node/config/install/field.storage.node.body.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + module: + - node + - text +id: node.body +field_name: body +entity_type: node +type: text_with_summary +settings: { } +module: text +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: true diff --git a/core/modules/node/node.module b/core/modules/node/node.module index afb229a..1aa4a2a 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -328,14 +328,6 @@ function node_add_body_field(NodeTypeInterface $type, $label = 'Body') { // Add or remove the body field, as needed. $field_storage = FieldStorageConfig::loadByName('node', 'body'); $field = FieldConfig::loadByName('node', $type->id(), 'body'); - if (empty($field_storage)) { - $field_storage = entity_create('field_storage_config', array( - 'field_name' => 'body', - 'entity_type' => 'node', - 'type' => 'text_with_summary', - )); - $field_storage->save(); - } if (empty($field)) { $field = entity_create('field_config', array( 'field_storage' => $field_storage, diff --git a/core/modules/node/src/Tests/Condition/NodeConditionTest.php b/core/modules/node/src/Tests/Condition/NodeConditionTest.php index bbba619..548f180 100644 --- a/core/modules/node/src/Tests/Condition/NodeConditionTest.php +++ b/core/modules/node/src/Tests/Condition/NodeConditionTest.php @@ -20,7 +20,6 @@ class NodeConditionTest extends EntityUnitTestBase { protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); // Create the node bundles required for testing. $type = entity_create('node_type', array('type' => 'page', 'name' => 'page')); diff --git a/core/modules/node/src/Tests/NodeBodyFieldStorageTest.php b/core/modules/node/src/Tests/NodeBodyFieldStorageTest.php new file mode 100644 index 0000000..f4c56ce --- /dev/null +++ b/core/modules/node/src/Tests/NodeBodyFieldStorageTest.php @@ -0,0 +1,60 @@ +installSchema('system', 'sequences'); + // Necessary for module uninstall. + $this->installSchema('user', 'users_data'); + $this->installEntitySchema('user'); + $this->installEntitySchema('node'); + $this->installConfig(array('field')); + } + + /** + * Tests node body field storage persistence even if there are no instances. + */ + public function testFieldOverrides() { + $field_storage = FieldStorageConfig::loadByName('node', 'body'); + $this->assertTrue($field_storage, 'Node body field storage exists.'); + NodeType::create(['name' => 'Ponies', 'type' => 'ponies'])->save(); + $field_storage = FieldStorageConfig::loadByName('node', 'body'); + $this->assertTrue(count($field_storage->getBundles()) == 1, 'Node body field storage is being used on the new node type.'); + $field = FieldConfig::loadByName('node', 'ponies', 'body'); + $field->delete(); + $field_storage = FieldStorageConfig::loadByName('node', 'body'); + $this->assertTrue(count($field_storage->getBundles()) == 0, 'Node body field storage exists after deleting the only instance of a field.'); + \Drupal::moduleHandler()->uninstall(array('node')); + $field_storage = FieldStorageConfig::loadByName('node', 'body'); + $this->assertFalse($field_storage, 'Node body field storage does not exist after uninstalling the Node module.'); + } + +} diff --git a/core/modules/node/src/Tests/NodeFieldOverridesTest.php b/core/modules/node/src/Tests/NodeFieldOverridesTest.php index b5d13b4..2472abe 100644 --- a/core/modules/node/src/Tests/NodeFieldOverridesTest.php +++ b/core/modules/node/src/Tests/NodeFieldOverridesTest.php @@ -38,7 +38,6 @@ class NodeFieldOverridesTest extends EntityUnitTestBase { */ protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); $this->installConfig(array('user')); $this->user = $this->createUser(); \Drupal::service('current_user')->setAccount($this->user); diff --git a/core/modules/node/src/Tests/NodeTokenReplaceTest.php b/core/modules/node/src/Tests/NodeTokenReplaceTest.php index 8103866..7c0dfe7 100644 --- a/core/modules/node/src/Tests/NodeTokenReplaceTest.php +++ b/core/modules/node/src/Tests/NodeTokenReplaceTest.php @@ -30,7 +30,6 @@ class NodeTokenReplaceTest extends TokenReplaceUnitTestBase { */ protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); $this->installConfig(array('filter')); $node_type = entity_create('node_type', array('type' => 'article', 'name' => 'Article')); diff --git a/core/modules/node/src/Tests/NodeValidationTest.php b/core/modules/node/src/Tests/NodeValidationTest.php index 3c5e2dd..ef11740 100644 --- a/core/modules/node/src/Tests/NodeValidationTest.php +++ b/core/modules/node/src/Tests/NodeValidationTest.php @@ -28,7 +28,6 @@ class NodeValidationTest extends EntityUnitTestBase { */ protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); // Create a node type for testing. $type = entity_create('node_type', array('type' => 'page', 'name' => 'page')); diff --git a/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml b/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml index daf5c75..f355b2e 100644 --- a/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml +++ b/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml @@ -22,3 +22,4 @@ locked: false cardinality: 1 translatable: true indexes: { } +persist_with_no_fields: false diff --git a/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php index c862e2e..537697f 100644 --- a/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php +++ b/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php @@ -44,7 +44,6 @@ class EntityCrudHookTest extends EntityUnitTestBase { protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); $this->installEntitySchema('comment'); $this->installSchema('user', array('users_data')); diff --git a/core/modules/system/src/Tests/Entity/EntityFieldTest.php b/core/modules/system/src/Tests/Entity/EntityFieldTest.php index 49d5a34..369da19 100644 --- a/core/modules/system/src/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/src/Tests/Entity/EntityFieldTest.php @@ -50,8 +50,6 @@ class EntityFieldTest extends EntityUnitTestBase { protected function setUp() { parent::setUp(); - $this->installEntitySchema('node'); - $this->installEntitySchema('entity_test_rev'); $this->installEntitySchema('entity_test_mul'); $this->installEntitySchema('entity_test_mulrev'); diff --git a/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php index c1dc0ff..d2dc925 100644 --- a/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php @@ -47,6 +47,26 @@ protected function setUp() { $this->installEntitySchema('user'); $this->installEntitySchema('entity_test'); + // If the concrete test sub-class installs node.module, ensure that the node + // entity schema is created before the field configurations are installed, + // because the node entity tables need to be created before the body field + // storage tables. This prevents trying to create the body field tables + // twice. + $class = get_class($this); + while ($class) { + if (property_exists($class, 'modules')) { + // Only check the modules, if the $modules property was not inherited. + $rp = new \ReflectionProperty($class, 'modules'); + if ($rp->class == $class) { + if (in_array('node', $class::$modules, TRUE)) { + $this->installEntitySchema('node'); + break; + } + } + } + $class = get_parent_class($class); + } + $this->installConfig(array('field')); } diff --git a/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php b/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php index f08cbca..d3c19bb 100644 --- a/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php +++ b/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php @@ -33,6 +33,16 @@ class ViewEntityDependenciesTest extends ViewUnitTestBase { public static $modules = ['node', 'comment', 'user', 'field', 'text', 'entity_reference']; /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + // Install the necessary dependencies for node type creation to work. + $this->installEntitySchema('node'); + $this->installConfig(array('field')); + } + + /** * Tests the calculateDependencies method. */ public function testCalculateDependencies() { diff --git a/core/profiles/standard/config/install/field.storage.node.field_image.yml b/core/profiles/standard/config/install/field.storage.node.field_image.yml index 34265d8..2e98e52 100644 --- a/core/profiles/standard/config/install/field.storage.node.field_image.yml +++ b/core/profiles/standard/config/install/field.storage.node.field_image.yml @@ -23,3 +23,4 @@ dependencies: module: - node - image +persist_with_no_fields: false diff --git a/core/profiles/standard/config/install/field.storage.node.field_tags.yml b/core/profiles/standard/config/install/field.storage.node.field_tags.yml index 2eca1d0..60c4546 100644 --- a/core/profiles/standard/config/install/field.storage.node.field_tags.yml +++ b/core/profiles/standard/config/install/field.storage.node.field_tags.yml @@ -20,3 +20,4 @@ dependencies: module: - node - taxonomy +persist_with_no_fields: false diff --git a/core/profiles/standard/config/install/field.storage.user.user_picture.yml b/core/profiles/standard/config/install/field.storage.user.user_picture.yml index 2987390..e4d4960 100644 --- a/core/profiles/standard/config/install/field.storage.user.user_picture.yml +++ b/core/profiles/standard/config/install/field.storage.user.user_picture.yml @@ -23,3 +23,4 @@ dependencies: module: - image - user +persist_with_no_fields: false