diff --git a/core/modules/config/config.links.task.yml b/core/modules/config/config.links.task.yml index 5a894f0..9e9383b 100644 --- a/core/modules/config/config.links.task.yml +++ b/core/modules/config/config.links.task.yml @@ -3,32 +3,32 @@ config.sync: base_route: config.sync title: 'Synchronize' -config.full: +config.import: route_name: config.import_full - title: 'Full Import/Export' + title: 'Import' base_route: config.sync -config.single: - route_name: config.import_single - title: 'Single Import/Export' +config.export: + route_name: config.export_full + title: 'Export' base_route: config.sync config.export_full: route_name: config.export_full - title: Export - parent_id: config.full + title: Full + parent_id: config.export config.import_full: route_name: config.import_full - title: Import - parent_id: config.full + title: Full + parent_id: config.import config.export_single: route_name: config.export_single - title: Export - parent_id: config.single + title: Single + parent_id: config.export config.import_single: route_name: config.import_single - title: Import - parent_id: config.single + title: Single + parent_id: config.import diff --git a/core/modules/config/config.routing.yml b/core/modules/config/config.routing.yml index 8eebac3..8c806e8 100644 --- a/core/modules/config/config.routing.yml +++ b/core/modules/config/config.routing.yml @@ -6,6 +6,14 @@ config.sync: requirements: _permission: 'synchronize configuration' +config.sync_confirm: + path: '/admin/config/development/configuration/sync/confirm' + defaults: + _form: 'Drupal\config\Form\ConfigSyncConfirmForm' + _title: 'Confirm configuration synchronization' + requirements: + _permission: 'synchronize configuration' + config.diff: path: '/admin/config/development/configuration/sync/diff/{source_name}/{target_name}' defaults: diff --git a/core/modules/config/src/Form/ConfigImportForm.php b/core/modules/config/src/Form/ConfigImportForm.php index 7b29e3f..2ee1917 100644 --- a/core/modules/config/src/Form/ConfigImportForm.php +++ b/core/modules/config/src/Form/ConfigImportForm.php @@ -9,8 +9,10 @@ use Drupal\Core\Archiver\ArchiveTar; use Drupal\Core\Config\StorageInterface; +use Drupal\Core\Config\ConfigManagerInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\RendererInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -26,13 +28,53 @@ class ConfigImportForm extends FormBase { protected $configStorage; /** + * The staging configuration object. + * + * @var \Drupal\Core\Config\StorageInterface + */ + protected $stagingStorage; + + /** + * The active configuration object. + * + * @var \Drupal\Core\Config\StorageInterface + */ + protected $activeStorage; + + /** + * The snapshot configuration object. + * + * @var \Drupal\Core\Config\StorageInterface + */ + protected $snapshotStorage; + + /** + * The configuration manager. + * + * @var \Drupal\Core\Config\ConfigManagerInterface; + */ + protected $configManager; + + /** + * The renderer. + * + * @var \Drupal\Core\Render\RendererInterface + */ + protected $renderer; + + /** * Constructs a new ConfigImportForm. * * @param \Drupal\Core\Config\StorageInterface $config_storage * The configuration storage. */ - public function __construct(StorageInterface $config_storage) { + public function __construct(StorageInterface $staging_storage, StorageInterface $active_storage, StorageInterface $snapshot_storage, StorageInterface $config_storage, ConfigManagerInterface $config_manager, RendererInterface $renderer) { + $this->stagingStorage = $staging_storage; + $this->activeStorage = $active_storage; + $this->snapshotStorage = $snapshot_storage; $this->configStorage = $config_storage; + $this->configManager = $config_manager; + $this->renderer = $renderer; } /** @@ -40,7 +82,12 @@ public function __construct(StorageInterface $config_storage) { */ public static function create(ContainerInterface $container) { return new static( - $container->get('config.storage.staging') + $container->get('config.storage.staging'), + $container->get('config.storage'), + $container->get('config.storage.snapshot'), + $container->get('config.storage.staging'), + $container->get('config.manager'), + $container->get('renderer') ); } @@ -65,6 +112,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#type' => 'submit', '#value' => $this->t('Upload'), ); + return $form; } diff --git a/core/modules/config/src/Form/ConfigSync.php b/core/modules/config/src/Form/ConfigSync.php index 7f240e3..be4e21a 100644 --- a/core/modules/config/src/Form/ConfigSync.php +++ b/core/modules/config/src/Form/ConfigSync.php @@ -19,6 +19,7 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface; use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\Config\StorageComparer; use Drupal\Core\Render\RendererInterface; @@ -109,6 +110,13 @@ class ConfigSync extends FormBase { protected $renderer; /** + * The key value storer. + * + * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface; + */ + protected $keyValueExpirable; + + /** * Constructs the object. * * @param \Drupal\Core\Config\StorageInterface $staging_storage @@ -119,7 +127,8 @@ class ConfigSync extends FormBase { * The snapshot storage. * @param \Drupal\Core\Lock\LockBackendInterface $lock * The lock object. - * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface + * $event_dispatcher * Event dispatcher. * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager * Configuration manager. @@ -131,10 +140,10 @@ class ConfigSync extends FormBase { * The module installer. * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler * The theme handler. - * @param \Drupal\Core\Render\RendererInterface + * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer. */ - public function __construct(StorageInterface $staging_storage, StorageInterface $active_storage, StorageInterface $snapshot_storage, LockBackendInterface $lock, EventDispatcherInterface $event_dispatcher, ConfigManagerInterface $config_manager, TypedConfigManagerInterface $typed_config, ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, ThemeHandlerInterface $theme_handler, RendererInterface $renderer) { + public function __construct(StorageInterface $staging_storage, StorageInterface $active_storage, StorageInterface $snapshot_storage, LockBackendInterface $lock, EventDispatcherInterface $event_dispatcher, ConfigManagerInterface $config_manager, TypedConfigManagerInterface $typed_config, ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, ThemeHandlerInterface $theme_handler, RendererInterface $renderer, KeyValueStoreExpirableInterface $key_value_expirable) { $this->stagingStorage = $staging_storage; $this->activeStorage = $active_storage; $this->snapshotStorage = $snapshot_storage; @@ -146,6 +155,7 @@ public function __construct(StorageInterface $staging_storage, StorageInterface $this->moduleInstaller = $module_installer; $this->themeHandler = $theme_handler; $this->renderer = $renderer; + $this->keyValueExpirable = $key_value_expirable; } /** @@ -163,7 +173,8 @@ public static function create(ContainerInterface $container) { $container->get('module_handler'), $container->get('module_installer'), $container->get('theme_handler'), - $container->get('renderer') + $container->get('renderer'), + $container->get('keyvalue.expirable')->get('config_import') ); } @@ -245,8 +256,8 @@ public function buildForm(array $form, FormStateInterface $form_state) { continue; } - // @todo A table caption would be more appropriate, but does not have the - // visual importance of a heading. + // @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', @@ -296,7 +307,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { 'class' => array('use-ajax'), 'data-dialog-type' => 'modal', 'data-dialog-options' => json_encode(array( - 'width' => 700 + 'width' => 700, )), ), ); @@ -319,46 +330,11 @@ public function buildForm(array $form, FormStateInterface $form_state) { * {@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->moduleInstaller, - $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)); - } + $account = $this->currentUser()->id(); + $this->keyValueExpirable->setWithExpire($account, $form_state->get('storage_comparer'), 60); - batch_set($batch); - } - catch (ConfigImporterException $e) { - // There are validation errors. - drupal_set_message($this->t('The configuration cannot be imported because it failed validation for the following reasons:'), 'error'); - foreach ($config_importer->getErrors() as $message) { - drupal_set_message($message, 'error'); - } - } - } + // Redirect to the confirmation form. + $form_state->setRedirect('config.sync_confirm'); } /** diff --git a/core/modules/config/src/Form/ConfigSyncConfirmForm.php b/core/modules/config/src/Form/ConfigSyncConfirmForm.php new file mode 100644 index 0000000..735b8ce --- /dev/null +++ b/core/modules/config/src/Form/ConfigSyncConfirmForm.php @@ -0,0 +1,266 @@ +eventDispatcher = $event_dispatcher; + $this->configManager = $config_manager; + $this->lock = $lock; + $this->typedConfigManager = $typed_config_manager; + $this->moduleHandler = $module_handler; + $this->moduleInstaller = $module_installer; + $this->themeHandler = $theme_handler; + $this->keyValueExpirable = $key_value_expirable; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('event_dispatcher'), + $container->get('config.manager'), + $container->get('lock.persistent'), + $container->get('config.typed'), + $container->get('module_handler'), + $container->get('module_installer'), + $container->get('theme_handler'), + $container->get('keyvalue.expirable')->get('config_import') + ); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $account = $this->currentUser()->id(); + $this->storageComparer = $this->keyValueExpirable->get($account); + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $config_importer = new ConfigImporter( + $this->storageComparer, + $this->eventDispatcher, + $this->configManager, + $this->lock, + $this->typedConfigManager, + $this->moduleHandler, + $this->moduleInstaller, + $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); + $form_state->setRedirect('config.sync'); + } + catch (ConfigImporterException $e) { + // There are validation errors. + drupal_set_message($this->t('The configuration cannot be imported because it failed validation for the following reasons:'), 'error'); + foreach ($config_importer->getErrors() as $message) { + drupal_set_message($message, 'error'); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return t('Confirm configuration import'); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Import'); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl() { + return new Url('config.sync'); + } + + /** + * Processes the config import batch and persists the importer. + * + * @param \Drupal\Core\Config\ConfigImporter $config_importer + * The batch config importer object to persist. + * @param string $sync_step + * The synchronization step to do. + * @param array $context + * The batch context. + */ + public static function processBatch(ConfigImporter $config_importer, $sync_step, &$context) { + if (!isset($context['sandbox']['config_importer'])) { + $context['sandbox']['config_importer'] = $config_importer; + } + + $config_importer = $context['sandbox']['config_importer']; + $config_importer->doSyncStep($sync_step, $context); + if ($errors = $config_importer->getErrors()) { + if (!isset($context['results']['errors'])) { + $context['results']['errors'] = array(); + } + $context['results']['errors'] += $errors; + } + } + + /** + * Finish batch. + * + * This function is a static function to avoid serializing the ConfigSync + * object unnecessarily. + */ + public static function finishBatch($success, $results, $operations) { + if ($success) { + if (!empty($results['errors'])) { + foreach ($results['errors'] as $error) { + drupal_set_message($error, 'error'); + \Drupal::logger('config_sync')->error($error); + } + drupal_set_message(\Drupal::translation()->translate('The configuration was imported with errors.'), 'warning'); + } + else { + drupal_set_message(\Drupal::translation()->translate('The configuration was imported successfully.')); + } + } + else { + // An error occurred. + // $operations contains the operations that remained unprocessed. + $error_operation = reset($operations); + $message = \Drupal::translation()->translate('An error occurred while processing %error_operation with arguments: @arguments', array( + '%error_operation' => $error_operation[0], + '@arguments' => print_r($error_operation[1], TRUE), + )); + drupal_set_message($message, 'error'); + } + } +} diff --git a/core/modules/config/src/Tests/ConfigExportImportUITest.php b/core/modules/config/src/Tests/ConfigExportImportUITest.php index 6a63df7..0878ede 100644 --- a/core/modules/config/src/Tests/ConfigExportImportUITest.php +++ b/core/modules/config/src/Tests/ConfigExportImportUITest.php @@ -91,7 +91,7 @@ protected function setUp() { */ public function testExportImport() { // After installation there is no snapshot and nothing to import. - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertNoText(t('Warning message')); $this->assertText(t('There are no configuration changes to import.')); @@ -173,6 +173,11 @@ public function testExportImport() { $this->assertText($this->contentType->label()); $this->drupalPostForm(NULL, array(), 'Import all'); + + // We now have to confirm the import. + $this->assertText(t('This action cannot be undone.')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), 'Import'); + // After importing the snapshot has been updated an there are no warnings. $this->assertNoText(t('Warning message')); $this->assertText(t('There are no configuration changes to import.')); @@ -185,13 +190,13 @@ public function testExportImport() { $this->config('system.site') ->set('slogan', $this->originalSlogan) ->save(); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertText(t('Warning message')); $this->assertText('The following items in your active configuration have changes since the last import that may be lost on the next import. system.site'); // Remove everything from staging. The warning about differences between the // active and snapshot should no longer exist. \Drupal::service('config.storage.staging')->deleteAll(); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertNoText(t('Warning message')); $this->assertNoText('The following items in your active configuration have changes since the last import that may be lost on the next import. system.site'); $this->assertText(t('There are no configuration changes to import.')); @@ -203,7 +208,7 @@ public function testExportImport() { $data['slogan'] = 'in the face'; $this->copyConfig($this->container->get('config.storage'), $staging); $staging->write('system.site', $data); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertText(t('Warning message')); $this->assertText('The following items in your active configuration have changes since the last import that may be lost on the next import. system.site'); } @@ -271,7 +276,7 @@ public function testExportImportCollections() { $this->drupalPostForm('admin/config/development/configuration/full/import', array('files[import_tarball]' => $filename), 'Upload'); // Verify that there are configuration differences to import. - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertNoText(t('There are no configuration changes to import.')); $this->assertText(t('!collection configuration collection', array('!collection' => 'collection.test1'))); $this->assertText(t('!collection configuration collection', array('!collection' => 'collection.test2'))); @@ -289,6 +294,11 @@ public function testExportImportCollections() { $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_delete'); $this->drupalPostForm(NULL, array(), 'Import all'); + + // We now have to confirm the import. + $this->assertText(t('This action cannot be undone.')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), 'Import'); + $this->assertText(t('There are no configuration changes to import.')); // Test data in collections. diff --git a/core/modules/config/src/Tests/ConfigImportAllTest.php b/core/modules/config/src/Tests/ConfigImportAllTest.php index 6e1aaea..dd0575b 100644 --- a/core/modules/config/src/Tests/ConfigImportAllTest.php +++ b/core/modules/config/src/Tests/ConfigImportAllTest.php @@ -23,7 +23,7 @@ class ConfigImportAllTest extends ModuleTestBase { use SchemaCheckTestTrait; /** - * A user with the 'synchronize configuration' permission. + * A user with the 'Import configuration' permission. * * @var \Drupal\user\UserInterface */ @@ -41,7 +41,7 @@ class ConfigImportAllTest extends ModuleTestBase { protected function setUp() { parent::setUp(); - $this->webUser = $this->drupalCreateUser(array('synchronize configuration')); + $this->webUser = $this->drupalCreateUser(array('import configuration')); $this->drupalLogin($this->webUser); } @@ -129,7 +129,8 @@ public function testInstallUninstall() { } // Import the configuration thereby re-installing all the modules. - $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), 'Import'); // Modules have been installed that have services. $this->rebuildContainer(); diff --git a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php index 64b2d5d..d294239 100644 --- a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php +++ b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php @@ -31,7 +31,7 @@ class ConfigImportInstallProfileTest extends WebTestBase { public static $modules = array('config'); /** - * A user with the 'synchronize configuration' permission. + * A user with the 'import configuration' permission. * * @var \Drupal\user\UserInterface */ @@ -40,7 +40,7 @@ class ConfigImportInstallProfileTest extends WebTestBase { protected function setUp() { parent::setUp(); - $this->webUser = $this->drupalCreateUser(array('synchronize configuration')); + $this->webUser = $this->drupalCreateUser(array('import configuration')); $this->drupalLogin($this->webUser); $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging')); } @@ -59,7 +59,8 @@ public function testInstallProfileValidation() { unset($core['module']['testing_config_import']); $staging->write('core.extension', $core); - $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:'); $this->assertText('Unable to uninstall the Testing config import profile since it is the install profile.'); @@ -73,7 +74,8 @@ public function testInstallProfileValidation() { $theme = $staging->read('system.theme'); $theme['default'] = 'classy'; $staging->write('system.theme', $theme); - $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $this->assertText('The configuration was imported successfully.'); $this->rebuildContainer(); $this->assertFalse(\Drupal::moduleHandler()->moduleExists('syslog'), 'The syslog module has been uninstalled.'); diff --git a/core/modules/config/src/Tests/ConfigImportUITest.php b/core/modules/config/src/Tests/ConfigImportUITest.php index dd00edf..219edfa 100644 --- a/core/modules/config/src/Tests/ConfigImportUITest.php +++ b/core/modules/config/src/Tests/ConfigImportUITest.php @@ -26,7 +26,7 @@ class ConfigImportUITest extends WebTestBase { public static $modules = array('config', 'config_test', 'config_import_test', 'text', 'options'); /** - * A user with the 'synchronize configuration' permission. + * A user with the 'Import configuration' permission. * * @var \Drupal\user\UserInterface */ @@ -35,7 +35,7 @@ class ConfigImportUITest extends WebTestBase { protected function setUp() { parent::setUp(); - $this->webUser = $this->drupalCreateUser(array('synchronize configuration')); + $this->webUser = $this->drupalCreateUser(array('import configuration')); $this->drupalLogin($this->webUser); $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.staging')); } @@ -49,7 +49,7 @@ function testImport() { /** @var \Drupal\Core\Config\StorageInterface $staging */ $staging = $this->container->get('config.storage.staging'); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertText('There are no configuration changes to import.'); $this->assertNoFieldById('edit-submit', t('Import all')); @@ -113,23 +113,24 @@ function testImport() { \Drupal::state()->set('ConfigImportUITest.core.extension.modules_uninstalled', array()); // Verify that both appear as ready to import. - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertRaw('' . $name); $this->assertRaw('' . $dynamic_name); $this->assertRaw('core.extension'); $this->assertRaw('system.theme'); $this->assertRaw('action.settings'); - $this->assertFieldById('edit-submit', t('Import all')); + $this->assertFieldById('edit-import', t('Import all')); // Import and verify that both do not appear anymore. $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), 'Import'); $this->assertNoRaw('' . $name); $this->assertNoRaw('' . $dynamic_name); $this->assertNoRaw('core.extension'); $this->assertNoRaw('system.theme'); $this->assertNoRaw('action.settings'); - $this->assertNoFieldById('edit-submit', t('Import all')); + $this->assertNoFieldById('edit-import', t('Import all')); // Verify that there are no further changes to import. $this->assertText(t('There are no configuration changes to import.')); @@ -188,13 +189,14 @@ function testImport() { \Drupal::state()->set('ConfigImportUITest.core.extension.modules_uninstalled', array()); // Verify that both appear as ready to import. - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertRaw('core.extension'); $this->assertRaw('system.theme'); $this->assertRaw('action.settings'); // Import and verify that both do not appear anymore. $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), 'Import'); $this->assertNoRaw('core.extension'); $this->assertNoRaw('system.theme'); $this->assertNoRaw('action.settings'); @@ -231,7 +233,7 @@ function testImportLock() { $this->prepareSiteNameUpdate($new_site_name); // Verify that there are configuration differences to import. - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertNoText(t('There are no configuration changes to import.')); // Acquire a fake-lock on the import mechanism. @@ -240,6 +242,7 @@ function testImportLock() { // Attempt to import configuration and verify that an error message appears. $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $this->assertText(t('Another request may be synchronizing configuration already.')); // Release the lock, just to keep testing sane. @@ -261,7 +264,7 @@ function testImportSiteUuidValidation() { $staging->write('system.site', $config_data); // Verify that there are configuration differences to import. - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertText(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.')); $this->assertNoFieldById('edit-submit', t('Import all')); } @@ -321,9 +324,10 @@ public function testImportValidation() { $new_site_name = 'Config import test ' . $this->randomString(); $this->prepareSiteNameUpdate($new_site_name); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertNoText(t('There are no configuration changes to import.')); $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm(NULL, array(), t('Import')); // Verify that the validation messages appear. $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:'); @@ -341,11 +345,12 @@ public function testConfigUninstallConfigException() { unset($core_extension['module']['config']); $staging->write('core.extension', $core_extension); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertText('core.extension'); // Import and verify that both do not appear anymore. $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $this->assertText('Can not uninstall the Configuration module as part of a configuration synchronization through the user interface.'); } @@ -398,11 +403,12 @@ function testImportErrorLog() { ); $staging->write($name_secondary, $values_secondary); // Verify that there are configuration differences to import. - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertNoText(t('There are no configuration changes to import.')); // Attempt to import configuration and verify that an error message appears. $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $this->assertText(SafeMarkup::format('Deleted and replaced configuration entity "@name"', array('@name' => $name_secondary))); $this->assertText(t('The configuration was imported with errors.')); $this->assertNoText(t('The configuration was imported successfully.')); @@ -420,7 +426,7 @@ public function testEntityBundleDelete() { $node_type = $this->drupalCreateContentType(); $node = $this->drupalCreateNode(array('type' => $node_type->id())); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); // The node type, body field and entity displays will be scheduled for // removal. $this->assertText(format_string('node.type.@type', array('@type' => $node_type->id()))); @@ -433,17 +439,13 @@ public function testEntityBundleDelete() { // and the node type, body field and entity displays are still scheduled for // removal. $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $validation_message = t('Entities exist of type %entity_type and %bundle_label %bundle. These entities need to be deleted before importing.', array('%entity_type' => $node->getEntityType()->getLabel(), '%bundle_label' => $node->getEntityType()->getBundleLabel(), '%bundle' => $node_type->label())); $this->assertRaw($validation_message); - $this->assertText(format_string('node.type.@type', array('@type' => $node_type->id()))); - $this->assertText(format_string('field.field.node.@type.body', array('@type' => $node_type->id()))); - $this->assertText(format_string('core.entity_view_display.node.@type.teaser', array('@type' => $node_type->id()))); - $this->assertText(format_string('core.entity_view_display.node.@type.default', array('@type' => $node_type->id()))); - $this->assertText(format_string('core.entity_form_display.node.@type.default', array('@type' => $node_type->id()))); // Delete the node and try to import again. $node->delete(); - $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm(NULL, array(), t('Import')); $this->assertNoRaw($validation_message); $this->assertText(t('There are no configuration changes to import.')); $this->assertNoText(format_string('node.type.@type', array('@type' => $node_type->id()))); @@ -480,7 +482,8 @@ public function testExtensionValidation() { $core['theme']['does_not_exist'] = 0; $staging->write('core.extension', $core); - $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:'); $this->assertText('Unable to uninstall the Text module since the Node module is installed.'); $this->assertText('Unable to uninstall the Classy theme since the Bartik theme is installed.'); diff --git a/core/modules/config/tests/src/Unit/Menu/ConfigLocalTasksTest.php b/core/modules/config/tests/src/Unit/Menu/ConfigLocalTasksTest.php index 1da4148..670191b 100644 --- a/core/modules/config/tests/src/Unit/Menu/ConfigLocalTasksTest.php +++ b/core/modules/config/tests/src/Unit/Menu/ConfigLocalTasksTest.php @@ -35,11 +35,10 @@ public function testConfigAdminLocalTasks($route, $expected) { */ public function getConfigAdminRoutes() { return array( - array('config.sync', array(array('config.sync', 'config.full', 'config.single'))), - array('config.export_full', array(array('config.sync', 'config.full', 'config.single'), array('config.export_full', 'config.import_full'))), - array('config.import_full', array(array('config.sync', 'config.full', 'config.single'), array('config.export_full', 'config.import_full'))), - array('config.export_single', array(array('config.sync', 'config.full', 'config.single'), array('config.export_single', 'config.import_single'))), - array('config.import_single', array(array('config.sync', 'config.full', 'config.single'), array('config.export_single', 'config.import_single'))), + array('config.import_full', array(array('config.import', 'config.export'), array('config.import_full', 'config.import_single'))), + array('config.import_single', array(array('config.import', 'config.export'), array('config.import_full', 'config.import_single'))), + array('config.export_full', array(array('config.import', 'config.export'), array('config.export_full', 'config.export_single'))), + array('config.export_single', array(array('config.import', 'config.export'), array('config.export_full', 'config.export_single'))), ); } diff --git a/core/modules/field/field.module b/core/modules/field/field.module index d09049e..b39170c 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -281,7 +281,7 @@ function field_config_import_steps_alter(&$sync_steps, ConfigImporter $config_im * * @see \Drupal\field\ConfigImporterFieldPurger */ -function field_form_config_admin_import_form_alter(&$form, FormStateInterface $form_state) { +function field_form_config_import_form_alter(&$form, FormStateInterface $form_state) { // Only display the message when there is a storage comparer available and the // form is not submitted. $user_input = $form_state->getUserInput(); diff --git a/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php b/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php index de793dd..f400fd4 100644 --- a/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php +++ b/core/modules/field/src/Tests/FieldImportDeleteUninstallUiTest.php @@ -28,7 +28,7 @@ class FieldImportDeleteUninstallUiTest extends FieldTestBase { protected function setUp() { parent::setUp(); - $this->drupalLogin($this->drupalCreateUser(array('synchronize configuration'))); + $this->drupalLogin($this->drupalCreateUser(array('import configuration'))); } /** @@ -90,7 +90,7 @@ public function testImportDeleteUninstall() { // Stage the field deletion $staging->delete('field.storage.entity_test.field_tel'); $staging->delete('field.field.entity_test.entity_test.field_tel'); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); // Test that the message for one field being purged during a configuration // synchronization is correct. $this->assertText('This synchronization will delete data from the field entity_test.field_tel.'); @@ -100,12 +100,13 @@ public function testImportDeleteUninstall() { unset($core_extension['module']['datetime']); $staging->write('core.extension', $core_extension); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->assertText('This synchronization will delete data from the fields: entity_test.field_tel, entity_test.field_date.'); // This will purge all the data, delete the field and uninstall the // Telephone and Text modules. $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm(NULL, array(), t('Import')); $this->assertNoText('Field data will be deleted by this synchronization.'); $this->rebuildContainer(); $this->assertFalse(\Drupal::moduleHandler()->moduleExists('telephone')); diff --git a/core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php b/core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php index af29bce..f8e1d2b 100644 --- a/core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php +++ b/core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php @@ -39,7 +39,7 @@ class NodeTypeRenameConfigImportTest extends WebTestBase { */ protected function setUp() { parent::setUp(); - $this->webUser = $this->drupalCreateUser(array('synchronize configuration')); + $this->webUser = $this->drupalCreateUser(array('import configuration')); $this->drupalLogin($this->webUser); } @@ -101,7 +101,7 @@ public function testConfigurationRename() { $renames = $this->configImporter()->getUnprocessedConfiguration('rename'); $this->assertIdentical($expected, $renames); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); foreach ($expected as $rename) { $names = $this->configImporter()->getStorageComparer()->extractRenameNames($rename); $this->assertText(SafeMarkup::format('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name']))); @@ -130,7 +130,8 @@ public function testConfigurationRename() { } // Run the import. - $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import', array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $this->assertText(t('There are no configuration changes to import.')); $this->assertFalse(NodeType::load($active_type), 'The content no longer exists with the old name.'); diff --git a/core/modules/options/src/Tests/OptionsFloatFieldImportTest.php b/core/modules/options/src/Tests/OptionsFloatFieldImportTest.php index 5be5840..9d859b2 100644 --- a/core/modules/options/src/Tests/OptionsFloatFieldImportTest.php +++ b/core/modules/options/src/Tests/OptionsFloatFieldImportTest.php @@ -29,7 +29,7 @@ protected function setUp() { parent::setUp(); // Create test user. - $admin_user = $this->drupalCreateUser(array('synchronize configuration', 'access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'bypass node access', 'administer node fields', 'administer node display')); + $admin_user = $this->drupalCreateUser(array('import configuration', 'access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'bypass node access', 'administer node fields', 'administer node display')); $this->drupalLogin($admin_user); } @@ -59,8 +59,9 @@ public function testImport() { // Import configuration with dots in the allowed values key names. This // tests \Drupal\Core\Config\Entity\ConfigEntityStorage::importUpdate(). - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $field_storage = FieldStorageConfig::loadByName('node', $field_name); $this->assertIdentical($field_storage->getSetting('allowed_values'), $array = array('0' => 'Zero', '0.5' => 'Point five')); @@ -68,8 +69,9 @@ public function testImport() { // \Drupal\Core\Config\Entity\ConfigEntityStorage::importCreate(). FieldConfig::loadByName('node', $type, $field_name)->delete(); - $this->drupalGet('admin/config/development/configuration'); + $this->drupalGet('admin/config/development/configuration/full/import'); $this->drupalPostForm(NULL, array(), t('Import all')); + $this->drupalPostForm('admin/config/development/configuration/full/import/confirm', array(), t('Import')); $field_storage = FieldStorageConfig::loadByName('node', $field_name); $this->assertIdentical($field_storage->getSetting('allowed_values'), $array = array('0' => 'Zero', '0.5' => 'Point five')); } diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml index ecb1c43..f2bbae0 100644 --- a/sites/default/default.services.yml +++ b/sites/default/default.services.yml @@ -51,7 +51,7 @@ parameters: # changes (see auto_reload below). # # For more information about debugging Twig templates, see - # https://www.drupal.org/node/1906392. + # http://drupal.org/node/1906392. # # Not recommended in production environments # @default false diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 9ad5cae..cbef15b 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -22,7 +22,7 @@ * 'sites/default' will be used. * * For example, for a fictitious site installed at - * https://www.drupal.org:8080/mysite/test/, the 'settings.php' file is searched + * http://www.drupal.org:8080/mysite/test/, the 'settings.php' file is searched * for in the following directories: * * - sites/8080.www.drupal.org.mysite.test @@ -44,7 +44,7 @@ * * Note that if you are installing on a non-standard port number, prefix the * hostname with that number. For example, - * https://www.drupal.org:8080/mysite/test/ could be loaded from + * http://www.drupal.org:8080/mysite/test/ could be loaded from * sites/8080.www.drupal.org.mysite.test/. * * @see example.sites.php @@ -440,7 +440,7 @@ * the code directly via SSH or FTP themselves. This setting completely * disables all functionality related to these authorized file operations. * - * @see https://www.drupal.org/node/244924 + * @see http://drupal.org/node/244924 * * Remove the leading hash signs to disable. */ @@ -473,8 +473,8 @@ * Note: Caches need to be cleared when this value is changed to make the * private:// stream wrapper available to the system. * - * See https://www.drupal.org/documentation/modules/file for more information - * about securing private files. + * See http://drupal.org/documentation/modules/file for more information about + * securing private files. */ # $settings['file_private_path'] = '';