protected function setUp()
 {
     parent::setUp();
     $this->installEntitySchema('node');
     $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging'));
     // Set up the ConfigImporter object for testing.
     $storage_comparer = new StorageComparer($this->container->get('config.storage.staging'), $this->container->get('config.storage'), $this->container->get('config.manager'));
     $this->configImporter = new ConfigImporter($storage_comparer->createChangelist(), $this->container->get('event_dispatcher'), $this->container->get('config.manager'), $this->container->get('lock'), $this->container->get('config.typed'), $this->container->get('module_handler'), $this->container->get('theme_handler'), $this->container->get('string_translation'));
 }
Esempio n. 2
0
 protected function setUp()
 {
     parent::setUp();
     $this->installConfig(array('config_test'));
     // Installing config_test's default configuration pollutes the global
     // variable being used for recording hook invocations by this test already,
     // so it has to be cleared out manually.
     unset($GLOBALS['hook_config_test']);
     $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging'));
     // Set up the ConfigImporter object for testing.
     $storage_comparer = new StorageComparer($this->container->get('config.storage.staging'), $this->container->get('config.storage'), $this->container->get('config.manager'));
     $this->configImporter = new ConfigImporter($storage_comparer->createChangelist(), $this->container->get('event_dispatcher'), $this->container->get('config.manager'), $this->container->get('lock'), $this->container->get('config.typed'), $this->container->get('module_handler'), $this->container->get('module_installer'), $this->container->get('theme_handler'), $this->container->get('string_translation'));
 }
 /**
  * Tests deleting a contact form entity via a configuration import.
  *
  * @see \Drupal\Core\Entity\Event\BundleConfigImportValidate
  */
 public function testDeleteThroughImport()
 {
     $contact_form = ContactForm::create(['id' => 'test']);
     $contact_form->save();
     $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
     // Set up the ConfigImporter object for testing.
     $storage_comparer = new StorageComparer($this->container->get('config.storage.sync'), $this->container->get('config.storage'), $this->container->get('config.manager'));
     $config_importer = new ConfigImporter($storage_comparer->createChangelist(), $this->container->get('event_dispatcher'), $this->container->get('config.manager'), $this->container->get('lock'), $this->container->get('config.typed'), $this->container->get('module_handler'), $this->container->get('module_installer'), $this->container->get('theme_handler'), $this->container->get('string_translation'));
     // Delete the contact message in sync.
     $sync = $this->container->get('config.storage.sync');
     $sync->delete($contact_form->getConfigDependencyName());
     // Import.
     $config_importer->reset()->import();
     $this->assertNull(ContactForm::load($contact_form->id()), 'The contact form has been deleted.');
 }
