diff --git a/core/includes/config.inc b/core/includes/config.inc index 0011533..851479e 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -32,13 +32,13 @@ function config_install_default_config($type, $name) { // If this module defines any ConfigEntity types, then create a manifest file // for each of them with a listing of the objects it maintains. foreach (config_get_module_config_entities($name) as $entity_type => $entity_info) { - $manifest_config = config('manifest.' . $entity_info['config_prefix']); + $config_manifest = config_manifest($entity_info['module'], $entity_info['config_prefix']); $manifest_data = array(); foreach ($source_storage->listAll($entity_info['config_prefix']) as $config_name) { list(, , $id) = explode('.', $config_name); $manifest_data[$id]['name'] = $config_name; } - $manifest_config->setData($manifest_data)->save(); + $config_manifest->setData($manifest_data)->save(); } $config_changes = array( @@ -56,25 +56,19 @@ function config_install_default_config($type, $name) { } /** - * Uninstalls the default configuration of a given extension. + * Uninstalls the configuration of a given extension. * * @param string $type * The extension type; e.g., 'module' or 'theme'. * @param string $name - * The name of the module or theme to install default configuration for. + * The name of the module or theme to uninstall configuration for. */ -function config_uninstall_default_config($type, $name) { +function config_uninstall_config($type, $name) { $storage = drupal_container()->get('config.storage'); $config_names = $storage->listAll($name . '.'); foreach ($config_names as $config_name) { config($config_name)->delete(); } - - // If this module defines any ConfigEntity types, then delete the manifest - // file for each of them. - foreach (config_get_module_config_entities($name) as $entity_type) { - config('manifest.' . $entity_info['config_prefix'])->delete(); - } } /** @@ -106,6 +100,35 @@ function config($name) { } /** + * Retrieves a configuration entity manifest object. + * + * @TODO An excellent explanation of manifests should live here. + * + * @param string $module + * The name of the module that provides the configuration entity type. + * @param string $config_prefix + * The config prefix used by the configuration entity type. + * + * @return Drupal\Core\Config\Config + * A configuration object. + */ +function config_manifest($module, $config_prefix) { + return config(config_manifest_name($module, $config_prefix)); +} + +/** + * Assembles a configuration entity manifest name. + * + * @param string $module + * The name of the module that provides the configuration entity type. + * @param string $config_prefix + * The config prefix used by the configuration entity type. + */ +function config_manifest_name($module, $config_prefix) { + return $module . '.manifest.' . $config_prefix; +} + +/** * Returns a list of differences between configuration storages. * * @param Drupal\Core\Config\StorageInterface $source_storage @@ -125,12 +148,21 @@ function config_sync_get_changes(StorageInterface $source_storage, StorageInterf // target storage, generate an array of the objects, and compare them. $source_config_data = array(); $target_config_data = array(); - foreach ($source_storage->listAll('manifest') as $name) { - if ($source_manifest_data = $source_storage->read($name)) { + foreach (config_get_module_config_entities() as $entity_info) { + $manifest_name = config_manifest_name($entity_info['module'], $entity_info['config_prefix']); + $source_manifest_data = $source_storage->read($manifest_name); + // Empty arrays need to be merged as this would indicate that all config + // entities of this type are to be removed. + if ($source_manifest_data !== FALSE) { $source_config_data = array_merge($source_config_data, $source_manifest_data); } + else { + // No manifest exists in the source directory. Therefore we can not make + // any assumptions about what the user wants to do. + continue; + } - if ($target_manifest_data = $target_storage->read($name)) { + if ($target_manifest_data = $target_storage->read($manifest_name)) { $target_config_data = array_merge($target_config_data, $target_manifest_data); } } @@ -150,8 +182,9 @@ function config_sync_get_changes(StorageInterface $source_storage, StorageInterf } foreach (array_intersect($source_storage->listAll(), $target_storage->listAll()) as $name) { - // Ignore manifest files - if (substr($name, 0, 9) != 'manifest.') { + // Ignore manifest files which have the pattern + // module.manifest.config_entity. + if (!preg_match('/^[^.]+\.manifest\./', $name)) { $source_config_data = $source_storage->read($name); $target_config_data = $target_storage->read($name); if ($source_config_data !== $target_config_data) { @@ -279,21 +312,21 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou } /** - * Return a list of all config entity types provided by a module. + * Returns a list of config entity types. * * @param string $module - * The name of the module possibly providing config entities. + * (optional) The name of the module providing config entities. * * @return array * An associative array containing the entity info for any config entities * provided by the requested module, keyed by the entity type. */ -function config_get_module_config_entities($module) { +function config_get_module_config_entities($module = NULL) { // While this is a lot of work to generate, it's not worth static caching // since this function is only called at install/uninstall, and only // once per module. $info = entity_get_info(); return array_filter($info, function($entity_info) use ($module) { - return ($entity_info['module'] == $module) && is_subclass_of($entity_info['class'], 'Drupal\Core\Config\Entity\ConfigEntityInterface'); + return ($entity_info['module'] == $module || $module === NULL) && is_subclass_of($entity_info['class'], 'Drupal\Core\Config\Entity\ConfigEntityInterface'); }); } diff --git a/core/includes/module.inc b/core/includes/module.inc index 9be96cd..e9a8652 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -720,7 +720,7 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE) drupal_uninstall_schema($module); // Remove all configuration belonging to the module. - config_uninstall_default_config('module', $module); + config_uninstall_config('module', $module); watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO); $schema_store->delete($module); diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php index 7f60f9d..109a96b 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php @@ -265,7 +265,7 @@ public function delete(array $entities) { $config->delete(); // Remove the entity from the manifest file. - config('manifest.' . $this->entityInfo['config_prefix']) + config_manifest($this->entityInfo['module'], $this->entityInfo['config_prefix']) ->clear($entity->id()) ->save(); } @@ -339,7 +339,7 @@ public function save(EntityInterface $entity) { } // Add this entity to the manifest file if necessary. - $config = config('manifest.' . $this->entityInfo['config_prefix']); + $config = config_manifest($this->entityInfo['module'], $this->entityInfo['config_prefix']); $manifest = $config->get(); if (!in_array($this->getConfigPrefix() . $entity->id(), $manifest)) { $manifest[$entity->id()] = array( diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php index 95089f7..db8c2f2 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php @@ -66,7 +66,7 @@ function testDeleted() { $this->assertIdentical($config->get('id'), 'default'); // Create an empty manifest to delete the configuration object. - $staging->write('manifest.config_test.dynamic', array()); + $staging->write(config_manifest_name('config_test','config_test.dynamic'), array()); // Import. config_import(); @@ -112,9 +112,9 @@ function testNew() { $staging->write($dynamic_name, $original_dynamic_data); // Create manifest for new config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); + $manifest_data = config_manifest('config_test', 'config_test.dynamic')->get(); $manifest_data[$original_dynamic_data['id']]['name'] = 'config_test.dynamic.' . $original_dynamic_data['id']; - $staging->write('manifest.config_test.dynamic', $manifest_data); + $staging->write(config_manifest_name('config_test', 'config_test.dynamic'), $manifest_data); $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); @@ -160,8 +160,8 @@ function testUpdated() { $original_dynamic_data['label'] = 'Updated'; $staging->write($dynamic_name, $original_dynamic_data); // Create manifest for updated config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); - $staging->write('manifest.config_test.dynamic', $manifest_data); + $manifest_data = config_manifest('config_test', 'config_test.dynamic')->get(); + $staging->write(config_manifest_name('config_test', 'config_test.dynamic'), $manifest_data); // Verify the active configuration still returns the default values. $config = config($name); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php index dd24224..18e348a 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php @@ -64,9 +64,9 @@ function testImport() { $staging->write($dynamic_name, $original_dynamic_data); // Create manifest for new config entity. - $manifest_data = config('manifest.config_test.dynamic')->get(); + $manifest_data = config_manifest('config_test', 'config_test.dynamic')->get(); $manifest_data[$original_dynamic_data['id']]['name'] = 'config_test.dynamic.' . $original_dynamic_data['id']; - $staging->write('manifest.config_test.dynamic', $manifest_data); + $staging->write(config_manifest_name('config_test', 'config_test.dynamic'), $manifest_data); $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.'); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php index b549119..6663c7c 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php @@ -7,12 +7,12 @@ namespace Drupal\config\Tests; -use Drupal\simpletest\DrupalUnitTestBase; +use Drupal\simpletest\WebTestBase; /** - * Tests installation of configuration objects in installation functionality. + * Tests install/uninstall of config objects during module install/uninstall. */ -class ConfigInstallTest extends DrupalUnitTestBase { +class ConfigInstallTest extends WebTestBase { public static function getInfo() { return array( 'name' => 'Installation functionality', @@ -30,26 +30,31 @@ function setUp() { } /** - * Tests module installation. + * Tests module install and uninstall. */ - function testModuleInstallation() { + function testModuleInstallAndUninstall() { $default_config = 'config_test.system'; $default_configuration_entity = 'config_test.dynamic.default'; + $default_configuration_entity_manifest = config_manifest_name('config_test', 'config_test.dynamic'); // Verify that default module config does not exist before installation yet. $config = config($default_config); $this->assertIdentical($config->isNew(), TRUE); $config = config($default_configuration_entity); $this->assertIdentical($config->isNew(), TRUE); + $config = config($default_configuration_entity_manifest); + $this->assertIdentical($config->isNew(), TRUE); // Install the test module. - $this->enableModules(array('config_test')); + module_enable(array('config_test')); // Verify that default module config exists. $config = config($default_config); $this->assertIdentical($config->isNew(), FALSE); $config = config($default_configuration_entity); $this->assertIdentical($config->isNew(), FALSE); + $config = config($default_configuration_entity_manifest); + $this->assertIdentical($config->isNew(), FALSE); // Verify that configuration import callback was invoked for the dynamic // configuration entity. @@ -63,5 +68,23 @@ function testModuleInstallation() { $this->assertFalse(isset($GLOBALS['hook_config_test']['update'])); $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete'])); $this->assertFalse(isset($GLOBALS['hook_config_test']['delete'])); + + module_disable(array('config_test')); + // Verify that default module config exists. + $config = config($default_config); + $this->assertIdentical($config->isNew(), FALSE); + $config = config($default_configuration_entity); + $this->assertIdentical($config->isNew(), FALSE); + $config = config($default_configuration_entity_manifest); + $this->assertIdentical($config->isNew(), FALSE); + + module_uninstall(array('config_test')); + // Verify the configuration no longer exists. + $config = config($default_config); + $this->assertIdentical($config->isNew(), TRUE); + $config = config($default_configuration_entity); + $this->assertIdentical($config->isNew(), TRUE); + $config = config($default_configuration_entity_manifest); + $this->assertIdentical($config->isNew(), TRUE); } }