/** * Tests the missing content event is fired. * * @see \Drupal\Core\Config\ConfigImporter::processMissingContent() * @see \Drupal\config_import_test\EventSubscriber */ function testMissingContent() { \Drupal::state()->set('config_import_test.config_import_missing_content', TRUE); // Update a configuration entity in the sync directory to have a dependency // on two content entities that do not exist. $storage = $this->container->get('config.storage'); $sync = $this->container->get('config.storage.sync'); $entity_one = entity_create('entity_test', array('name' => 'one')); $entity_two = entity_create('entity_test', array('name' => 'two')); $entity_three = entity_create('entity_test', array('name' => 'three')); $dynamic_name = 'config_test.dynamic.dotted.default'; $original_dynamic_data = $storage->read($dynamic_name); // Entity one will be resolved by // \Drupal\config_import_test\EventSubscriber::onConfigImporterMissingContentOne(). $original_dynamic_data['dependencies']['content'][] = $entity_one->getConfigDependencyName(); // Entity two will be resolved by // \Drupal\config_import_test\EventSubscriber::onConfigImporterMissingContentTwo(). $original_dynamic_data['dependencies']['content'][] = $entity_two->getConfigDependencyName(); // Entity three will be resolved by // \Drupal\Core\Config\Importer\FinalMissingContentSubscriber. $original_dynamic_data['dependencies']['content'][] = $entity_three->getConfigDependencyName(); $sync->write($dynamic_name, $original_dynamic_data); // Import. $this->configImporter->reset()->import(); $this->assertEqual([], $this->configImporter->getErrors(), 'There were no errors during the import.'); $this->assertEqual($entity_one->uuid(), \Drupal::state()->get('config_import_test.config_import_missing_content_one'), 'The missing content event is fired during configuration import.'); $this->assertEqual($entity_two->uuid(), \Drupal::state()->get('config_import_test.config_import_missing_content_two'), 'The missing content event is fired during configuration import.'); $original_dynamic_data = $storage->read($dynamic_name); $this->assertEqual([$entity_one->getConfigDependencyName(), $entity_two->getConfigDependencyName(), $entity_three->getConfigDependencyName()], $original_dynamic_data['dependencies']['content'], 'The imported configuration entity has the missing content entity dependency.'); }
/** * Tests configuration renaming validation for simple configuration. */ public function testRenameSimpleConfigValidation() { $uuid = new Php(); // Create a simple configuration with a UUID. $config = $this->config('config_test.new'); $uuid_value = $uuid->generate(); $config->set('uuid', $uuid_value)->save(); $active = $this->container->get('config.storage'); $sync = $this->container->get('config.storage.sync'); $this->copyConfig($active, $sync); $config->delete(); // Create another simple configuration with the same UUID. $config = $this->config('config_test.old'); $config->set('uuid', $uuid_value)->save(); // Confirm that the staged configuration is detected as a rename since the // UUIDs match. $this->configImporter->reset(); $expected = array('config_test.old::config_test.new'); $renames = $this->configImporter->getUnprocessedConfiguration('rename'); $this->assertIdentical($expected, $renames); // Try to import the configuration. We expect an exception to be thrown // because the rename is for simple configuration. try { $this->configImporter->import(); $this->fail('Expected ConfigImporterException thrown when simple configuration is renamed.'); } catch (ConfigImporterException $e) { $this->pass('Expected ConfigImporterException thrown when simple configuration is renamed.'); $expected = array(SafeMarkup::format('Rename operation for simple configuration. Existing configuration @old_name and staged configuration @new_name.', array('@old_name' => 'config_test.old', '@new_name' => 'config_test.new'))); $this->assertEqual($expected, $this->configImporter->getErrors()); } }
private function configImport($io, StorageComparer $storage_comparer) { $config_importer = new ConfigImporter($storage_comparer, \Drupal::service('event_dispatcher'), \Drupal::service('config.manager'), \Drupal::lock(), \Drupal::service('config.typed'), \Drupal::moduleHandler(), \Drupal::service('module_installer'), \Drupal::service('theme_handler'), \Drupal::service('string_translation')); if ($config_importer->alreadyImporting()) { $io->success($this->trans('commands.config.import.messages.already-imported')); } else { try { if ($config_importer->validate()) { $sync_steps = $config_importer->initialize(); foreach ($sync_steps as $step) { $context = array(); do { $config_importer->doSyncStep($step, $context); } while ($context['finished'] < 1); } } } catch (ConfigImporterException $e) { $message = 'The import failed due for the following reasons:' . "\n"; $message .= implode("\n", $config_importer->getErrors()); $io->error(sprintf($this->trans('commands.site.import.local.messages.error-writing'), $message)); } catch (\Exception $e) { $io->error(sprintf($this->trans('commands.site.import.local.messages.error-writing'), $e->getMessage())); } } }
/** * Tests missing core.extension during configuration import. * * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber */ public function testMissingCoreExtension() { $staging = $this->container->get('config.storage.staging'); $staging->delete('core.extension'); try { $this->configImporter->reset()->import(); $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to missing dependencies.'); } catch (ConfigImporterException $e) { $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.'); $error_log = $this->configImporter->getErrors(); $this->assertEqual(['The core.extension configuration does not exist.'], $error_log); } }
/** * Tests install profile validation during configuration import. * * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber */ public function testInstallProfile() { $sync = $this->container->get('config.storage.sync'); $extensions = $sync->read('core.extension'); // Add an install profile. $extensions['module']['standard'] = 0; $sync->write('core.extension', $extensions); try { $this->configImporter->reset()->import(); $this->fail('ConfigImporterException not thrown; an invalid import was not stopped due to missing dependencies.'); } catch (ConfigImporterException $e) { $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.'); $error_log = $this->configImporter->getErrors(); // Install profiles should not even be scanned at this point. $this->assertEqual(['Unable to install the <em class="placeholder">standard</em> module since it does not exist.'], $error_log); } }
private function configImport(DrupalStyle $io, StorageComparer $storage_comparer) { $config_importer = new ConfigImporter($storage_comparer, \Drupal::service('event_dispatcher'), \Drupal::service('config.manager'), \Drupal::lock(), \Drupal::service('config.typed'), \Drupal::moduleHandler(), \Drupal::service('module_installer'), \Drupal::service('theme_handler'), \Drupal::service('string_translation')); if ($config_importer->alreadyImporting()) { $io->success($this->trans('commands.config.import.messages.already-imported')); } else { try { $config_importer->import(); $io->info($this->trans('commands.config.import.messages.importing')); } catch (ConfigImporterException $e) { $message = 'The import failed due for the following reasons:' . "\n"; $message .= implode("\n", $config_importer->getErrors()); $io->error(sprintf($this->trans('commands.site.import.local.messages.error-writing'), $message)); } catch (\Exception $e) { $io->error(sprintf($this->trans('commands.site.import.local.messages.error-writing'), $e->getMessage())); } } }
/** * Tests updating of configuration during import. */ function testUpdated() { $name = 'config_test.system'; $dynamic_name = 'config_test.dynamic.dotted.default'; $storage = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); // Verify that the configuration objects to import exist. $this->assertIdentical($storage->exists($name), TRUE, $name . ' found.'); $this->assertIdentical($storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); // Replace the file content of the existing configuration objects in the // staging directory. $original_name_data = array('foo' => 'beer'); $staging->write($name, $original_name_data); $original_dynamic_data = $storage->read($dynamic_name); $original_dynamic_data['label'] = 'Updated'; $staging->write($dynamic_name, $original_dynamic_data); // Verify the active configuration still returns the default values. $config = \Drupal::config($name); $this->assertIdentical($config->get('foo'), 'bar'); $config = \Drupal::config($dynamic_name); $this->assertIdentical($config->get('label'), 'Default'); // Import. $this->configImporter->reset()->import(); // Verify the values were updated. \Drupal::configFactory()->reset($name); $config = \Drupal::config($name); $this->assertIdentical($config->get('foo'), 'beer'); $config = \Drupal::config($dynamic_name); $this->assertIdentical($config->get('label'), 'Updated'); // Verify that the original file content is still the same. $this->assertIdentical($staging->read($name), $original_name_data); $this->assertIdentical($staging->read($dynamic_name), $original_dynamic_data); // Verify that appropriate module API hooks have been invoked. $this->assertTrue(isset($GLOBALS['hook_config_test']['load'])); $this->assertTrue(isset($GLOBALS['hook_config_test']['presave'])); $this->assertFalse(isset($GLOBALS['hook_config_test']['insert'])); $this->assertTrue(isset($GLOBALS['hook_config_test']['update'])); $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete'])); $this->assertFalse(isset($GLOBALS['hook_config_test']['delete'])); // Verify that there is nothing more to import. $this->assertFalse($this->configImporter->hasUnprocessedConfigurationChanges()); $logs = $this->configImporter->getErrors(); $this->assertEqual(count($logs), 0); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $config_importer = new ConfigImporter($form_state->get('storage_comparer'), $this->eventDispatcher, $this->configManager, $this->lock, $this->typedConfigManager, $this->moduleHandler, $this->themeHandler, $this->getStringTranslation()); if ($config_importer->alreadyImporting()) { drupal_set_message($this->t('Another request may be synchronizing configuration already.')); } else { try { $sync_steps = $config_importer->initialize(); $batch = array('operations' => array(), 'finished' => array(get_class($this), 'finishBatch'), 'title' => t('Synchronizing configuration'), 'init_message' => t('Starting configuration synchronization.'), 'progress_message' => t('Completed @current step of @total.'), 'error_message' => t('Configuration synchronization has encountered an error.'), 'file' => drupal_get_path('module', 'config') . '/config.admin.inc'); foreach ($sync_steps as $sync_step) { $batch['operations'][] = array(array(get_class($this), 'processBatch'), array($config_importer, $sync_step)); } batch_set($batch); } catch (ConfigImporterException $e) { // There are validation errors. drupal_set_message($this->t('The configuration synchronization failed validation.')); foreach ($config_importer->getErrors() as $message) { drupal_set_message($message, 'error'); } } } }