Esempio n. 4
0
 /**
  * {@inheritdoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $io = new DrupalStyle($input, $output);
     $directory = $input->getOption('directory');
     if ($directory) {
         $configSyncDir = $directory;
     } else {
         $configSyncDir = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
     }
     $source_storage = new FileStorage($configSyncDir);
     $storage_comparer = new StorageComparer($source_storage, $this->configStorage, $this->configManager);
     if (!$storage_comparer->createChangelist()->hasChanges()) {
         $io->success($this->trans('commands.config.import.messages.nothing-to-do'));
     }
     if ($this->configImport($io, $storage_comparer)) {
         $io->success($this->trans('commands.config.import.messages.imported'));
     }
 }
Esempio n. 5
0
 /**
  * {@inheritdoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $io = new DrupalStyle($input, $output);
     $directory = $input->getArgument('directory');
     $source_storage = new FileStorage($directory);
     if ($input->getOption('reverse')) {
         $config_comparer = new StorageComparer($source_storage, $this->configStorage, $this->configManager);
     } else {
         $config_comparer = new StorageComparer($this->configStorage, $source_storage, $this->configManager);
     }
     if (!$config_comparer->createChangelist()->hasChanges()) {
         $output->writeln($this->trans('commands.config.diff.messages.no-changes'));
     }
     $change_list = [];
     foreach ($config_comparer->getAllCollectionNames() as $collection) {
         $change_list[$collection] = $config_comparer->getChangelist(null, $collection);
     }
     $this->outputDiffTable($io, $change_list);
 }
 /**
  * Tests config snapshot creation and updating.
  */
 function testSnapshot()
 {
     $active = $this->container->get('config.storage');
     $sync = $this->container->get('config.storage.sync');
     $snapshot = $this->container->get('config.storage.snapshot');
     $config_manager = $this->container->get('config.manager');
     $config_name = 'config_test.system';
     $config_key = 'foo';
     $new_data = 'foobar';
     $active_snapshot_comparer = new StorageComparer($active, $snapshot, $config_manager);
     $sync_snapshot_comparer = new StorageComparer($sync, $snapshot, $config_manager);
     // Verify that we have an initial snapshot that matches the active
     // configuration. This has to be true as no config should be installed.
     $this->assertFalse($active_snapshot_comparer->createChangelist()->hasChanges());
     // Install the default config.
     $this->installConfig(array('config_test'));
     // Although we have imported config this has not affected the snapshot.
     $this->assertTrue($active_snapshot_comparer->reset()->hasChanges());
     // Update the config snapshot.
     \Drupal::service('config.manager')->createSnapshot($active, $snapshot);
     // The snapshot and active config should now contain the same config
     // objects.
     $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
     // Change a configuration value in sync.
     $sync_data = $this->config($config_name)->get();
     $sync_data[$config_key] = $new_data;
     $sync->write($config_name, $sync_data);
     // Verify that active and snapshot match, and that sync doesn't match
     // active.
     $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
     $this->assertTrue($sync_snapshot_comparer->createChangelist()->hasChanges());
     // Import changed data from sync to active.
     $this->configImporter()->import();
     // Verify changed config was properly imported.
     \Drupal::configFactory()->reset($config_name);
     $this->assertIdentical($this->config($config_name)->get($config_key), $new_data);
     // Verify that a new snapshot was created which and that it matches
     // the active config.
     $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
 }
