diff --git a/core/modules/system/src/SystemConfigSubscriber.php b/core/modules/system/src/SystemConfigSubscriber.php index ddd37be..dc2f86b 100644 --- a/core/modules/system/src/SystemConfigSubscriber.php +++ b/core/modules/system/src/SystemConfigSubscriber.php @@ -78,6 +78,53 @@ public function onConfigImporterValidateSiteUUID(ConfigImporterEvent $event) { } /** + * Checks for any pending database updates. + * + * As pending database update can cause issues as they potentially make + * changes code base and database. + * + * @see https://www.drupal.org/node/2628144 + * + * @param ConfigImporterEvent $event + * The config import event. + */ + public function onConfigImporterValidateDatabaseUpdate(ConfigImporterEvent $event) { + if ($this->hasModuleUpdates()) { + $event->getConfigImporter()->logError($this->t('Pending database updates available.')); + } + } + + /** + * Checks if there any pending database updates. + * + * @return bool + * TRUE, if there any pending update on modules, FALSE otherwise. + */ + protected function hasModuleUpdates() { + // Check installed modules. + $has_pending_updates = FALSE; + foreach (\Drupal::moduleHandler()->getModuleList() as $module => $filename) { + $updates = drupal_get_schema_versions($module); + if ($updates !== FALSE) { + $default = drupal_get_installed_schema_version($module); + if (max($updates) > $default) { + $has_pending_updates = TRUE; + break; + } + } + } + /*if (!$has_pending_updates) { + $post_update_registry = \Drupal::service('update.post_update_registry'); + $missing_post_update_functions = $post_update_registry->getPendingUpdateFunctions(); + if (!empty($missing_post_update_functions)) { + $has_pending_updates = TRUE; + } + }*/ + + return $has_pending_updates; + } + + /** * {@inheritdoc} */ public static function getSubscribedEvents() { @@ -86,6 +133,7 @@ public static function getSubscribedEvents() { // there is no configuration to import. $events[ConfigEvents::IMPORT_VALIDATE][] = ['onConfigImporterValidateNotEmpty', 512]; $events[ConfigEvents::IMPORT_VALIDATE][] = ['onConfigImporterValidateSiteUUID', 256]; + $events[ConfigEvents::IMPORT_VALIDATE][] = ['onConfigImporterValidateDatabaseUpdate', 255]; return $events; } diff --git a/core/modules/system/src/Tests/Update/UpdatePendingConfigImportTest.php b/core/modules/system/src/Tests/Update/UpdatePendingConfigImportTest.php new file mode 100644 index 0000000..6022ef1 --- /dev/null +++ b/core/modules/system/src/Tests/Update/UpdatePendingConfigImportTest.php @@ -0,0 +1,76 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz', + __DIR__ . '/../../../tests/fixtures/update/drupal-8.update-test-config-import.php', + ]; + } + + /** + * {@inheritdoc} + */ + protected function doSelectionTest() { + parent::doSelectionTest(); + $this->assertRaw('8001 - Pending update.'); + } + + /** + * Tests database update with configuration import. + */ + public function testConfigImport() { + + // Add 'profile' key so we don't get notices. + \Drupal::configFactory()->getEditable('core.extension')->set('profile', \Drupal::installProfile())->save(); + // Export active config to sync. + $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync')); + // Get site name. + $site_name = \Drupal::config('system.site')->get('name'); + // Change site name. + \Drupal::configFactory()->getEditable('system.site')->set('name', 'Do not sync config before all database have ran.')->save(); + + try { + // Try running config import with pending. + $this->configImporter()->import(); + } + catch (ConfigImporterException $e) { + $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.'); + $error_log = $this->configImporter->getErrors(); + $expected = array('Pending database updates available.'); + $this->assertEqual($expected, $error_log); + } + + // Run database updates. + $this->runUpdates(); + $this->drupalGet('update.php/selection'); + $this->assertText('No pending updates.'); + + // Run config import with no pending updates. + try { + // Try running config import with pending. + $this->configImporter->import(); + } + catch (ConfigImporterException $e) { + $error_log = $this->configImporter->getErrors(); + $expected = []; + $this->assertEqual($expected, $error_log); + } + + $this->assertEqual($site_name, \Drupal::config('system.site')->get('name')); + } + +} diff --git a/core/modules/system/tests/fixtures/update/drupal-8.update-test-config-import.php b/core/modules/system/tests/fixtures/update/drupal-8.update-test-config-import.php new file mode 100644 index 0000000..f3e5180 --- /dev/null +++ b/core/modules/system/tests/fixtures/update/drupal-8.update-test-config-import.php @@ -0,0 +1,39 @@ +merge('key_value') + ->condition('collection', 'system.schema') + ->condition('name', 'update_test_config_import') + ->fields([ + 'collection' => 'system.schema', + 'name' => 'update_test_config_import', + 'value' => 'i:8000;', + ]) + ->execute(); + +// Update core.extension. +$extensions = $connection->select('config') + ->fields('config', ['data']) + ->condition('collection', '') + ->condition('name', 'core.extension') + ->execute() + ->fetchField(); +$extensions = unserialize($extensions); +$extensions['module']['update_test_config_import'] = 8000; +$connection->update('config') + ->fields([ + 'data' => serialize($extensions), + ]) + ->condition('collection', '') + ->condition('name', 'core.extension') + ->execute(); diff --git a/core/modules/system/tests/modules/update_test_config_import/update_test_config_import.info.yml b/core/modules/system/tests/modules/update_test_config_import/update_test_config_import.info.yml new file mode 100644 index 0000000..faf112f --- /dev/null +++ b/core/modules/system/tests/modules/update_test_config_import/update_test_config_import.info.yml @@ -0,0 +1,5 @@ +core: 8.x +name: Update test config import +type: module +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/update_test_config_import/update_test_config_import.install b/core/modules/system/tests/modules/update_test_config_import/update_test_config_import.install new file mode 100644 index 0000000..11ec5e3 --- /dev/null +++ b/core/modules/system/tests/modules/update_test_config_import/update_test_config_import.install @@ -0,0 +1,12 @@ +container->get('database')->schema()->createTable($table, $schema); + + // Set a very high schema version so no updates are found because we + // don't want to run them anyway. + drupal_set_installed_schema_version($module, 8888); } }