diff -u b/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php --- b/core/lib/Drupal/Core/Config/ConfigManager.php +++ b/core/lib/Drupal/Core/Config/ConfigManager.php @@ -130,11 +130,23 @@ * @param string $type * The extension type; e.g., 'module' or 'theme'. * @param string $name - * The name of the module or theme to uninstall default configuration for. + * The name of the module or theme to install default configuration for. */ function uninstall($type, $name) { + // Remove all dependent configuration entities. + // @todo start a batch purge any leftover field data. Field API does one + // purge call anyway, so in case there was no data in the tables, this + // will be fast. + $dependent_entities = $this->findConfigEntityDependentsAsEntities($type, array($name)); + + // Reverse the array to that entities are removed in the correct order of + // dependence. This ensures that field instances are removed before fields. + foreach (array_reverse($dependent_entities) as $entity) { + $entity->setUninstalling(TRUE); + $entity->delete(); + } + $config_names = $this->configFactory->listAll($name . '.'); - // @todo this should also use the entity api, no ? foreach ($config_names as $config_name) { $this->configFactory->get($config_name)->delete(); } diff -u b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php --- b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php @@ -106,6 +106,7 @@ */ protected function getGraph() { if (!isset($this->graph)) { + $graph = array(); $all_the_thingies = $this->loadAllTheThingies(); foreach ($all_the_thingies as $entity) { $graph_key = $entity->getConfigDependencyName(); @@ -134,7 +135,7 @@ * @return \Drupal\Core\Config\Entity\ConfigEntityDependency[] */ protected function loadAllTheThingies () { - if (empty($this->allTheThingies)) { + if (!isset($this->allTheThingies)) { // Load all the configuration and filter out configuration which does not // have the special keys 'dependencies' and 'uuid'. $this->allTheThingies = array_filter( diff -u b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php --- b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php @@ -261,6 +261,12 @@ * {@inheritdoc} */ public function createDependency($type, $name) { + // A config entity is always dependent on it's provider. There is no need to + // explicitly declared the dependency. + // @see \Drupal\Core\Config\Entity\ConfigEntityDependency::hasDependency() + if ($type == 'module' && $this->getEntityType()->getProvider() == $name) { + return $this; + } if (empty($this->dependencies[$type])) { $this->dependencies[$type] = array($name); } diff -u b/core/lib/Drupal/Core/Config/Entity/ConfigEntityDependency.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityDependency.php --- b/core/lib/Drupal/Core/Config/Entity/ConfigEntityDependency.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityDependency.php @@ -7,8 +7,6 @@ namespace Drupal\Core\Config\Entity; -use Drupal\Core\Entity\EntityTypeInterface; - /** * Class ConfigEntityDependency */ @@ -36,11 +34,6 @@ protected $dependencies; /** - * The configuration entity type. - */ - protected $entityType; - - /** * Constructs the configuration entity dependency from the entity values. * * @param string $name @@ -51,7 +44,6 @@ public function __construct($name, $values) { $this->name = $name; $this->uuid = $values['uuid']; - $this->entityType = $this->setEntityType($name); if (isset($values['dependencies'])) { $this->dependencies = $values['dependencies']; } @@ -80,10 +72,14 @@ * The list of dependencies of the supplied type. */ public function getDependencies($type) { + $dependencies = array(); if (isset($this->dependencies[$type])) { - return $this->dependencies[$type]; + $dependencies = $this->dependencies[$type]; } - return array(); + if ($type == 'module') { + $dependencies[] = substr($this->name,0, strpos($this->name, '.')); + } + return $dependencies; } /** @@ -117,25 +113,6 @@ } /** - * Gets the entity type of this object. - * - * @return string - * The entity type. - */ - public function getEntityType() { - return $this->entityType; - } - - public function setEntityType($name) { - // @todo copied from ConfigManager::getEntityTypeIdByName() - $entities = array_filter(\Drupal::entityManager()->getDefinitions(), function (EntityTypeInterface $entity_type) use ($name) { - return ($config_prefix = $entity_type->getConfigPrefix()) && strpos($name, $config_prefix . '.') === 0; - }); - return key($entities); - - } - - /** * Gets the configuration entity's configuration dependency name. * * @return string @@ -147,7 +124,2 @@ - // @todo copied from ConfigStorageController::getIDFromConfigName() - function getIDFromConfigName() { - return substr($this->name, strlen(\Drupal::entityManager()->getDefinition($this->getEntityType())->getConfigPrefix() . '.')); - } - } diff -u b/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php --- b/core/lib/Drupal/Core/Extension/ModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php @@ -725,21 +725,8 @@ module_load_install($module); $this->invoke($module, 'uninstall'); - // Remove all dependent configuration entities. - // @todo maybe move the call to configManager::uninstall() to here - // and move this code in that method ? - // @todo start a batch purge any leftover field data. Field API does one - // purge call anyway, so in case there was no data in the tables, this - // will be fast. - $dependent_entities = \Drupal::service('config.manager')->findConfigEntityDependents('module', array($module)); - foreach ($dependent_entities as $dependent_entity) { - $entity = \Drupal::entityManager()->getStorageController($dependent_entity->getEntityType())->load($dependent_entity->getIDFromConfigName()); - // Sometimes entities can be deleted already, e.g. field instances. - if ($entity) { - $entity->setUninstalling(TRUE); - $entity->delete(); - } - } + // Remove all configuration belonging to the module. + \Drupal::service('config.manager')->uninstall('module', $module); // Remove the schema. drupal_uninstall_schema($module); @@ -747,9 +734,6 @@ // Remove the module's entry from the config. $module_config->clear("enabled.$module")->save(); - // Remove all configuration belonging to the module. - \Drupal::service('config.manager')->uninstall('module', $module); - // Update the module handler to remove the module. // The current ModuleHandler instance is obsolete with the kernel rebuild // below. diff -u b/core/modules/comment/config/views.view.comments_recent.yml b/core/modules/comment/config/views.view.comments_recent.yml --- b/core/modules/comment/config/views.view.comments_recent.yml +++ b/core/modules/comment/config/views.view.comments_recent.yml @@ -234 +233,0 @@ - - views diff -u b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityUnitTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityUnitTest.php --- b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityUnitTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityUnitTest.php @@ -104,24 +104,38 @@ * Tests setDependency(), hasDependency() and removeDependency(). */ public function testDependencyMangement() { - // Test dependencies between entities. + $config_manager = \Drupal::service('config.manager'); + // Test dependencies between modules. $entity1 = $this->storage->create(array('id' => 'entity1')); + $entity1->createDependency('module', 'node'); + $entity1->createDependency('module', 'config_test'); + $entity1->save(); + + $dependents = $config_manager->findConfigEntityDependents('module', array('node')); + $this->assertTrue(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 has a dependency on the Node module.'); + $dependents = $config_manager->findConfigEntityDependents('module', array('config_test')); + $this->assertTrue(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 has a dependency on the config_test module.'); + $dependents = $config_manager->findConfigEntityDependents('module', array('views')); + $this->assertFalse(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 does not have a dependency on the Views module.'); + // Ensure that the provider of the config entity is not actually written to + // the dependencies array. + $raw_config = \Drupal::config('config_test.dynamic.entity1'); + $this->assertTrue(array_search('config_test', $raw_config->get('dependencies.module')) === FALSE, 'Module that the provides the configuration entity is not written to the dependencies array as this is implicit.'); + $this->assertTrue(array_search('node', $raw_config->get('dependencies.module')) !== FALSE, 'Node module is written to the dependencies array as this has to be explicit.'); + + // Create additional entities to test dependencies on config entities. $entity2 = $this->storage->create(array('id' => 'entity2')); $entity3 = $this->storage->create(array('id' => 'entity3')); $entity4 = $this->storage->create(array('id' => 'entity4')); - $entity1->createDependency('module', 'node'); $entity4->createDependency('entity', $entity3->getConfigDependencyName()); $entity3->createDependency('entity', $entity2->getConfigDependencyName()); $entity2->createDependency('entity', $entity1->getConfigDependencyName()); - $entity1->save(); $entity2->save(); $entity3->save(); $entity4->save(); - $config_manager = \Drupal::service('config.manager'); - // Test getting $entity1's dependencies as configuration dependency objects. $dependents = $config_manager->findConfigEntityDependents('entity', array($entity1->getConfigDependencyName())); $this->assertFalse(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 does not have a dependency on itself.'); diff -u b/core/modules/file/config/views.view.files.yml b/core/modules/file/config/views.view.files.yml --- b/core/modules/file/config/views.view.files.yml +++ b/core/modules/file/config/views.view.files.yml @@ -1047 +1046,0 @@ - - views diff -u b/core/modules/node/config/views.view.content.yml b/core/modules/node/config/views.view.content.yml --- b/core/modules/node/config/views.view.content.yml +++ b/core/modules/node/config/views.view.content.yml @@ -560 +559,0 @@ - - views diff -u b/core/modules/node/config/views.view.content_recent.yml b/core/modules/node/config/views.view.content_recent.yml --- b/core/modules/node/config/views.view.content_recent.yml +++ b/core/modules/node/config/views.view.content_recent.yml @@ -468 +467,0 @@ - - views diff -u b/core/modules/node/config/views.view.frontpage.yml b/core/modules/node/config/views.view.frontpage.yml --- b/core/modules/node/config/views.view.frontpage.yml +++ b/core/modules/node/config/views.view.frontpage.yml @@ -237 +236,0 @@ - - views diff -u b/core/modules/node/config/views.view.glossary.yml b/core/modules/node/config/views.view.glossary.yml --- b/core/modules/node/config/views.view.glossary.yml +++ b/core/modules/node/config/views.view.glossary.yml @@ -378 +377,0 @@ - - views diff -u b/core/modules/taxonomy/config/views.view.taxonomy_term.yml b/core/modules/taxonomy/config/views.view.taxonomy_term.yml --- b/core/modules/taxonomy/config/views.view.taxonomy_term.yml +++ b/core/modules/taxonomy/config/views.view.taxonomy_term.yml @@ -242 +241,0 @@ - - views diff -u b/core/modules/user/config/views.view.user_admin_people.yml b/core/modules/user/config/views.view.user_admin_people.yml --- b/core/modules/user/config/views.view.user_admin_people.yml +++ b/core/modules/user/config/views.view.user_admin_people.yml @@ -554,6 +554,7 @@ empty_zero: false hide_alter_empty: true text: Translate + optional: true plugin_id: content_translation_link provider: content_translation dropbutton: diff -u b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php --- b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php +++ b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php @@ -47,9 +47,10 @@ // EntityInterface::isNew() is missing from the list of methods, because it // calls id(), which breaks the ->expect($this->once()) call. Call it later. // EntityInterface::isSyncing() is only called during syncing process. - // ConfigEntityInterface::getConfigDependencyName is only used during - // dependency management. - if ($reflection_method->getName() != 'isNew' && $reflection_method->getName() != 'isSyncing' && $reflection_method->getName() != 'getConfigDependencyName') { + // EntityInterface::isUninstalling() is only called during uninstallation + // process. ConfigEntityInterface::getConfigDependencyName is only used + // during dependency management. + if ($reflection_method->getName() != 'isNew' && $reflection_method->getName() != 'isSyncing' && $reflection_method->getName() != 'isUninstalling' && $reflection_method->getName() != 'getConfigDependencyName') { if (count($reflection_method->getParameters()) == 0) { $method_args[$reflection_method->getName()] = array(); } only in patch2: unchanged: --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigDependencyManagerTest.php @@ -0,0 +1,56 @@ + 'ConfigDependencyManager test', + 'description' => 'Tests the ConfigDependencyManager class.', + 'group' => 'Configuration' + ); + } + + public function testNoConfiguration() { + $storage = $this->getMock('Drupal\Core\Config\StorageInterface'); + $storage->expects($this->once()) + ->method('listAll') + ->with('') + ->will($this->returnValue(array())); + $storage->expects($this->once()) + ->method('readMultiple') + ->with(array()) + ->will($this->returnValue(array())); + $dep_manger = new ConfigDependencyManager($storage); + $this->assertEmpty($dep_manger->getDependentEntities('entity', 'config_test.dynamic.entity_id:745b0ce0-aece-42dd-a800-ade5b8455e84')); + } + + public function testNoConfigEntities() { + $storage = $this->getMock('Drupal\Core\Config\StorageInterface'); + $storage->expects($this->once()) + ->method('listAll') + ->with('') + ->will($this->returnValue(array('simple.config'))); + $storage->expects($this->once()) + ->method('readMultiple') + ->with(array('simple.config')) + ->will($this->returnValue(array( + 'simple.config' => array( + 'key' => 'value', + ), + ))); + $dep_manger = new ConfigDependencyManager($storage); + $this->assertEmpty($dep_manger->getDependentEntities('entity', 'config_test.dynamic.entity_id:745b0ce0-aece-42dd-a800-ade5b8455e84')); + } + +} only in patch2: unchanged: --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityDependencyTest.php @@ -0,0 +1,66 @@ + 'ConfigEntityDependency test', + 'description' => 'Tests the ConfigEntityDependency class.', + 'group' => 'Configuration' + ); + } + + public function testEmptyDependencies() { + $values = array( + 'uuid' => '60db47f4-54fb-4c86-a439-5769fbda4bd1', + ); + $dep = new ConfigEntityDependency('config_test.dynamic.entity_id', $values); + + $this->assertEquals($values['uuid'], $dep->uuid()); + $this->assertEquals('config_test.dynamic.entity_id', $dep->getName()); + $this->assertEquals('config_test.dynamic.entity_id:' . $values['uuid'], $dep->getConfigDependencyName()); + $this->assertEquals(array(), $dep->getDependencies('theme')); + $this->assertEquals(array(), $dep->getDependencies('entity')); + $this->assertEquals(array('config_test'), $dep->getDependencies('module')); + $this->assertTrue($dep->hasDependency('module', 'config_test')); + $this->assertFalse($dep->hasDependency('module', 'views')); + } + + public function testWithDependencies() { + $values = array( + 'uuid' => '60db47f4-54fb-4c86-a439-5769fbda4bd1', + 'dependencies' => array( + 'module' => array( + 'node', + 'views' + ), + 'entity' => array( + 'config_test.dynamic.entity_id:745b0ce0-aece-42dd-a800-ade5b8455e84', + ), + ), + ); + $dep = new ConfigEntityDependency('config_test.dynamic.entity_id', $values); + + $this->assertEquals(array(), $dep->getDependencies('theme')); + $this->assertEquals(array('config_test.dynamic.entity_id:745b0ce0-aece-42dd-a800-ade5b8455e84'), $dep->getDependencies('entity')); + $this->assertEquals(array('node', 'views', 'config_test'), $dep->getDependencies('module')); + $this->assertTrue($dep->hasDependency('module', 'config_test')); + $this->assertTrue($dep->hasDependency('module', 'views')); + $this->assertTrue($dep->hasDependency('module', 'node')); + $this->assertFalse($dep->hasDependency('module', 'block')); + $this->assertTrue($dep->hasDependency('entity', 'config_test.dynamic.entity_id:745b0ce0-aece-42dd-a800-ade5b8455e84')); + $this->assertFalse($dep->hasDependency('entity', 'config_test.dynamic.another_id:7dfa5cb7-2248-4d52-8c00-cd8e02d1e78e')); + } + +}