Esempio n. 7
0
 /**
  * {@inheritdoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $io = new DrupalStyle($input, $output);
     $archiveFile = $input->getOption('file');
     $directory = $input->getOption('directory');
     $removeFiles = $input->getOption('remove-files');
     if ($directory) {
         $configSyncDir = $directory;
     } else {
         $configSyncDir = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
     }
     // Determine $source_storage in partial and non-partial cases.
     $active_storage = \Drupal::service('config.storage');
     $source_storage = new FileStorage($configSyncDir);
     /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
     $config_manager = \Drupal::service('config.manager');
     $storage_comparer = new StorageComparer($source_storage, $active_storage, $config_manager);
     if (!$storage_comparer->createChangelist()->hasChanges()) {
         $io->success($this->trans('commands.config.import.messages.nothing-to-do'));
     }
     if ($this->configImport($io, $storage_comparer)) {
         $io->success($this->trans('commands.config.import.messages.imported'));
     }
 }
Esempio n. 8
0
 /**
  * @covers ::createChangelist
  */
 public function testCreateChangelistUpdate()
 {
     $target_data = $source_data = $this->getConfigData();
     $source_data['system.site']['title'] = 'Drupal New!';
     $source_data['field.field.node.article.body']['new_config_key'] = 'new data';
     $source_data['field.storage.node.body']['new_config_key'] = 'new data';
     $this->sourceStorage->expects($this->once())->method('listAll')->will($this->returnValue(array_keys($source_data)));
     $this->targetStorage->expects($this->once())->method('listAll')->will($this->returnValue(array_keys($target_data)));
     $this->sourceStorage->expects($this->once())->method('readMultiple')->will($this->returnValue($source_data));
     $this->targetStorage->expects($this->once())->method('readMultiple')->will($this->returnValue($target_data));
     $this->sourceStorage->expects($this->once())->method('getAllCollectionNames')->will($this->returnValue(array()));
     $this->targetStorage->expects($this->once())->method('getAllCollectionNames')->will($this->returnValue(array()));
     $this->storageComparer->createChangelist();
     $expected = array('field.storage.node.body', 'system.site', 'field.field.node.article.body');
     $this->assertEquals($expected, $this->storageComparer->getChangelist('update'));
     $this->assertEmpty($this->storageComparer->getChangelist('create'));
     $this->assertEmpty($this->storageComparer->getChangelist('delete'));
 }
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     $snapshot_comparer = new StorageComparer($this->activeStorage, $this->snapshotStorage, $this->configManager);
     if (!$form_state->getUserInput() && $snapshot_comparer->createChangelist()->hasChanges()) {
         $change_list = array();
         foreach ($snapshot_comparer->getAllCollectionNames() as $collection) {
             foreach ($snapshot_comparer->getChangelist(NULL, $collection) as $config_names) {
                 if (empty($config_names)) {
                     continue;
                 }
                 foreach ($config_names as $config_name) {
                     $change_list[] = $config_name;
                 }
             }
         }
         sort($change_list);
         $change_list_render = array('#theme' => 'item_list', '#items' => $change_list);
         $change_list_html = drupal_render($change_list_render);
         drupal_set_message($this->t('Your current configuration has changed. Changes to these configuration items will be lost on the next synchronization: !changes', array('!changes' => $change_list_html)), 'warning');
     }
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Import all'));
     $source_list = $this->stagingStorage->listAll();
     $storage_comparer = new StorageComparer($this->stagingStorage, $this->activeStorage, $this->configManager);
     if (empty($source_list) || !$storage_comparer->createChangelist()->hasChanges()) {
         $form['no_changes'] = array('#type' => 'table', '#header' => array('Name', 'Operations'), '#rows' => array(), '#empty' => $this->t('There are no configuration changes to import.'));
         $form['actions']['#access'] = FALSE;
         return $form;
     } elseif (!$storage_comparer->validateSiteUuid()) {
         drupal_set_message($this->t('The staged configuration cannot be imported, because it originates from a different site than this site. You can only synchronize configuration between cloned instances of this site.'), 'error');
         $form['actions']['#access'] = FALSE;
         return $form;
     } else {
         // Store the comparer for use in the submit.
         $form_state->set('storage_comparer', $storage_comparer);
     }
     // Add the AJAX library to the form for dialog support.
     $form['#attached']['library'][] = 'core/drupal.ajax';
     foreach ($storage_comparer->getAllCollectionNames() as $collection) {
         if ($collection != StorageInterface::DEFAULT_COLLECTION) {
             $form[$collection]['collection_heading'] = array('#type' => 'html_tag', '#tag' => 'h2', '#value' => $this->t('!collection configuration collection', array('!collection' => $collection)));
         }
         foreach ($storage_comparer->getChangelist(NULL, $collection) as $config_change_type => $config_names) {
             if (empty($config_names)) {
                 continue;
             }
             // @todo A table caption would be more appropriate, but does not have the
             //   visual importance of a heading.
             $form[$collection][$config_change_type]['heading'] = array('#type' => 'html_tag', '#tag' => 'h3');
             switch ($config_change_type) {
                 case 'create':
                     $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count new', '@count new');
                     break;
                 case 'update':
                     $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count changed', '@count changed');
                     break;
                 case 'delete':
                     $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count removed', '@count removed');
                     break;
                 case 'rename':
                     $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count renamed', '@count renamed');
                     break;
             }
             $form[$collection][$config_change_type]['list'] = array('#type' => 'table', '#header' => array('Name', 'Operations'));
             foreach ($config_names as $config_name) {
                 if ($config_change_type == 'rename') {
                     $names = $storage_comparer->extractRenameNames($config_name);
                     $route_options = array('source_name' => $names['old_name'], 'target_name' => $names['new_name']);
                     $config_name = $this->t('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name']));
                 } else {
                     $route_options = array('source_name' => $config_name);
                 }
                 if ($collection != StorageInterface::DEFAULT_COLLECTION) {
                     $route_name = 'config.diff_collection';
                     $route_options['collection'] = $collection;
                 } else {
                     $route_name = 'config.diff';
                 }
                 $links['view_diff'] = array('title' => $this->t('View differences'), 'url' => Url::fromRoute($route_name, $route_options), 'attributes' => array('class' => array('use-ajax'), 'data-accepts' => 'application/vnd.drupal-modal', 'data-dialog-options' => json_encode(array('width' => 700))));
                 $form[$collection][$config_change_type]['list']['#rows'][] = array('name' => $config_name, 'operations' => array('data' => array('#type' => 'operations', '#links' => $links)));
             }
         }
     }
     return $form;
 }
