diff --git a/core/includes/config.inc b/core/includes/config.inc index 8166e84..a3f4a68 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -1,11 +1,13 @@ listAll($name . '.'); + + // Work out if this extension provides default configuration for any other + // enabled extensions. $config_dir = drupal_get_path($type, $name) . '/config'; if (is_dir($config_dir)) { - $source_storage = new FileStorage($config_dir); - $storage_comparer = new StorageComparer($source_storage, Drupal::service('config.storage')); + $default_storage = new FileStorage($config_dir); + $other_module_config = array_filter($default_storage->listAll(), + function ($value) use ($name) { + return !preg_match('/^' . $name . '\./', $value); + } + ); + $enabled_extensions = array_keys(\Drupal::moduleHandler()->getModuleList()); + $enabled_extensions += array_keys(array_filter(list_themes(), function ($theme) {return $theme->status;})); + + $other_module_config = array_filter($other_module_config, function ($config_name) use ($enabled_extensions) { + $provider = Unicode::substr($config_name, 0, strpos($config_name, '.')); + return in_array($provider, $enabled_extensions); + }); + + $config_to_install = array_merge($config_to_install, $other_module_config); + } + if (!empty($config_to_install)) { + $storage_comparer = new ExtensionInstallStorageComparer($source_storage, Drupal::service('config.storage')); + $storage_comparer->setSourceNames($config_to_install); // Only import new config. Changed config is from previous enables and // should not be overwritten. $storage_comparer->addChangelistCreate(); diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 87b3b18..5e12ff5 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1476,15 +1476,16 @@ function theme_enable($theme_list) { } // The value is not used; the weight is ignored for themes currently. - $theme_config->set("enabled.$key", 0); - $disabled_themes->clear($key); + $theme_config->set("enabled.$key", 0)->save(); + $disabled_themes->clear($key)->save(); + + // Refresh the theme list as config_install_default_config() needs an + // updated list to work. + list_themes(TRUE); // Install default configuration of the theme. config_install_default_config('theme', $key); } - $theme_config->save(); - $disabled_themes->save(); - list_themes(TRUE); Drupal::service('router.builder')->rebuild(); menu_router_rebuild(); drupal_theme_rebuild(); diff --git a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php new file mode 100644 index 0000000..689b14d --- /dev/null +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php @@ -0,0 +1,61 @@ +folders)) { + $this->folders = $this->getComponentNames('module', array_keys(\Drupal::moduleHandler()->getModuleList())); + $this->folders += $this->getComponentNames('theme', array_keys(array_filter(list_themes(), function ($theme) {return $theme->status;}))); + } + return $this->folders; + } + + /** + * {@inheritdoc} + * + * @throws \Drupal\Core\Config\StorageException + */ + public function write($name, array $data) { + throw new StorageException('Write operation is not allowed for config extension install storage.'); + } + + /** + * {@inheritdoc} + * + * @throws \Drupal\Core\Config\StorageException + */ + public function delete($name) { + throw new StorageException('Delete operation is not allowed for config extension install storage.'); + } + + /** + * {@inheritdoc} + * + * @throws \Drupal\Core\Config\StorageException + */ + public function rename($name, $new_name) { + throw new StorageException('Rename operation is not allowed for config extension install storage.'); + } + +} diff --git a/core/lib/Drupal/Core/Config/ExtensionInstallStorageComparer.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorageComparer.php new file mode 100644 index 0000000..0503315 --- /dev/null +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorageComparer.php @@ -0,0 +1,38 @@ +sourceNames = $source_names; + return $this; + } + + /** + * Gets all the configuration names in the source storage. + * + * @return array + * List of all the configuration names in the source storage. + * + * @see self::setSourceNames() + */ + protected function getSourceNames() { + return $this->sourceNames; + } + +} diff --git a/core/modules/breakpoint/breakpoint.install b/core/modules/breakpoint/breakpoint.install index dcc0b35..6c74779 100644 --- a/core/modules/breakpoint/breakpoint.install +++ b/core/modules/breakpoint/breakpoint.install @@ -11,8 +11,8 @@ * Import breakpoints from all enabled themes. */ function breakpoint_enable() { - // Import breakpoints from themes. - $themes = list_themes(); + // Import breakpoints from enabled themes. + $themes = array_filter(list_themes(), function ($theme) {return $theme->status;}); _breakpoint_theme_enabled(array_keys($themes)); // Import breakpoints from modules. diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php index a8ca042..363b889 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php @@ -182,17 +182,6 @@ function testNameValidation() { $this->fail($message); } - // Verify an exception is thrown when importing configuration with an - // invalid name (missing a namespace). - $message = 'Expected ConfigNameException was thrown when attempting to install invalid configuration.'; - try { - $this->enableModules(array('config_test_invalid_name')); - $this->installConfig(array('config_test_invalid_name')); - $this->fail($message); - } - catch (ConfigNameException $e) { - $this->pass($message); - } } } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php index 989c074..f3f3ea6 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php @@ -34,6 +34,7 @@ public static function getInfo() { public function setUp() { parent::setUp(); config_install_default_config('module', 'config_test'); + config_install_default_config('module', 'locale'); } /** diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigOtherModuleTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigOtherModuleTest.php new file mode 100644 index 0000000..4f87b58 --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigOtherModuleTest.php @@ -0,0 +1,98 @@ + 'Default configuration owner', + 'description' => 'Tests default configuration provided by a module that does not own it.', + 'group' => 'Configuration', + ); + } + + /** + * Sets up the module handler for enabling and disabling modules. + */ + public function setUp() { + parent::setUp(); + $this->moduleHandler = $this->container->get('module_handler'); + } + + /** + * Tests enabling the provider of the default configuration first. + */ + public function testInstallOtherModuleFirst() { + $this->moduleHandler->enable(array('config_other_module_config')); + + // Check that the config entity doesn't exist before the config_test module + // is enabled. We cannot use the entity system because the config_test + // entity type does not exist. + $config = $this->container->get('config.factory')->get('config_test.dynamic.other_module'); + $this->assertTrue($config->isNew(), 'Default configuration for other modules is not installed if that module is not enabled.'); + + // Install the module that provides the entity type. This installs the + // default configuration. + $this->moduleHandler->enable(array('config_test')); + $this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration has been installed.'); + + // Uninstall the module that provides the entity type. This will remove the + // default configuration. + $this->moduleHandler->disable(array('config_test')); + $this->moduleHandler->uninstall(array('config_test')); + $config = $this->container->get('config.factory')->get('config_test.dynamic.other_module'); + $this->assertTrue($config->isNew(), 'Default configuration for other modules is removed when the config entity provider is disabled.'); + + // Install the module that provides the entity type again. This installs the + // default configuration. + $this->moduleHandler->enable(array('config_test')); + $other_module_config_entity = entity_load('config_test', 'other_module', TRUE); + $this->assertTrue($other_module_config_entity, "Default configuration has been recreated."); + + // Update the default configuration to test that the changes are preserved + // if the module that provides the default configuration is uninstalled. + $other_module_config_entity->set('style', "The piano ain't got no wrong notes."); + $other_module_config_entity->save(); + + // Uninstall the module that provides the default configuration. + $this->moduleHandler->disable(array('config_other_module_config')); + $this->moduleHandler->uninstall(array('config_other_module_config')); + $this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration for other modules is not removed when the module that provides it is uninstalled.'); + + // Default configuration provided by config_test should still exist. + $this->assertTrue(entity_load('config_test', 'dotted.default', TRUE), 'The configuration is not deleted.'); + + // Re-enable module to test that default config is unchanged. + $this->moduleHandler->enable(array('config_other_module_config')); + $config_entity = entity_load('config_test', 'other_module', TRUE); + $this->assertEqual($config_entity->get('style'), "The piano ain't got no wrong notes.", 'Re-enabling the module does not install default config over the existing config entity.'); + } + + /** + * Tests enabling the provider of the config entity type first. + */ + public function testInstallConfigEnityModuleFirst() { + $this->moduleHandler->enable(array('config_test')); + $this->assertFalse(entity_load('config_test', 'other_module', TRUE), 'Default configuration provided by config_other_module_config does not exist.'); + + $this->moduleHandler->enable(array('config_other_module_config')); + $this->assertTrue(entity_load('config_test', 'other_module', TRUE), 'Default configuration provided by config_other_module_config has been installed.'); + } + +} diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php index e1ea9b7..652b0b4 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php @@ -22,7 +22,7 @@ class ConfigSchemaTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('system', 'locale', 'image', 'config_test'); + public static $modules = array('system', 'locale', 'field', 'image', 'config_test'); public static function getInfo() { return array( diff --git a/core/modules/config/tests/config_other_module_config/config/config_test.dynamic.other_module.yml b/core/modules/config/tests/config_other_module_config/config/config_test.dynamic.other_module.yml new file mode 100644 index 0000000..b144af6 --- /dev/null +++ b/core/modules/config/tests/config_other_module_config/config/config_test.dynamic.other_module.yml @@ -0,0 +1,8 @@ +id: other_module +uuid: 486f9f5c-82ed-4add-a700-b0ee3af4d17d +label: 'Other module' +weight: '0' +style: '' +status: '1' +langcode: en +protected_property: Default diff --git a/core/modules/config/tests/config_other_module_config/config_other_module_config.info.yml b/core/modules/config/tests/config_other_module_config/config_other_module_config.info.yml new file mode 100644 index 0000000..0f78017 --- /dev/null +++ b/core/modules/config/tests/config_other_module_config/config_other_module_config.info.yml @@ -0,0 +1,6 @@ +name: 'Config other module config' +type: module +package: Testing +version: VERSION +core: 8.x +hidden: true diff --git a/core/modules/config/tests/config_other_module_config/config_other_module_config.module b/core/modules/config/tests/config_other_module_config/config_other_module_config.module new file mode 100644 index 0000000..3d68fc0 --- /dev/null +++ b/core/modules/config/tests/config_other_module_config/config_other_module_config.module @@ -0,0 +1,6 @@ +container->set('current_user', $user); - $available_values = $data->getPossibleValues(); - $this->assertEqual($available_values, array('filtered_html', 'full_html', 'plain_text')); - $available_options = $data->getPossibleOptions(); $expected_available_options = array( 'filtered_html' => 'Filtered HTML', 'full_html' => 'Full HTML', + 'filter_test' => 'Test format', 'plain_text' => 'Plain text', ); + + $available_values = $data->getPossibleValues(); + $this->assertEqual($available_values, array_keys($expected_available_options)); + $available_options = $data->getPossibleOptions(); $this->assertEqual($available_options, $expected_available_options); + $allowed_values = $data->getSettableValues($user); $this->assertEqual($allowed_values, array('plain_text')); $allowed_options = $data->getSettableOptions($user); diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php index d3461f3..64b9722 100644 --- a/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php +++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php @@ -20,7 +20,7 @@ class FilterUnitTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('filter'); + public static $modules = array('system', 'filter'); /** * @var \Drupal\filter\Plugin\FilterInterface[]