diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php index 2d8e4d52c01230fb0ddcf7140d767ca6f888aef9..da188315ebaa87c3dc4547b1501c51658ce526e9 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -123,10 +123,14 @@ public function installDefaultConfig($type, $name) { $collection_info = $this->configManager->getConfigCollectionInfo(); foreach ($collection_info->getCollectionNames() as $collection) { $config_to_create = $this->getConfigToCreate($storage, $collection, $prefix, $profile_storages); - // If we're installing a profile ensure configuration that is overriding - // is excluded. if ($name == $this->drupalGetProfile()) { - $existing_configuration = $this->getActiveStorages($collection)->listAll(); + // If we're installing a profile ensure simple configuration that + // already exists is excluded as it will have already been written. + // This means that if the configuration is changed by something else + // during the install it will not be overwritten again. + $existing_configuration = array_filter($this->getActiveStorages($collection)->listAll(), function ($config_name) { + return !$this->configManager->getEntityTypeIdByName($config_name); + }); $config_to_create = array_diff_key($config_to_create, array_flip($existing_configuration)); } if (!empty($config_to_create)) { @@ -266,12 +270,35 @@ protected function getConfigToCreate(StorageInterface $storage, $collection, $pr } $data = $storage->readMultiple($storage->listAll($prefix)); - // Check to see if the corresponding override storage has any overrides. + // Check to see if configuration provided by the install profile has any + // overrides. foreach ($profile_storages as $profile_storage) { if ($profile_storage->getCollectionName() != $collection) { $profile_storage = $profile_storage->createCollection($collection); } - $data = $profile_storage->readMultiple(array_keys($data)) + $data; + $profile_overrides = $profile_storage->readMultiple(array_keys($data)); + if (InstallerKernel::installationAttempted()) { + // During installation overrides of simple configuration are applied + // immediately. Configuration entities that are overridden will be + // updated when the profile is installed. This allows install profiles + // to provide configuration entity overrides that have dependencies that + // cannot be met when the module provided configuration entity is + // created. + foreach ($profile_overrides as $name => $override_data) { + // The only way to determine if they are configuration entities is the + // presence of a dependencies key. + if (!isset($override_data['dependencies'])) { + $data[$name] = $override_data; + } + } + } + else { + // Allow install profiles to provide overridden configuration for new + // extensions that are being enabled after Drupal has already been + // installed. This allows profiles to ship new extensions in version + // updates without requiring additional code to apply the overrides. + $data = $profile_overrides + $data; + } } return $data; } diff --git a/core/modules/config/tests/src/Functional/ConfigInstallProfileOverrideTest.php b/core/modules/config/tests/src/Functional/ConfigInstallProfileOverrideTest.php index cb085b53439b9898bb352d6cf39cd14ef2f2f1a4..3a151b574dd64f5b048dc5b1a76f20ac26426149 100644 --- a/core/modules/config/tests/src/Functional/ConfigInstallProfileOverrideTest.php +++ b/core/modules/config/tests/src/Functional/ConfigInstallProfileOverrideTest.php @@ -3,11 +3,13 @@ namespace Drupal\Tests\config\Functional; use Drupal\Component\Utility\Crypt; +use Drupal\Component\Uuid\Uuid; use Drupal\Core\Config\InstallStorage; use Drupal\Tests\BrowserTestBase; use Drupal\Core\Config\FileStorage; use Drupal\system\Entity\Action; use Drupal\tour\Entity\Tour; +use Drupal\user\Entity\Role; /** * Tests installation and removal of configuration objects in install, disable @@ -61,6 +63,16 @@ public function testInstallProfileConfigOverwrite() { $config = $this->config($config_name); $this->assertIdentical($config->get(), $expected_profile_data); + $config = $this->config('system.site'); + // Verify the system.site config has a valid UUID. + $site_uuid = $config->get('uuid'); + $this->assertTrue(Uuid::isValid($site_uuid) && strlen($site_uuid) > 0, "Site UUID '$site_uuid' is valid"); + // Verify the profile overrides have been used. + $this->assertEquals(91, $config->get('weight_select_max')); + // Ensure the site configure form is used. + $this->assertEquals('Drupal', $config->get('name')); + $this->assertEquals('simpletest@example.com', $config->get('mail')); + // Ensure that the configuration entity has the expected dependencies and // overrides. $action = Action::load('user_block_user_action'); @@ -117,6 +129,10 @@ public function testInstallProfileConfigOverwrite() { $this->rebuildContainer(); $config_test_storage = \Drupal::entityTypeManager()->getStorage('config_test'); $this->assertNull($config_test_storage->load('completely_new')); + + // Ensure the authenticated role has the access tour permission. + $role = Role::load(Role::AUTHENTICATED_ID); + $this->assertTrue($role->hasPermission('access tour'), 'The Authenticated role has the "access tour" permission.'); } } diff --git a/core/modules/config/tests/src/Functional/ConfigInstallProfileUnmetDependenciesTest.php b/core/modules/config/tests/src/Functional/ConfigInstallProfileUnmetDependenciesTest.php index ab71faa3a2c7e99b9e83e652e7215040ac04ad1c..59f9f706ee70595e3ffc3b37dc2294a8054ad99a 100644 --- a/core/modules/config/tests/src/Functional/ConfigInstallProfileUnmetDependenciesTest.php +++ b/core/modules/config/tests/src/Functional/ConfigInstallProfileUnmetDependenciesTest.php @@ -69,11 +69,10 @@ protected function copyTestingOverrides() { } } - // Add a dependency that can not be met because User is installed before - // Action. + // Add a dependency that can not be met. $config_file = $dest . DIRECTORY_SEPARATOR . InstallStorage::CONFIG_INSTALL_DIRECTORY . DIRECTORY_SEPARATOR . 'system.action.user_block_user_action.yml'; $action = Yaml::decode(file_get_contents($config_file)); - $action['dependencies']['module'][] = 'action'; + $action['dependencies']['module'][] = 'does_not_exist'; file_put_contents($config_file, Yaml::encode($action)); } @@ -82,7 +81,7 @@ protected function copyTestingOverrides() { */ public function testInstalled() { if ($this->expectedException) { - $this->assertContains('Configuration objects provided by <em class="placeholder">user</em> have unmet dependencies: <em class="placeholder">system.action.user_block_user_action (action)</em>', $this->expectedException->getMessage()); + $this->assertContains('Configuration objects provided by <em class="placeholder">testing_config_overrides</em> have unmet dependencies: <em class="placeholder">system.action.user_block_user_action (does_not_exist)</em>', $this->expectedException->getMessage()); $this->assertContains('Drupal\Core\Config\UnmetDependenciesException', $this->expectedException->getMessage()); } else { diff --git a/core/profiles/testing_config_overrides/config/install/system.site.yml b/core/profiles/testing_config_overrides/config/install/system.site.yml new file mode 100644 index 0000000000000000000000000000000000000000..56104f4bffbf45707273c4af84c90153158536b7 --- /dev/null +++ b/core/profiles/testing_config_overrides/config/install/system.site.yml @@ -0,0 +1,12 @@ +uuid: '' +name: 'Test - this is overridden by the installer site configure form' +mail: '' +slogan: '' +page: + 403: '' + 404: '' + front: /user/login +admin_compact_mode: false +weight_select_max: 91 +langcode: en +default_langcode: en diff --git a/core/profiles/testing_config_overrides/config/install/user.role.authenticated.yml b/core/profiles/testing_config_overrides/config/install/user.role.authenticated.yml new file mode 100644 index 0000000000000000000000000000000000000000..1b210736bef9135c35ab1dfa75c0d46e70a83f50 --- /dev/null +++ b/core/profiles/testing_config_overrides/config/install/user.role.authenticated.yml @@ -0,0 +1,11 @@ +langcode: en +status: true +dependencies: + module: + - tour +id: authenticated +label: 'Authenticated user' +weight: 1 +is_admin: false +permissions: + - 'access tour'