Esempio n. 10
0
 /**
  * Tests that a fixed set of modules can be installed and uninstalled.
  */
 public function testInstallUninstall()
 {
     // Get a list of modules to enable.
     $all_modules = system_rebuild_module_data();
     $all_modules = array_filter($all_modules, function ($module) {
         // Filter contrib, hidden, already enabled modules and modules in the
         // Testing package.
         if ($module->origin !== 'core' || !empty($module->info['hidden']) || $module->status == TRUE || $module->info['package'] == 'Testing') {
             return FALSE;
         }
         return TRUE;
     });
     // Install every module possible.
     \Drupal::service('module_installer')->install(array_keys($all_modules));
     $this->assertModules(array_keys($all_modules), TRUE);
     foreach ($all_modules as $module => $info) {
         $this->assertModuleConfig($module);
         $this->assertModuleTablesExist($module);
     }
     // Export active config to sync.
     $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
     system_list_reset();
     $this->resetAll();
     // Delete every field on the site so all modules can be uninstalled. For
     // example, if a comment field exists then module becomes required and can
     // not be uninstalled.
     $field_storages = \Drupal::entityManager()->getStorage('field_storage_config')->loadMultiple();
     \Drupal::entityManager()->getStorage('field_storage_config')->delete($field_storages);
     // Purge the data.
     field_purge_batch(1000);
     // Delete all terms.
     $terms = Term::loadMultiple();
     entity_delete_multiple('taxonomy_term', array_keys($terms));
     // Delete all filter formats.
     $filters = FilterFormat::loadMultiple();
     entity_delete_multiple('filter_format', array_keys($filters));
     // Delete any shortcuts so the shortcut module can be uninstalled.
     $shortcuts = Shortcut::loadMultiple();
     entity_delete_multiple('shortcut', array_keys($shortcuts));
     system_list_reset();
     $all_modules = system_rebuild_module_data();
     // Ensure that only core required modules and the install profile can not be uninstalled.
     $validation_reasons = \Drupal::service('module_installer')->validateUninstall(array_keys($all_modules));
     $this->assertEqual(['standard', 'system', 'user'], array_keys($validation_reasons));
     $modules_to_uninstall = array_filter($all_modules, function ($module) use($validation_reasons) {
         // Filter required and not enabled modules.
         if (!empty($module->info['required']) || $module->status == FALSE) {
             return FALSE;
         }
         return TRUE;
     });
     // Can not uninstall config and use admin/config/development/configuration!
     unset($modules_to_uninstall['config']);
     $this->assertTrue(isset($modules_to_uninstall['comment']), 'The comment module will be disabled');
     $this->assertTrue(isset($modules_to_uninstall['file']), 'The File module will be disabled');
     $this->assertTrue(isset($modules_to_uninstall['editor']), 'The Editor module will be disabled');
     // Uninstall all modules that can be uninstalled.
     \Drupal::service('module_installer')->uninstall(array_keys($modules_to_uninstall));
     $this->assertModules(array_keys($modules_to_uninstall), FALSE);
     foreach ($modules_to_uninstall as $module => $info) {
         $this->assertNoModuleConfig($module);
         $this->assertModuleTablesDoNotExist($module);
     }
     // Import the configuration thereby re-installing all the modules.
     $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all'));
     // Modules have been installed that have services.
     $this->rebuildContainer();
     // Check that there are no errors.
     $this->assertIdentical($this->configImporter()->getErrors(), array());
     // Check that all modules that were uninstalled are now reinstalled.
     $this->assertModules(array_keys($modules_to_uninstall), TRUE);
     foreach ($modules_to_uninstall as $module => $info) {
         $this->assertModuleConfig($module);
         $this->assertModuleTablesExist($module);
     }
     // Ensure that we have no configuration changes to import.
     $storage_comparer = new StorageComparer($this->container->get('config.storage.sync'), $this->container->get('config.storage'), $this->container->get('config.manager'));
     $this->assertIdentical($storage_comparer->createChangelist()->getChangelist(), $storage_comparer->getEmptyChangelist());
     // Now we have all configuration imported, test all of them for schema
     // conformance. Ensures all imported default configuration is valid when
     // all modules are enabled.
     $names = $this->container->get('config.storage')->listAll();
     /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
     $typed_config = $this->container->get('config.typed');
     foreach ($names as $name) {
         $config = $this->config($name);
         $this->assertConfigSchema($typed_config, $name, $config->get());
     }
 }
