Commit 503d9dde authored by catch's avatar catch

Issue #2976035 by amateescu, blazey, hchonov, plach, tstoeckler, catch,...

Issue #2976035 by amateescu, blazey, hchonov, plach, tstoeckler, catch, jibran, larowlan, alexpott: Entity type CRUD operations must use the last installed entity type and field storage definitions
parent 390ffde1
......@@ -172,33 +172,7 @@ public function getChangeSummary() {
* {@inheritdoc}
*/
public function applyUpdates() {
$complete_change_list = $this->getChangeList();
if ($complete_change_list) {
// self::getChangeList() only disables the cache and does not invalidate.
// In case there are changes, explicitly invalidate caches.
$this->clearCachedDefinitions();
}
foreach ($complete_change_list as $entity_type_id => $change_list) {
// Process entity type definition changes before storage definitions ones
// this is necessary when you change an entity type from non-revisionable
// to revisionable and at the same time add revisionable fields to the
// entity type.
if (!empty($change_list['entity_type'])) {
$this->doEntityUpdate($change_list['entity_type'], $entity_type_id);
}
// Process field storage definition changes.
if (!empty($change_list['field_storage_definitions'])) {
$storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type_id);
$original_storage_definitions = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type_id);
foreach ($change_list['field_storage_definitions'] as $field_name => $change) {
$storage_definition = isset($storage_definitions[$field_name]) ? $storage_definitions[$field_name] : NULL;
$original_storage_definition = isset($original_storage_definitions[$field_name]) ? $original_storage_definitions[$field_name] : NULL;
$this->doFieldUpdate($change, $storage_definition, $original_storage_definition);
}
}
}
trigger_error('EntityDefinitionUpdateManagerInterface::applyUpdates() is deprecated in 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface::getChangeList() and execute each entity type and field storage update manually instead. See https://www.drupal.org/node/3034742.', E_USER_DEPRECATED);
}
/**
......@@ -298,69 +272,9 @@ public function uninstallFieldStorageDefinition(FieldStorageDefinitionInterface
}
/**
* Performs an entity type definition update.
*
* @param string $op
* The operation to perform, either static::DEFINITION_CREATED or
* static::DEFINITION_UPDATED.
* @param string $entity_type_id
* The entity type ID.
*/
protected function doEntityUpdate($op, $entity_type_id) {
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
switch ($op) {
case static::DEFINITION_CREATED:
$this->entityTypeListener->onEntityTypeCreate($entity_type);
break;
case static::DEFINITION_UPDATED:
$original = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
$this->entityTypeListener->onEntityTypeUpdate($entity_type, $original);
break;
}
}
/**
* Performs a field storage definition update.
*
* @param string $op
* The operation to perform, possible values are static::DEFINITION_CREATED,
* static::DEFINITION_UPDATED or static::DEFINITION_DELETED.
* @param array|null $storage_definition
* The new field storage definition.
* @param array|null $original_storage_definition
* The original field storage definition.
*/
protected function doFieldUpdate($op, $storage_definition = NULL, $original_storage_definition = NULL) {
switch ($op) {
case static::DEFINITION_CREATED:
$this->fieldStorageDefinitionListener->onFieldStorageDefinitionCreate($storage_definition);
break;
case static::DEFINITION_UPDATED:
$this->fieldStorageDefinitionListener->onFieldStorageDefinitionUpdate($storage_definition, $original_storage_definition);
break;
case static::DEFINITION_DELETED:
$this->fieldStorageDefinitionListener->onFieldStorageDefinitionDelete($original_storage_definition);
break;
}
}
/**
* Gets a list of changes to entity type and field storage definitions.
*
* @return array
* An associative array keyed by entity type id of change descriptors. Every
* entry is an associative array with the following optional keys:
* - entity_type: a scalar having only the DEFINITION_UPDATED value.
* - field_storage_definitions: an associative array keyed by field name of
* scalars having one value among:
* - DEFINITION_CREATED
* - DEFINITION_UPDATED
* - DEFINITION_DELETED
* {@inheritdoc}
*/
protected function getChangeList() {
public function getChangeList() {
$this->entityTypeManager->useCaches(FALSE);
$this->entityFieldManager->useCaches(FALSE);
$change_list = [];
......
......@@ -79,6 +79,23 @@ public function needsUpdates();
*/
public function getChangeSummary();
/**
* Gets a list of changes to entity type and field storage definitions.
*
* @return array
* An associative array keyed by entity type ID of change descriptors. Every
* entry is an associative array with the following optional keys:
* - entity_type: a scalar having one value among:
* - EntityDefinitionUpdateManagerInterface::DEFINITION_CREATED
* - EntityDefinitionUpdateManagerInterface::DEFINITION_UPDATED
* - field_storage_definitions: an associative array keyed by field name of
* scalars having one value among:
* - EntityDefinitionUpdateManagerInterface::DEFINITION_CREATED
* - EntityDefinitionUpdateManagerInterface::DEFINITION_UPDATED
* - EntityDefinitionUpdateManagerInterface::DEFINITION_DELETED
*/
public function getChangeList();
/**
* Applies all the detected valid changes.
*
......@@ -90,6 +107,12 @@ public function getChangeSummary();
* unacceptable data loss. In such a case, the site administrator needs to
* apply some other process, such as a custom update function or a
* migration via the Migrate module.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Use
* \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface::getChangeList()
* and execute each entity type and field storage update manually instead.
*
* @see https://www.drupal.org/node/3034742
*/
public function applyUpdates();
......
......@@ -184,6 +184,7 @@ public static function create(ContentEntityTypeInterface $entity_type, array $st
$all_fields = array_merge($key_fields, array_diff($all_fields, $key_fields));
$revision_metadata_fields = $revisionable ? array_values($entity_type->getRevisionMetadataKeys()) : [];
$revision_metadata_fields = array_intersect($revision_metadata_fields, array_keys($storage_definitions));
if (!$revisionable && !$translatable) {
// The base layout stores all the base field values in the base table.
......
......@@ -7,7 +7,6 @@
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityStorageInterface;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
......@@ -82,16 +81,7 @@ public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $
// @todo Forward this to all interested handlers, not only storage, once
// iterating handlers is possible: https://www.drupal.org/node/2332857.
$storage = clone $this->entityTypeManager->getStorage($entity_type_id);
// Entity type definition updates can change the schema by adding or
// removing entity tables (for example when switching an entity type from
// non-revisionable to revisionable), so CRUD operations on a field storage
// definition need to use the last installed entity type schema.
if ($storage instanceof SqlContentEntityStorage
&& ($last_installed_entity_type = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id))) {
$storage->setEntityType($last_installed_entity_type);
}
$storage = $this->entityTypeManager->getStorage($entity_type_id);
if ($storage instanceof FieldStorageDefinitionListenerInterface) {
$storage->onFieldStorageDefinitionCreate($storage_definition);
......@@ -111,16 +101,7 @@ public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $
// @todo Forward this to all interested handlers, not only storage, once
// iterating handlers is possible: https://www.drupal.org/node/2332857.
$storage = clone $this->entityTypeManager->getStorage($entity_type_id);
// Entity type definition updates can change the schema by adding or
// removing entity tables (for example when switching an entity type from
// non-revisionable to revisionable), so CRUD operations on a field storage
// definition need to use the last installed entity type schema.
if ($storage instanceof SqlContentEntityStorage
&& ($last_installed_entity_type = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id))) {
$storage->setEntityType($last_installed_entity_type);
}
$storage = $this->entityTypeManager->getStorage($entity_type_id);
if ($storage instanceof FieldStorageDefinitionListenerInterface) {
$storage->onFieldStorageDefinitionUpdate($storage_definition, $original);
......@@ -140,16 +121,7 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $
// @todo Forward this to all interested handlers, not only storage, once
// iterating handlers is possible: https://www.drupal.org/node/2332857.
$storage = clone $this->entityTypeManager->getStorage($entity_type_id);
// Entity type definition updates can change the schema by adding or
// removing entity tables (for example when switching an entity type from
// non-revisionable to revisionable), so CRUD operations on a field storage
// definition need to use the last installed entity type schema.
if ($storage instanceof SqlContentEntityStorage
&& ($last_installed_entity_type = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id))) {
$storage->setEntityType($last_installed_entity_type);
}
$storage = $this->entityTypeManager->getStorage($entity_type_id);
// Keep the field definition in the deleted fields repository so we can use
// it later during field_purge_batch(), but only if the field has data.
......
......@@ -35,9 +35,9 @@ class MigrateBlockContentTranslationTest extends MigrateDrupal6TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('block_content');
$this->installConfig(['block']);
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->executeMigrations([
'd6_filter_format',
......
......@@ -38,8 +38,8 @@ protected function setUp() {
// Install the themes used for this test.
$this->container->get('theme_installer')->install(['bartik', 'test_theme']);
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->installConfig(['block_content']);
// Set Bartik as the default public theme.
$config = $this->config('system.theme');
......
......@@ -39,9 +39,9 @@ class MigrateBlockContentTranslationTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('block_content');
$this->installConfig(['block']);
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->executeMigrations([
'language',
......
......@@ -37,8 +37,8 @@ protected function setUp() {
// Install the themes used for this test.
$this->container->get('theme_installer')->install(['bartik', 'seven']);
$this->installConfig(static::$modules);
$this->installEntitySchema('block_content');
$this->installConfig(static::$modules);
// Set Bartik and Seven as the default public and admin theme.
$config = $this->config('system.theme');
......
......@@ -22,8 +22,8 @@ class MigrateBlockContentBodyFieldTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->installConfig(['block_content']);
$this->executeMigrations([
'block_content_type',
'block_content_body_field',
......
......@@ -22,6 +22,7 @@ class MigrateBlockContentEntityDisplayTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('block_content');
$this->installConfig(static::$modules);
$this->executeMigrations([
'block_content_type',
......
......@@ -22,6 +22,7 @@ class MigrateBlockContentEntityFormDisplayTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('block_content');
$this->installConfig(static::$modules);
$this->executeMigrations([
'block_content_type',
......
......@@ -20,8 +20,8 @@ class MigrateBlockContentTypeTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->installConfig(['block_content']);
$this->executeMigration('block_content_type');
}
......
......@@ -22,8 +22,8 @@ class MigrateBlockContentTest extends MigrateDrupal6TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->installConfig(['block_content']);
$this->executeMigrations([
'd6_filter_format',
......
......@@ -28,8 +28,8 @@ class MigrateCustomBlockContentTranslationTest extends MigrateDrupal6TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->installConfig(['block_content']);
$this->executeMigrations([
'language',
'd6_filter_format',
......
......@@ -30,8 +30,8 @@ class MigrateCustomBlockContentTranslationTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->installConfig(['block_content']);
$this->executeMigrations([
'language',
'd7_filter_format',
......
......@@ -24,8 +24,8 @@ class MigrateCustomBlockTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installConfig(static::$modules);
$this->installEntitySchema('block_content');
$this->installConfig(static::$modules);
$this->executeMigrations([
'd7_filter_format',
......
......@@ -15,7 +15,7 @@ class MigrateBookTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['book', 'menu_ui'];
public static $modules = ['book', 'node', 'menu_ui'];
/**
* {@inheritdoc}
......
......@@ -27,6 +27,7 @@ class CommentItemTest extends FieldKernelTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('comment');
$this->installSchema('comment', ['comment_entity_statistics']);
$this->installConfig(['comment']);
}
......
......@@ -30,6 +30,7 @@ class CommentStringIdEntitiesTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('comment');
$this->installEntitySchema('entity_test_string_id');
$this->installSchema('comment', ['comment_entity_statistics']);
// Create the comment body field storage.
$this->installConfig(['field']);
......
......@@ -5,19 +5,24 @@
* Contains install and update hooks.
*/
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
/**
* Implements hook_install().
*/
function contact_storage_test_install() {
$entity_type_manager = \Drupal::entityTypeManager();
$entity_type = $entity_type_manager->getDefinition('contact_message');
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
// Recreate the original entity type definition, in order to notify the
// manager of what changed. The change of storage backend will trigger
// schema installation.
// @see contact_storage_test_entity_type_alter()
$original = clone $entity_type;
$original->setStorageClass('Drupal\Core\Entity\ContentEntityNullStorage');
$original = $entity_definition_update_manager->getEntityType('contact_message');
$entity_definition_update_manager->uninstallEntityType($original);
\Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $original);
// Update the entity type definition and make it use the default SQL storage.
// @see contact_storage_test_entity_type_alter()
$entity_type = clone $original;
$entity_type->setStorageClass(SqlContentEntityStorage::class);
$keys = $entity_type->getKeys();
$keys['id'] = 'id';
$entity_type->set('entity_keys', $keys);
$entity_type->set('base_table', 'contact_message');
$entity_definition_update_manager->installEntityType($entity_type);
}
......@@ -13,6 +13,7 @@
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
use Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait;
use Drupal\workflows\Entity\Workflow;
/**
......@@ -23,6 +24,7 @@
class ContentModerationStateTest extends KernelTestBase {
use ContentModerationTestTrait;
use EntityDefinitionTestTrait;
/**
* {@inheritdoc}
......@@ -529,7 +531,7 @@ public function testNonLangcodeEntityTypeModeration() {
\Drupal::state()->set('entity_test_rev.entity_type', $entity_type);
// Update the entity type in order to remove the 'langcode' field.
\Drupal::entityDefinitionUpdateManager()->applyUpdates();
$this->applyEntityUpdates('entity_test_rev');
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
......
......@@ -177,7 +177,6 @@ protected function enableTranslation() {
\Drupal::entityManager()->clearCachedDefinitions();
\Drupal::service('router.builder')->rebuild();
\Drupal::service('entity.definition_update_manager')->applyUpdates();
}
/**
......
......@@ -51,7 +51,6 @@ protected function setUp() {
\Drupal::service('content_translation.manager')->setEnabled('node', 'article', TRUE);
\Drupal::service('router.builder')->rebuild();
\Drupal::service('entity.definition_update_manager')->applyUpdates();
$this->baseUser1 = $this->drupalCreateUser(['access content overview']);
$this->baseUser2 = $this->drupalCreateUser(['access content overview', 'create content translations', 'update content translations', 'delete content translations']);
......
......@@ -170,7 +170,6 @@ protected function enableTranslation() {
\Drupal::service('content_translation.manager')->setEnabled($this->entityTypeId, $this->bundle, TRUE);
\Drupal::service('router.builder')->rebuild();
\Drupal::service('entity.definition_update_manager')->applyUpdates();
}
/**
......
......@@ -21,13 +21,13 @@ function field_test_entity_type_alter(array &$entity_types) {
function field_test_entity_info_translatable($entity_type_id = NULL, $translatable = NULL) {
$stored_value = &drupal_static(__FUNCTION__, []);
if (isset($entity_type_id)) {
$entity_type_manager = \Drupal::entityTypeManager();
$original = $entity_type_manager->getDefinition($entity_type_id);
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = $entity_definition_update_manager->getEntityType($entity_type_id);
$stored_value[$entity_type_id] = $translatable;
if ($translatable != $original->isTranslatable()) {
$entity_type_manager->clearCachedDefinitions();
$entity_type = $entity_type_manager->getDefinition($entity_type_id);
\Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $original);
if ($translatable != $entity_type->isTranslatable()) {
$entity_definition_update_manager->uninstallEntityType($entity_type);
$entity_type->set('translatable', $translatable);
$entity_definition_update_manager->installEntityType($entity_type);
}
}
return $stored_value;
......
......@@ -224,7 +224,6 @@ protected function enableTranslation() {
\Drupal::service('content_translation.manager')->setEnabled($this->testEntityTypeName, $this->referencedType->id(), TRUE);
\Drupal::service('router.builder')->rebuild();
\Drupal::service('entity.definition_update_manager')->applyUpdates();
}
/**
......
......@@ -43,6 +43,7 @@ protected function setUp() {
$this->entityManager = $this->container->get('entity.manager');
// Create a second field on 'entity_test_rev'.
$this->installEntitySchema('entity_test_rev');
$this->createFieldWithStorage('_rev', 'entity_test_rev', 'entity_test_rev');
}
......
......@@ -7,6 +7,7 @@
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait;
/**
* Tests that schema changes in fields with data are detected during updates.
......@@ -15,6 +16,8 @@
*/
class SqlContentEntityStorageSchemaColumnTest extends KernelTestBase {
use EntityDefinitionTestTrait;
/**
* {@inheritdoc}
*/
......@@ -88,7 +91,9 @@ public function testColumnUpdate() {
// Now attempt to run automatic updates. An exception should be thrown
// since there is data in the table.
try {
\Drupal::service('entity.definition_update_manager')->applyUpdates();
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$field_storage_definition = $entity_definition_update_manager->getFieldStorageDefinition('test', 'entity_test_rev');
$entity_definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
$this->fail('Failed to detect a schema change in a field with data.');
}
catch (FieldStorageDefinitionUpdateForbiddenException $e) {
......
......@@ -15,7 +15,7 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['menu_ui'];
public static $modules = ['menu_ui', 'node'];
/**
* {@inheritdoc}
......
......@@ -17,7 +17,7 @@ class MigrateFieldInstanceTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['menu_ui'];
public static $modules = ['menu_ui', 'node'];
/**
* Tests migration of file variables to file.settings.yml.
......
......@@ -13,7 +13,7 @@
*/
class MigrateViewModesTest extends MigrateDrupal7TestBase {
public static $modules = ['comment', 'node', 'taxonomy'];
public static $modules = ['comment', 'node', 'taxonomy', 'text'];
/**
* {@inheritdoc}
......
......@@ -12,6 +12,11 @@
*/
class RollbackViewModesTest extends MigrateViewModesTest {
/**
* {@inheritdoc}
*/
public static $modules = ['text'];
/**
* Tests migrating D7 view modes, then rolling back.
*/
......
......@@ -72,6 +72,7 @@ class TranslationTest extends FieldKernelTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installConfig(['language']);
$this->fieldName = mb_strtolower($this->randomMachineName());
......
......@@ -32,6 +32,7 @@ class EntityDisplayTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->installConfig(['field', 'node', 'user']);
......
......@@ -24,6 +24,7 @@ class EntityFormDisplayTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test');
}
/**
......
......@@ -35,6 +35,7 @@ class FileItemValidationTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installEntitySchema('user');
$this->installEntitySchema('file');
$this->installSchema('file', 'file_usage');
......
......@@ -22,6 +22,14 @@ class ImageStyleIntegrationTest extends KernelTestBase {
*/
public static $modules = ['image', 'file', 'field', 'system', 'user', 'node'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
}
/**
* Tests the dependency between ImageStyle and entity display components.
*/
......
......@@ -21,6 +21,15 @@ class ImageViewsDataTest extends ViewsKernelTestBase {
*/
public static $modules = ['image', 'file', 'views', 'entity_test', 'user', 'field'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->installEntitySchema('entity_test');
$this->installEntitySchema('entity_test_mul');
}
/**
* Tests views data generated for image field relationship.
*
......
......@@ -26,8 +26,7 @@ protected function setUp() {
parent::setUp();
ConfigurableLanguage::createFromLangcode('fr')->save();
$this->config('system.site')->set('default_langcode', 'fr')->save();
// Make sure new entity type definitions are processed.
\Drupal::service('entity.definition_update_manager')->applyUpdates();
// Clear all caches so that the base field definition, its cache in the
// entity manager, the t() cache, etc. are all cleared.
drupal_flush_all_caches();
......
......@@ -35,10 +35,10 @@ class EntityRevisionTest extends MigrateTestBase {
*/
protected function setUp() {
parent::setUp();
$this->installConfig('node');
$this->installSchema('node', ['node_access']);
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->installConfig('node');
$this->installSchema('node', ['node_access']);
}
/**
......