3 namespace Drupal\KernelTests\Core\Config;
5 use Drupal\entity_test\Entity\EntityTest;
6 use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
9 * Tests for configuration dependencies.
11 * @coversDefaultClass \Drupal\Core\Config\ConfigManager
15 class ConfigDependencyTest extends EntityKernelTestBase {
20 * The entity_test module is enabled to provide content entity types.
24 public static $modules = ['config_test', 'entity_test', 'user'];
27 * Tests that calculating dependencies for system module.
29 public function testNonEntity() {
30 $this->installConfig(['system']);
31 $config_manager = \Drupal::service('config.manager');
32 $dependents = $config_manager->findConfigEntityDependents('module', ['system']);
33 $this->assertTrue(isset($dependents['system.site']), 'Simple configuration system.site has a UUID key even though it is not a configuration entity and therefore is found when looking for dependencies of the System module.');
34 // Ensure that calling
35 // \Drupal\Core\Config\ConfigManager::findConfigEntityDependentsAsEntities()
36 // does not try to load system.site as an entity.
37 $config_manager->findConfigEntityDependentsAsEntities('module', ['system']);
41 * Tests creating dependencies on configuration entities.
43 public function testDependencyManagement() {
44 /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
45 $config_manager = \Drupal::service('config.manager');
46 $storage = $this->container->get('entity.manager')->getStorage('config_test');
47 // Test dependencies between modules.
48 $entity1 = $storage->create(
60 $dependents = $config_manager->findConfigEntityDependents('module', ['node']);
61 $this->assertTrue(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 has a dependency on the Node module.');
62 $dependents = $config_manager->findConfigEntityDependents('module', ['config_test']);
63 $this->assertTrue(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 has a dependency on the config_test module.');
64 $dependents = $config_manager->findConfigEntityDependents('module', ['views']);
65 $this->assertFalse(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 does not have a dependency on the Views module.');
66 // Ensure that the provider of the config entity is not actually written to
67 // the dependencies array.
68 $raw_config = $this->config('config_test.dynamic.entity1');
69 $root_module_dependencies = $raw_config->get('dependencies.module');
70 $this->assertTrue(empty($root_module_dependencies), 'Node module is not written to the root dependencies array as it is enforced.');
72 // Create additional entities to test dependencies on config entities.
73 $entity2 = $storage->create(['id' => 'entity2', 'dependencies' => ['enforced' => ['config' => [$entity1->getConfigDependencyName()]]]]);
75 $entity3 = $storage->create(['id' => 'entity3', 'dependencies' => ['enforced' => ['config' => [$entity2->getConfigDependencyName()]]]]);
77 $entity4 = $storage->create(['id' => 'entity4', 'dependencies' => ['enforced' => ['config' => [$entity3->getConfigDependencyName()]]]]);
80 // Test getting $entity1's dependencies as configuration dependency objects.
81 $dependents = $config_manager->findConfigEntityDependents('config', [$entity1->getConfigDependencyName()]);
82 $this->assertFalse(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 does not have a dependency on itself.');
83 $this->assertTrue(isset($dependents['config_test.dynamic.entity2']), 'config_test.dynamic.entity2 has a dependency on config_test.dynamic.entity1.');
84 $this->assertTrue(isset($dependents['config_test.dynamic.entity3']), 'config_test.dynamic.entity3 has a dependency on config_test.dynamic.entity1.');
85 $this->assertTrue(isset($dependents['config_test.dynamic.entity4']), 'config_test.dynamic.entity4 has a dependency on config_test.dynamic.entity1.');
87 // Test getting $entity2's dependencies as entities.
88 $dependents = $config_manager->findConfigEntityDependentsAsEntities('config', [$entity2->getConfigDependencyName()]);
89 $dependent_ids = $this->getDependentIds($dependents);
90 $this->assertFalse(in_array('config_test:entity1', $dependent_ids), 'config_test.dynamic.entity1 does not have a dependency on config_test.dynamic.entity1.');
91 $this->assertFalse(in_array('config_test:entity2', $dependent_ids), 'config_test.dynamic.entity2 does not have a dependency on itself.');
92 $this->assertTrue(in_array('config_test:entity3', $dependent_ids), 'config_test.dynamic.entity3 has a dependency on config_test.dynamic.entity2.');
93 $this->assertTrue(in_array('config_test:entity4', $dependent_ids), 'config_test.dynamic.entity4 has a dependency on config_test.dynamic.entity2.');
95 // Test getting node module's dependencies as configuration dependency
97 $dependents = $config_manager->findConfigEntityDependents('module', ['node']);
98 $this->assertTrue(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 has a dependency on the Node module.');
99 $this->assertTrue(isset($dependents['config_test.dynamic.entity2']), 'config_test.dynamic.entity2 has a dependency on the Node module.');
100 $this->assertTrue(isset($dependents['config_test.dynamic.entity3']), 'config_test.dynamic.entity3 has a dependency on the Node module.');
101 $this->assertTrue(isset($dependents['config_test.dynamic.entity4']), 'config_test.dynamic.entity4 has a dependency on the Node module.');
103 // Test getting node module's dependencies as configuration dependency
104 // objects after making $entity3 also dependent on node module but $entity1
105 // no longer depend on node module.
106 $entity1->setEnforcedDependencies([])->save();
107 $entity3->setEnforcedDependencies(['module' => ['node'], 'config' => [$entity2->getConfigDependencyName()]])->save();
108 $dependents = $config_manager->findConfigEntityDependents('module', ['node']);
109 $this->assertFalse(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 does not have a dependency on the Node module.');
110 $this->assertFalse(isset($dependents['config_test.dynamic.entity2']), 'config_test.dynamic.entity2 does not have a dependency on the Node module.');
111 $this->assertTrue(isset($dependents['config_test.dynamic.entity3']), 'config_test.dynamic.entity3 has a dependency on the Node module.');
112 $this->assertTrue(isset($dependents['config_test.dynamic.entity4']), 'config_test.dynamic.entity4 has a dependency on the Node module.');
114 // Test dependency on a content entity.
115 $entity_test = EntityTest::create([
116 'name' => $this->randomString(),
117 'type' => 'entity_test',
119 $entity_test->save();
120 $entity2->setEnforcedDependencies(['config' => [$entity1->getConfigDependencyName()], 'content' => [$entity_test->getConfigDependencyName()]])->save();;
121 $dependents = $config_manager->findConfigEntityDependents('content', [$entity_test->getConfigDependencyName()]);
122 $this->assertFalse(isset($dependents['config_test.dynamic.entity1']), 'config_test.dynamic.entity1 does not have a dependency on the content entity.');
123 $this->assertTrue(isset($dependents['config_test.dynamic.entity2']), 'config_test.dynamic.entity2 has a dependency on the content entity.');
124 $this->assertTrue(isset($dependents['config_test.dynamic.entity3']), 'config_test.dynamic.entity3 has a dependency on the content entity (via entity2).');
125 $this->assertTrue(isset($dependents['config_test.dynamic.entity4']), 'config_test.dynamic.entity4 has a dependency on the content entity (via entity3).');
127 // Create a configuration entity of a different type with the same ID as one
128 // of the entities already created.
129 $alt_storage = $this->container->get('entity.manager')->getStorage('config_query_test');
130 $alt_storage->create(['id' => 'entity1', 'dependencies' => ['enforced' => ['config' => [$entity1->getConfigDependencyName()]]]])->save();
131 $alt_storage->create(['id' => 'entity2', 'dependencies' => ['enforced' => ['module' => ['views']]]])->save();
133 $dependents = $config_manager->findConfigEntityDependentsAsEntities('config', [$entity1->getConfigDependencyName()]);
134 $dependent_ids = $this->getDependentIds($dependents);
135 $this->assertFalse(in_array('config_test:entity1', $dependent_ids), 'config_test.dynamic.entity1 does not have a dependency on itself.');
136 $this->assertTrue(in_array('config_test:entity2', $dependent_ids), 'config_test.dynamic.entity2 has a dependency on config_test.dynamic.entity1.');
137 $this->assertTrue(in_array('config_test:entity3', $dependent_ids), 'config_test.dynamic.entity3 has a dependency on config_test.dynamic.entity1.');
138 $this->assertTrue(in_array('config_test:entity4', $dependent_ids), 'config_test.dynamic.entity4 has a dependency on config_test.dynamic.entity1.');
139 $this->assertTrue(in_array('config_query_test:entity1', $dependent_ids), 'config_query_test.dynamic.entity1 has a dependency on config_test.dynamic.entity1.');
140 $this->assertFalse(in_array('config_query_test:entity2', $dependent_ids), 'config_query_test.dynamic.entity2 does not have a dependency on config_test.dynamic.entity1.');
142 $dependents = $config_manager->findConfigEntityDependentsAsEntities('module', ['node', 'views']);
143 $dependent_ids = $this->getDependentIds($dependents);
144 $this->assertFalse(in_array('config_test:entity1', $dependent_ids), 'config_test.dynamic.entity1 does not have a dependency on Views or Node.');
145 $this->assertFalse(in_array('config_test:entity2', $dependent_ids), 'config_test.dynamic.entity2 does not have a dependency on Views or Node.');
146 $this->assertTrue(in_array('config_test:entity3', $dependent_ids), 'config_test.dynamic.entity3 has a dependency on Views or Node.');
147 $this->assertTrue(in_array('config_test:entity4', $dependent_ids), 'config_test.dynamic.entity4 has a dependency on Views or Node.');
148 $this->assertFalse(in_array('config_query_test:entity1', $dependent_ids), 'config_test.query.entity1 does not have a dependency on Views or Node.');
149 $this->assertTrue(in_array('config_query_test:entity2', $dependent_ids), 'config_test.query.entity2 has a dependency on Views or Node.');
151 $dependents = $config_manager->findConfigEntityDependentsAsEntities('module', ['config_test']);
152 $dependent_ids = $this->getDependentIds($dependents);
153 $this->assertTrue(in_array('config_test:entity1', $dependent_ids), 'config_test.dynamic.entity1 has a dependency on config_test module.');
154 $this->assertTrue(in_array('config_test:entity2', $dependent_ids), 'config_test.dynamic.entity2 has a dependency on config_test module.');
155 $this->assertTrue(in_array('config_test:entity3', $dependent_ids), 'config_test.dynamic.entity3 has a dependency on config_test module.');
156 $this->assertTrue(in_array('config_test:entity4', $dependent_ids), 'config_test.dynamic.entity4 has a dependency on config_test module.');
157 $this->assertTrue(in_array('config_query_test:entity1', $dependent_ids), 'config_test.query.entity1 has a dependency on config_test module.');
158 $this->assertTrue(in_array('config_query_test:entity2', $dependent_ids), 'config_test.query.entity2 has a dependency on config_test module.');
160 // Test the ability to find missing content dependencies.
161 $missing_dependencies = $config_manager->findMissingContentDependencies();
162 $this->assertEqual([], $missing_dependencies);
165 $entity_test->uuid() => [
166 'entity_type' => 'entity_test',
167 'bundle' => $entity_test->bundle(),
168 'uuid' => $entity_test->uuid(),
171 // Delete the content entity so that is it now missing.
172 $entity_test->delete();
173 $missing_dependencies = $config_manager->findMissingContentDependencies();
174 $this->assertEqual($expected, $missing_dependencies);
176 // Add a fake missing dependency to ensure multiple missing dependencies
178 $entity1->setEnforcedDependencies(['content' => [$entity_test->getConfigDependencyName(), 'entity_test:bundle:uuid']])->save();;
179 $expected['uuid'] = [
180 'entity_type' => 'entity_test',
181 'bundle' => 'bundle',
184 $missing_dependencies = $config_manager->findMissingContentDependencies();
185 $this->assertEqual($expected, $missing_dependencies);
189 * Tests ConfigManager::uninstall() and config entity dependency management.
191 public function testConfigEntityUninstall() {
192 /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
193 $config_manager = \Drupal::service('config.manager');
194 /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
195 $storage = $this->container->get('entity.manager')
196 ->getStorage('config_test');
197 // Test dependencies between modules.
198 $entity1 = $storage->create(
203 'module' => ['node', 'config_test']
209 $entity2 = $storage->create(
214 'config' => [$entity1->getConfigDependencyName()],
220 // Perform a module rebuild so we can know where the node module is located
222 // @todo Remove as part of https://www.drupal.org/node/2186491
223 system_rebuild_module_data();
224 // Test that doing a config uninstall of the node module deletes entity2
225 // since it is dependent on entity1 which is dependent on the node module.
226 $config_manager->uninstall('module', 'node');
227 $this->assertFalse($storage->load('entity1'), 'Entity 1 deleted');
228 $this->assertFalse($storage->load('entity2'), 'Entity 2 deleted');
232 * Data provider for self::testConfigEntityUninstallComplex().
234 public function providerConfigEntityUninstallComplex() {
235 // Ensure that alphabetical order has no influence on dependency fixing and
238 [['a', 'b', 'c', 'd', 'e']],
239 [['e', 'd', 'c', 'b', 'a']],
240 [['e', 'c', 'd', 'a', 'b']],
245 * Tests complex configuration entity dependency handling during uninstall.
247 * Configuration entities can be deleted or updated during module uninstall
248 * because they have dependencies on the module.
250 * @param array $entity_id_suffixes
251 * The suffixes to add to the 4 entities created by the test.
253 * @dataProvider providerConfigEntityUninstallComplex
255 public function testConfigEntityUninstallComplex(array $entity_id_suffixes) {
256 /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
257 $config_manager = \Drupal::service('config.manager');
258 /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
259 $storage = $this->container->get('entity.manager')
260 ->getStorage('config_test');
261 // Entity 1 will be deleted because it depends on node.
262 $entity_1 = $storage->create(
264 'id' => 'entity_' . $entity_id_suffixes[0],
267 'module' => ['node', 'config_test']
274 // Entity 2 has a dependency on entity 1 but it can be fixed because
275 // \Drupal\config_test\Entity::onDependencyRemoval() will remove the
276 // dependency before config entities are deleted.
277 $entity_2 = $storage->create(
279 'id' => 'entity_' . $entity_id_suffixes[1],
282 'config' => [$entity_1->getConfigDependencyName()],
289 // Entity 3 will be unchanged because it is dependent on entity 2 which can
290 // be fixed. The ConfigEntityInterface::onDependencyRemoval() method will
291 // not be called for this entity.
292 $entity_3 = $storage->create(
294 'id' => 'entity_' . $entity_id_suffixes[2],
297 'config' => [$entity_2->getConfigDependencyName()],
304 // Entity 4's config dependency will be fixed but it will still be deleted
305 // because it also depends on the node module.
306 $entity_4 = $storage->create(
308 'id' => 'entity_' . $entity_id_suffixes[3],
311 'config' => [$entity_1->getConfigDependencyName()],
312 'module' => ['node', 'config_test']
319 // Entity 5 will be fixed because it is dependent on entity 3, which is
320 // unchanged, and entity 1 which will be fixed because
321 // \Drupal\config_test\Entity::onDependencyRemoval() will remove the
323 $entity_5 = $storage->create(
325 'id' => 'entity_' . $entity_id_suffixes[4],
329 $entity_1->getConfigDependencyName(),
330 $entity_3->getConfigDependencyName(),
338 // Set a more complicated test where dependencies will be fixed.
339 \Drupal::state()->set('config_test.fix_dependencies', [$entity_1->getConfigDependencyName()]);
340 \Drupal::state()->set('config_test.on_dependency_removal_called', []);
342 // Do a dry run using
343 // \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval().
344 $config_entities = $config_manager->getConfigEntitiesToChangeOnDependencyRemoval('module', ['node']);
346 // Assert that \Drupal\config_test\Entity\ConfigTest::onDependencyRemoval()
347 // is called as expected and with the correct dependencies.
348 $called = \Drupal::state()->get('config_test.on_dependency_removal_called', []);
349 $this->assertArrayNotHasKey($entity_3->id(), $called, 'ConfigEntityInterface::onDependencyRemoval() is not called for entity 3.');
350 $this->assertSame([$entity_1->id(), $entity_4->id(), $entity_2->id(), $entity_5->id()], array_keys($called), 'The most dependent entites have ConfigEntityInterface::onDependencyRemoval() called first.');
351 $this->assertSame(['config' => [], 'content' => [], 'module' => ['node'], 'theme' => []], $called[$entity_1->id()]);
352 $this->assertSame(['config' => [$entity_1->getConfigDependencyName()], 'content' => [], 'module' => [], 'theme' => []], $called[$entity_2->id()]);
353 $this->assertSame(['config' => [$entity_1->getConfigDependencyName()], 'content' => [], 'module' => ['node'], 'theme' => []], $called[$entity_4->id()]);
354 $this->assertSame(['config' => [$entity_1->getConfigDependencyName()], 'content' => [], 'module' => [], 'theme' => []], $called[$entity_5->id()]);
356 $this->assertEqual($entity_1->uuid(), $config_entities['delete'][1]->uuid(), 'Entity 1 will be deleted.');
357 $this->assertEqual($entity_2->uuid(), $config_entities['update'][0]->uuid(), 'Entity 2 will be updated.');
358 $this->assertEqual($entity_3->uuid(), reset($config_entities['unchanged'])->uuid(), 'Entity 3 is not changed.');
359 $this->assertEqual($entity_4->uuid(), $config_entities['delete'][0]->uuid(), 'Entity 4 will be deleted.');
360 $this->assertEqual($entity_5->uuid(), $config_entities['update'][1]->uuid(), 'Entity 5 is updated.');
362 // Perform a module rebuild so we can know where the node module is located
364 // @todo Remove as part of https://www.drupal.org/node/2186491
365 system_rebuild_module_data();
366 // Perform the uninstall.
367 $config_manager->uninstall('module', 'node');
369 // Test that expected actions have been performed.
370 $this->assertFalse($storage->load($entity_1->id()), 'Entity 1 deleted');
371 $entity_2 = $storage->load($entity_2->id());
372 $this->assertTrue($entity_2, 'Entity 2 not deleted');
373 $this->assertEqual($entity_2->calculateDependencies()->getDependencies()['config'], [], 'Entity 2 dependencies updated to remove dependency on entity 1.');
374 $entity_3 = $storage->load($entity_3->id());
375 $this->assertTrue($entity_3, 'Entity 3 not deleted');
376 $this->assertEqual($entity_3->calculateDependencies()->getDependencies()['config'], [$entity_2->getConfigDependencyName()], 'Entity 3 still depends on entity 2.');
377 $this->assertFalse($storage->load($entity_4->id()), 'Entity 4 deleted');
381 * @covers ::uninstall
382 * @covers ::getConfigEntitiesToChangeOnDependencyRemoval
384 public function testConfigEntityUninstallThirdParty() {
385 /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
386 $config_manager = \Drupal::service('config.manager');
387 /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
388 $storage = $this->container->get('entity_type.manager')
389 ->getStorage('config_test');
390 // Entity 1 will be fixed because it only has a dependency via third-party
391 // settings, which are fixable.
392 $entity_1 = $storage->create([
396 'module' => ['config_test'],
399 'third_party_settings' => [
407 // Entity 2 has a dependency on entity 1.
408 $entity_2 = $storage->create([
412 'config' => [$entity_1->getConfigDependencyName()],
415 'third_party_settings' => [
423 // Entity 3 will be unchanged because it is dependent on entity 2 which can
424 // be fixed. The ConfigEntityInterface::onDependencyRemoval() method will
425 // not be called for this entity.
426 $entity_3 = $storage->create([
430 'config' => [$entity_2->getConfigDependencyName()],
436 // Entity 4's config dependency will be fixed but it will still be deleted
437 // because it also depends on the node module.
438 $entity_4 = $storage->create([
442 'config' => [$entity_1->getConfigDependencyName()],
443 'module' => ['node', 'config_test'],
449 \Drupal::state()->set('config_test.fix_dependencies', []);
450 \Drupal::state()->set('config_test.on_dependency_removal_called', []);
452 // Do a dry run using
453 // \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval().
454 $config_entities = $config_manager->getConfigEntitiesToChangeOnDependencyRemoval('module', ['node']);
455 $config_entity_ids = [
460 foreach ($config_entities as $type => $config_entities_by_type) {
461 foreach ($config_entities_by_type as $config_entity) {
462 $config_entity_ids[$type][] = $config_entity->id();
466 'update' => [$entity_1->id(), $entity_2->id()],
467 'delete' => [$entity_4->id()],
468 'unchanged' => [$entity_3->id()],
470 $this->assertSame($expected, $config_entity_ids);
472 $called = \Drupal::state()->get('config_test.on_dependency_removal_called', []);
473 $this->assertArrayNotHasKey($entity_3->id(), $called, 'ConfigEntityInterface::onDependencyRemoval() is not called for entity 3.');
474 $this->assertSame([$entity_1->id(), $entity_4->id(), $entity_2->id()], array_keys($called), 'The most dependent entities have ConfigEntityInterface::onDependencyRemoval() called first.');
475 $this->assertSame(['config' => [], 'content' => [], 'module' => ['node'], 'theme' => []], $called[$entity_1->id()]);
476 $this->assertSame(['config' => [], 'content' => [], 'module' => ['node'], 'theme' => []], $called[$entity_2->id()]);
477 $this->assertSame(['config' => [], 'content' => [], 'module' => ['node'], 'theme' => []], $called[$entity_4->id()]);
479 // Perform a module rebuild so we can know where the node module is located
481 // @todo Remove as part of https://www.drupal.org/node/2186491
482 system_rebuild_module_data();
483 // Perform the uninstall.
484 $config_manager->uninstall('module', 'node');
486 // Test that expected actions have been performed.
487 $entity_1 = $storage->load($entity_1->id());
488 $this->assertTrue($entity_1, 'Entity 1 not deleted');
489 $this->assertSame($entity_1->getThirdPartySettings('node'), [], 'Entity 1 third party settings updated.');
490 $entity_2 = $storage->load($entity_2->id());
491 $this->assertTrue($entity_2, 'Entity 2 not deleted');
492 $this->assertSame($entity_2->getThirdPartySettings('node'), [], 'Entity 2 third party settings updated.');
493 $this->assertSame($entity_2->calculateDependencies()->getDependencies()['config'], [$entity_1->getConfigDependencyName()], 'Entity 2 still depends on entity 1.');
494 $entity_3 = $storage->load($entity_3->id());
495 $this->assertTrue($entity_3, 'Entity 3 not deleted');
496 $this->assertSame($entity_3->calculateDependencies()->getDependencies()['config'], [$entity_2->getConfigDependencyName()], 'Entity 3 still depends on entity 2.');
497 $this->assertFalse($storage->load($entity_4->id()), 'Entity 4 deleted');
501 * Tests deleting a configuration entity and dependency management.
503 public function testConfigEntityDelete() {
504 /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
505 $config_manager = \Drupal::service('config.manager');
506 /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
507 $storage = $this->container->get('entity.manager')->getStorage('config_test');
508 // Test dependencies between configuration entities.
509 $entity1 = $storage->create(
515 $entity2 = $storage->create(
520 'config' => [$entity1->getConfigDependencyName()],
527 // Do a dry run using
528 // \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval().
529 $config_entities = $config_manager->getConfigEntitiesToChangeOnDependencyRemoval('config', [$entity1->getConfigDependencyName()]);
530 $this->assertEqual($entity2->uuid(), reset($config_entities['delete'])->uuid(), 'Entity 2 will be deleted.');
531 $this->assertTrue(empty($config_entities['update']), 'No dependent configuration entities will be updated.');
532 $this->assertTrue(empty($config_entities['unchanged']), 'No dependent configuration entities will be unchanged.');
534 // Test that doing a delete of entity1 deletes entity2 since it is dependent
537 $this->assertFalse($storage->load('entity1'), 'Entity 1 deleted');
538 $this->assertFalse($storage->load('entity2'), 'Entity 2 deleted');
540 // Set a more complicated test where dependencies will be fixed.
541 \Drupal::state()->set('config_test.fix_dependencies', [$entity1->getConfigDependencyName()]);
543 // Entity1 will be deleted by the test.
544 $entity1 = $storage->create(
551 // Entity2 has a dependency on Entity1 but it can be fixed because
552 // \Drupal\config_test\Entity::onDependencyRemoval() will remove the
553 // dependency before config entities are deleted.
554 $entity2 = $storage->create(
559 'config' => [$entity1->getConfigDependencyName()],
566 // Entity3 will be unchanged because it is dependent on Entity2 which can
568 $entity3 = $storage->create(
573 'config' => [$entity2->getConfigDependencyName()],
580 // Do a dry run using
581 // \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval().
582 $config_entities = $config_manager->getConfigEntitiesToChangeOnDependencyRemoval('config', [$entity1->getConfigDependencyName()]);
583 $this->assertTrue(empty($config_entities['delete']), 'No dependent configuration entities will be deleted.');
584 $this->assertEqual($entity2->uuid(), reset($config_entities['update'])->uuid(), 'Entity 2 will be updated.');
585 $this->assertEqual($entity3->uuid(), reset($config_entities['unchanged'])->uuid(), 'Entity 3 is not changed.');
587 // Perform the uninstall.
590 // Test that expected actions have been performed.
591 $this->assertFalse($storage->load('entity1'), 'Entity 1 deleted');
592 $entity2 = $storage->load('entity2');
593 $this->assertTrue($entity2, 'Entity 2 not deleted');
594 $this->assertEqual($entity2->calculateDependencies()->getDependencies()['config'], [], 'Entity 2 dependencies updated to remove dependency on Entity1.');
595 $entity3 = $storage->load('entity3');
596 $this->assertTrue($entity3, 'Entity 3 not deleted');
597 $this->assertEqual($entity3->calculateDependencies()->getDependencies()['config'], [$entity2->getConfigDependencyName()], 'Entity 3 still depends on Entity 2.');
601 * Tests getConfigEntitiesToChangeOnDependencyRemoval() with content entities.
603 * At the moment there is no runtime code that calculates configuration
604 * dependencies on content entity delete because this calculation is expensive
605 * and all content dependencies are soft. This test ensures that the code
606 * works for content entities.
608 * @see \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval()
610 public function testContentEntityDelete() {
611 $this->installEntitySchema('entity_test');
612 /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
613 $config_manager = \Drupal::service('config.manager');
615 $content_entity = EntityTest::create();
616 $content_entity->save();
617 /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
618 $storage = $this->container->get('entity.manager')->getStorage('config_test');
619 $entity1 = $storage->create(
624 'content' => [$content_entity->getConfigDependencyName()]
630 $entity2 = $storage->create(
635 'config' => [$entity1->getConfigDependencyName()]
642 // Create a configuration entity that is not in the dependency chain.
643 $entity3 = $storage->create(['id' => 'entity3']);
646 $config_entities = $config_manager->getConfigEntitiesToChangeOnDependencyRemoval('content', [$content_entity->getConfigDependencyName()]);
647 $this->assertEqual($entity1->uuid(), $config_entities['delete'][1]->uuid(), 'Entity 1 will be deleted.');
648 $this->assertEqual($entity2->uuid(), $config_entities['delete'][0]->uuid(), 'Entity 2 will be deleted.');
649 $this->assertTrue(empty($config_entities['update']), 'No dependencies of the content entity will be updated.');
650 $this->assertTrue(empty($config_entities['unchanged']), 'No dependencies of the content entity will be unchanged.');
654 * Gets a list of identifiers from an array of configuration entities.
656 * @param \Drupal\Core\Config\Entity\ConfigEntityInterface[] $dependents
657 * An array of configuration entities.
660 * An array with values of entity_type_id:ID
662 protected function getDependentIds(array $dependents) {
664 foreach ($dependents as $dependent) {
665 $dependent_ids[] = $dependent->getEntityTypeId() . ':' . $dependent->id();
667 return $dependent_ids;