Esempio n. 11
0
 /**
  * Tests that a fixed set of modules can be installed and uninstalled.
  */
 public function testInstallUninstall()
 {
     // Get a list of modules to enable.
     $all_modules = system_rebuild_module_data();
     $all_modules = array_filter($all_modules, function ($module) {
         // Filter hidden, already enabled modules and modules in the Testing
         // package.
         if (!empty($module->info['hidden']) || $module->status == TRUE || $module->info['package'] == 'Testing') {
             return FALSE;
         }
         return TRUE;
     });
     // Install every module possible.
     \Drupal::moduleHandler()->install(array_keys($all_modules));
     $this->assertModules(array_keys($all_modules), TRUE);
     foreach ($all_modules as $module => $info) {
         $this->assertModuleConfig($module);
         $this->assertModuleTablesExist($module);
     }
     // Export active config to staging
     $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging'));
     system_list_reset();
     $this->resetAll();
     // Delete every field on the site so all modules can be uninstalled. For
     // example, if a comment field exists then module becomes required and can
     // not be uninstalled.
     $field_storages = \Drupal::entityManager()->getStorage('field_storage_config')->loadMultiple();
     \Drupal::entityManager()->getStorage('field_storage_config')->delete($field_storages);
     // Purge the data.
     field_purge_batch(1000);
     // Delete any forum terms so it can be uninstalled.
     $vid = \Drupal::config('forum.settings')->get('vocabulary');
     $terms = entity_load_multiple_by_properties('taxonomy_term', ['vid' => $vid]);
     foreach ($terms as $term) {
         $term->delete();
     }
     system_list_reset();
     $all_modules = system_rebuild_module_data();
     $modules_to_uninstall = array_filter($all_modules, function ($module) {
         // Filter required and not enabled modules.
         if (!empty($module->info['required']) || $module->status == FALSE) {
             return FALSE;
         }
         return TRUE;
     });
     // Can not uninstall config and use admin/config/development/configuration!
     unset($modules_to_uninstall['config']);
     $this->assertTrue(isset($modules_to_uninstall['comment']), 'The comment module will be disabled');
     // Uninstall all modules that can be uninstalled.
     \Drupal::moduleHandler()->uninstall(array_keys($modules_to_uninstall));
     $this->assertModules(array_keys($modules_to_uninstall), FALSE);
     foreach ($modules_to_uninstall as $module => $info) {
         $this->assertNoModuleConfig($module);
         $this->assertModuleTablesDoNotExist($module);
     }
     // Import the configuration thereby re-installing all the modules.
     $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all'));
     // Check that there are no errors.
     $this->assertIdentical($this->configImporter()->getErrors(), array());
     // Check that all modules that were uninstalled are now reinstalled.
     $this->assertModules(array_keys($modules_to_uninstall), TRUE);
     foreach ($modules_to_uninstall as $module => $info) {
         $this->assertModuleConfig($module);
         $this->assertModuleTablesExist($module);
     }
     // Ensure that we have no configuration changes to import.
     $storage_comparer = new StorageComparer($this->container->get('config.storage.staging'), $this->container->get('config.storage'), $this->container->get('config.manager'));
     $this->assertIdentical($storage_comparer->createChangelist()->getChangelist(), $storage_comparer->getEmptyChangelist());
     // Now we have all configuration imported, test all of them for schema
     // conformance. Ensures all imported default configuration is valid when
     // all modules are enabled.
     $names = $this->container->get('config.storage')->listAll();
     $factory = $this->container->get('config.factory');
     /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
     $typed_config = $this->container->get('config.typed');
     foreach ($names as $name) {
         $config = $factory->get($name);
         $this->assertConfigSchema($typed_config, $name, $config->get());
     }
 }
Esempio n. 12
0
 /**
  * {@inheritdoc}
  */
 public function validateForm(array &$form, FormStateInterface $form_state)
 {
     // The confirmation step needs no additional validation.
     if ($this->data) {
         return;
     }
     // Decode the submitted import.
     $data = Yaml::decode($form_state->getValue('import'));
     // Validate for config entities.
     if ($form_state->getValue('config_type') !== 'system.simple') {
         $definition = $this->entityManager->getDefinition($form_state->getValue('config_type'));
         $id_key = $definition->getKey('id');
         // If a custom entity ID is specified, override the value in the
         // configuration data being imported.
         if (!$form_state->isValueEmpty('custom_entity_id')) {
             $data[$id_key] = $form_state->getValue('custom_entity_id');
         }
         $entity_storage = $this->entityManager->getStorage($form_state->getValue('config_type'));
         // If an entity ID was not specified, set an error.
         if (!isset($data[$id_key])) {
             $form_state->setErrorByName('import', $this->t('Missing ID key "@id_key" for this @entity_type import.', array('@id_key' => $id_key, '@entity_type' => $definition->getLabel())));
             return;
         }
         $config_name = $definition->getConfigPrefix() . '.' . $data[$id_key];
         // If there is an existing entity, ensure matching ID and UUID.
         if ($entity = $entity_storage->load($data[$id_key])) {
             $this->configExists = $entity;
             if (!isset($data['uuid'])) {
                 $form_state->setErrorByName('import', $this->t('An entity with this machine name already exists but the import did not specify a UUID.'));
                 return;
             }
             if ($data['uuid'] !== $entity->uuid()) {
                 $form_state->setErrorByName('import', $this->t('An entity with this machine name already exists but the UUID does not match.'));
                 return;
             }
         } elseif (isset($data['uuid']) && $entity_storage->loadByProperties(array('uuid' => $data['uuid']))) {
             $form_state->setErrorByName('import', $this->t('An entity with this UUID already exists but the machine name does not match.'));
         }
     } else {
         $config_name = $form_state->getValue('config_name');
         $config = $this->config($config_name);
         $this->configExists = !$config->isNew() ? $config : FALSE;
     }
     // Use ConfigImporter validation.
     if (!$form_state->getErrors()) {
         $source_storage = new StorageReplaceDataWrapper($this->configStorage);
         $source_storage->replaceData($config_name, $data);
         $storage_comparer = new StorageComparer($source_storage, $this->configStorage, $this->configManager);
         if (!$storage_comparer->createChangelist()->hasChanges()) {
             $form_state->setErrorByName('import', $this->t('There are no changes to import.'));
         } else {
             $config_importer = new ConfigImporter($storage_comparer, $this->eventDispatcher, $this->configManager, $this->lock, $this->typedConfigManager, $this->moduleHandler, $this->moduleInstaller, $this->themeHandler, $this->getStringTranslation());
             try {
                 $config_importer->validate();
                 $form_state->set('config_importer', $config_importer);
             } catch (ConfigImporterException $e) {
                 // There are validation errors.
                 $item_list = ['#theme' => 'item_list', '#items' => $config_importer->getErrors(), '#title' => $this->t('The configuration cannot be imported because it failed validation for the following reasons:')];
                 $form_state->setErrorByName('import', $this->renderer->render($item_list));
             }
         }
     }
     // Store the decoded version of the submitted import.
     $form_state->setValueForElement($form['import'], $data);
 }
 /**
  * Constructs the Configuration Sync storage comparer.
  *
  * @param \Drupal\Core\Config\StorageInterface $source_storage
  *   Storage object used to read configuration.
  * @param \Drupal\Core\Config\StorageInterface $target_storage
  *   Storage object used to write configuration.
  * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
  *   The configuration manager.
  * @param \Drupal\config_update\ConfigDiffInterface $config_diff
  *   The config differ.
  */
 public function __construct(StorageInterface $source_storage, StorageInterface $target_storage, ConfigManagerInterface $config_manager, ConfigDiffInterface $config_diff)
 {
     parent::__construct($source_storage, $target_storage, $config_manager);
     $this->configDiff = $config_diff;
 }