annotate core/lib/Drupal/Core/Config/ConfigManager.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Core\Config;
Chris@0 4
Chris@0 5 use Drupal\Component\Diff\Diff;
Chris@0 6 use Drupal\Core\Config\Entity\ConfigDependencyManager;
Chris@0 7 use Drupal\Core\Config\Entity\ConfigEntityInterface;
Chris@0 8 use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
Chris@18 9 use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
Chris@0 10 use Drupal\Core\Entity\EntityManagerInterface;
Chris@18 11 use Drupal\Core\Entity\EntityRepositoryInterface;
Chris@0 12 use Drupal\Core\Entity\EntityTypeInterface;
Chris@18 13 use Drupal\Core\Entity\EntityTypeManagerInterface;
Chris@0 14 use Drupal\Core\Serialization\Yaml;
Chris@0 15 use Drupal\Core\StringTranslation\StringTranslationTrait;
Chris@0 16 use Drupal\Core\StringTranslation\TranslationInterface;
Chris@0 17 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
Chris@0 18
Chris@0 19 /**
Chris@0 20 * The ConfigManager provides helper functions for the configuration system.
Chris@0 21 */
Chris@0 22 class ConfigManager implements ConfigManagerInterface {
Chris@0 23 use StringTranslationTrait;
Chris@18 24 use DeprecatedServicePropertyTrait;
Chris@18 25 use StorageCopyTrait;
Chris@0 26
Chris@0 27 /**
Chris@18 28 * {@inheritdoc}
Chris@18 29 */
Chris@18 30 protected $deprecatedProperties = ['entityManager' => 'entity.manager'];
Chris@18 31
Chris@18 32 /**
Chris@18 33 * The entity type manager.
Chris@0 34 *
Chris@18 35 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
Chris@0 36 */
Chris@18 37 protected $entityTypeManager;
Chris@18 38
Chris@18 39 /**
Chris@18 40 * The entity repository.
Chris@18 41 *
Chris@18 42 * @var \Drupal\Core\Entity\EntityRepositoryInterface
Chris@18 43 */
Chris@18 44 protected $entityRepository;
Chris@0 45
Chris@0 46 /**
Chris@0 47 * The configuration factory.
Chris@0 48 *
Chris@0 49 * @var \Drupal\Core\Config\ConfigFactoryInterface
Chris@0 50 */
Chris@0 51 protected $configFactory;
Chris@0 52
Chris@0 53 /**
Chris@0 54 * The typed config manager.
Chris@0 55 *
Chris@0 56 * @var \Drupal\Core\Config\TypedConfigManagerInterface
Chris@0 57 */
Chris@0 58 protected $typedConfigManager;
Chris@0 59
Chris@0 60 /**
Chris@0 61 * The active configuration storage.
Chris@0 62 *
Chris@0 63 * @var \Drupal\Core\Config\StorageInterface
Chris@0 64 */
Chris@0 65 protected $activeStorage;
Chris@0 66
Chris@0 67 /**
Chris@0 68 * The event dispatcher.
Chris@0 69 *
Chris@0 70 * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
Chris@0 71 */
Chris@0 72 protected $eventDispatcher;
Chris@0 73
Chris@0 74 /**
Chris@0 75 * The configuration collection info.
Chris@0 76 *
Chris@0 77 * @var \Drupal\Core\Config\ConfigCollectionInfo
Chris@0 78 */
Chris@0 79 protected $configCollectionInfo;
Chris@0 80
Chris@0 81 /**
Chris@0 82 * The configuration storages keyed by collection name.
Chris@0 83 *
Chris@0 84 * @var \Drupal\Core\Config\StorageInterface[]
Chris@0 85 */
Chris@0 86 protected $storages;
Chris@0 87
Chris@0 88 /**
Chris@0 89 * Creates ConfigManager objects.
Chris@0 90 *
Chris@18 91 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
Chris@18 92 * The entity type manager.
Chris@0 93 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
Chris@0 94 * The configuration factory.
Chris@0 95 * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
Chris@0 96 * The typed config manager.
Chris@0 97 * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
Chris@0 98 * The string translation service.
Chris@0 99 * @param \Drupal\Core\Config\StorageInterface $active_storage
Chris@0 100 * The active configuration storage.
Chris@0 101 * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
Chris@0 102 * The event dispatcher.
Chris@18 103 * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
Chris@18 104 * The entity repository.
Chris@0 105 */
Chris@18 106 public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, TypedConfigManagerInterface $typed_config_manager, TranslationInterface $string_translation, StorageInterface $active_storage, EventDispatcherInterface $event_dispatcher, EntityRepositoryInterface $entity_repository = NULL) {
Chris@18 107 if ($entity_type_manager instanceof EntityManagerInterface) {
Chris@18 108 @trigger_error('Passing the entity.manager service to ConfigManager::__construct() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Pass the new dependencies instead. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
Chris@18 109 $this->entityTypeManager = \Drupal::entityTypeManager();
Chris@18 110 }
Chris@18 111 else {
Chris@18 112 $this->entityTypeManager = $entity_type_manager;
Chris@18 113 }
Chris@0 114 $this->configFactory = $config_factory;
Chris@0 115 $this->typedConfigManager = $typed_config_manager;
Chris@0 116 $this->stringTranslation = $string_translation;
Chris@0 117 $this->activeStorage = $active_storage;
Chris@0 118 $this->eventDispatcher = $event_dispatcher;
Chris@18 119 if ($entity_repository) {
Chris@18 120 $this->entityRepository = $entity_repository;
Chris@18 121 }
Chris@18 122 else {
Chris@18 123 @trigger_error('The entity.repository service must be passed to ConfigManager::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
Chris@18 124 $this->entityRepository = \Drupal::service('entity.repository');
Chris@18 125 }
Chris@0 126 }
Chris@0 127
Chris@0 128 /**
Chris@0 129 * {@inheritdoc}
Chris@0 130 */
Chris@0 131 public function getEntityTypeIdByName($name) {
Chris@18 132 $entities = array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) use ($name) {
Chris@0 133 return ($entity_type instanceof ConfigEntityTypeInterface && $config_prefix = $entity_type->getConfigPrefix()) && strpos($name, $config_prefix . '.') === 0;
Chris@0 134 });
Chris@0 135 return key($entities);
Chris@0 136 }
Chris@0 137
Chris@0 138 /**
Chris@0 139 * {@inheritdoc}
Chris@0 140 */
Chris@0 141 public function loadConfigEntityByName($name) {
Chris@0 142 $entity_type_id = $this->getEntityTypeIdByName($name);
Chris@0 143 if ($entity_type_id) {
Chris@18 144 $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
Chris@0 145 $id = substr($name, strlen($entity_type->getConfigPrefix()) + 1);
Chris@18 146 return $this->entityTypeManager->getStorage($entity_type_id)->load($id);
Chris@0 147 }
Chris@0 148 return NULL;
Chris@0 149 }
Chris@0 150
Chris@0 151 /**
Chris@0 152 * {@inheritdoc}
Chris@0 153 */
Chris@0 154 public function getEntityManager() {
Chris@18 155 @trigger_error('ConfigManagerInterface::getEntityManager() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use ::getEntityTypeManager() instead. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
Chris@18 156 return \Drupal::service('entity.manager');
Chris@18 157 }
Chris@18 158
Chris@18 159 /**
Chris@18 160 * {@inheritdoc}
Chris@18 161 */
Chris@18 162 public function getEntityTypeManager() {
Chris@18 163 return $this->entityTypeManager;
Chris@0 164 }
Chris@0 165
Chris@0 166 /**
Chris@0 167 * {@inheritdoc}
Chris@0 168 */
Chris@0 169 public function getConfigFactory() {
Chris@0 170 return $this->configFactory;
Chris@0 171 }
Chris@0 172
Chris@0 173 /**
Chris@0 174 * {@inheritdoc}
Chris@0 175 */
Chris@0 176 public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL, $collection = StorageInterface::DEFAULT_COLLECTION) {
Chris@0 177 if ($collection != StorageInterface::DEFAULT_COLLECTION) {
Chris@0 178 $source_storage = $source_storage->createCollection($collection);
Chris@0 179 $target_storage = $target_storage->createCollection($collection);
Chris@0 180 }
Chris@0 181 if (!isset($target_name)) {
Chris@0 182 $target_name = $source_name;
Chris@0 183 }
Chris@0 184 // The output should show configuration object differences formatted as YAML.
Chris@0 185 // But the configuration is not necessarily stored in files. Therefore, they
Chris@0 186 // need to be read and parsed, and lastly, dumped into YAML strings.
Chris@0 187 $source_data = explode("\n", Yaml::encode($source_storage->read($source_name)));
Chris@0 188 $target_data = explode("\n", Yaml::encode($target_storage->read($target_name)));
Chris@0 189
Chris@0 190 // Check for new or removed files.
Chris@0 191 if ($source_data === ['false']) {
Chris@0 192 // Added file.
Chris@0 193 // Cast the result of t() to a string, as the diff engine doesn't know
Chris@0 194 // about objects.
Chris@0 195 $source_data = [(string) $this->t('File added')];
Chris@0 196 }
Chris@0 197 if ($target_data === ['false']) {
Chris@0 198 // Deleted file.
Chris@0 199 // Cast the result of t() to a string, as the diff engine doesn't know
Chris@0 200 // about objects.
Chris@0 201 $target_data = [(string) $this->t('File removed')];
Chris@0 202 }
Chris@0 203
Chris@0 204 return new Diff($source_data, $target_data);
Chris@0 205 }
Chris@0 206
Chris@0 207 /**
Chris@0 208 * {@inheritdoc}
Chris@0 209 */
Chris@0 210 public function createSnapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
Chris@18 211 self::replaceStorageContents($source_storage, $snapshot_storage);
Chris@0 212 }
Chris@0 213
Chris@0 214 /**
Chris@0 215 * {@inheritdoc}
Chris@0 216 */
Chris@0 217 public function uninstall($type, $name) {
Chris@0 218 $entities = $this->getConfigEntitiesToChangeOnDependencyRemoval($type, [$name], FALSE);
Chris@0 219 // Fix all dependent configuration entities.
Chris@0 220 /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
Chris@0 221 foreach ($entities['update'] as $entity) {
Chris@0 222 $entity->save();
Chris@0 223 }
Chris@0 224 // Remove all dependent configuration entities.
Chris@0 225 foreach ($entities['delete'] as $entity) {
Chris@0 226 $entity->setUninstalling(TRUE);
Chris@0 227 $entity->delete();
Chris@0 228 }
Chris@0 229
Chris@0 230 $config_names = $this->configFactory->listAll($name . '.');
Chris@0 231 foreach ($config_names as $config_name) {
Chris@0 232 $this->configFactory->getEditable($config_name)->delete();
Chris@0 233 }
Chris@0 234
Chris@0 235 // Remove any matching configuration from collections.
Chris@0 236 foreach ($this->activeStorage->getAllCollectionNames() as $collection) {
Chris@0 237 $collection_storage = $this->activeStorage->createCollection($collection);
Chris@0 238 $collection_storage->deleteAll($name . '.');
Chris@0 239 }
Chris@0 240
Chris@0 241 $schema_dir = drupal_get_path($type, $name) . '/' . InstallStorage::CONFIG_SCHEMA_DIRECTORY;
Chris@0 242 if (is_dir($schema_dir)) {
Chris@0 243 // Refresh the schema cache if uninstalling an extension that provides
Chris@0 244 // configuration schema.
Chris@0 245 $this->typedConfigManager->clearCachedDefinitions();
Chris@0 246 }
Chris@0 247 }
Chris@0 248
Chris@0 249 /**
Chris@0 250 * {@inheritdoc}
Chris@0 251 */
Chris@0 252 public function getConfigDependencyManager() {
Chris@0 253 $dependency_manager = new ConfigDependencyManager();
Chris@0 254 // Read all configuration using the factory. This ensures that multiple
Chris@0 255 // deletes during the same request benefit from the static cache. Using the
Chris@0 256 // factory also ensures configuration entity dependency discovery has no
Chris@0 257 // dependencies on the config entity classes. Assume data with UUID is a
Chris@0 258 // config entity. Only configuration entities can be depended on so we can
Chris@0 259 // ignore everything else.
Chris@0 260 $data = array_map(function ($config) {
Chris@0 261 $data = $config->get();
Chris@0 262 if (isset($data['uuid'])) {
Chris@0 263 return $data;
Chris@0 264 }
Chris@0 265 return FALSE;
Chris@0 266 }, $this->configFactory->loadMultiple($this->activeStorage->listAll()));
Chris@0 267 $dependency_manager->setData(array_filter($data));
Chris@0 268 return $dependency_manager;
Chris@0 269 }
Chris@0 270
Chris@0 271 /**
Chris@0 272 * {@inheritdoc}
Chris@0 273 */
Chris@0 274 public function findConfigEntityDependents($type, array $names, ConfigDependencyManager $dependency_manager = NULL) {
Chris@0 275 if (!$dependency_manager) {
Chris@0 276 $dependency_manager = $this->getConfigDependencyManager();
Chris@0 277 }
Chris@0 278 $dependencies = [];
Chris@0 279 foreach ($names as $name) {
Chris@0 280 $dependencies = array_merge($dependencies, $dependency_manager->getDependentEntities($type, $name));
Chris@0 281 }
Chris@0 282 return $dependencies;
Chris@0 283 }
Chris@0 284
Chris@0 285 /**
Chris@0 286 * {@inheritdoc}
Chris@0 287 */
Chris@0 288 public function findConfigEntityDependentsAsEntities($type, array $names, ConfigDependencyManager $dependency_manager = NULL) {
Chris@0 289 $dependencies = $this->findConfigEntityDependents($type, $names, $dependency_manager);
Chris@0 290 $entities = [];
Chris@18 291 $definitions = $this->entityTypeManager->getDefinitions();
Chris@0 292 foreach ($dependencies as $config_name => $dependency) {
Chris@0 293 // Group by entity type to efficient load entities using
Chris@0 294 // \Drupal\Core\Entity\EntityStorageInterface::loadMultiple().
Chris@0 295 $entity_type_id = $this->getEntityTypeIdByName($config_name);
Chris@0 296 // It is possible that a non-configuration entity will be returned if a
Chris@0 297 // simple configuration object has a UUID key. This would occur if the
Chris@0 298 // dependents of the system module are calculated since system.site has
Chris@0 299 // a UUID key.
Chris@0 300 if ($entity_type_id) {
Chris@0 301 $id = substr($config_name, strlen($definitions[$entity_type_id]->getConfigPrefix()) + 1);
Chris@0 302 $entities[$entity_type_id][] = $id;
Chris@0 303 }
Chris@0 304 }
Chris@0 305 $entities_to_return = [];
Chris@0 306 foreach ($entities as $entity_type_id => $entities_to_load) {
Chris@18 307 $storage = $this->entityTypeManager->getStorage($entity_type_id);
Chris@0 308 // Remove the keys since there are potential ID clashes from different
Chris@0 309 // configuration entity types.
Chris@0 310 $entities_to_return = array_merge($entities_to_return, array_values($storage->loadMultiple($entities_to_load)));
Chris@0 311 }
Chris@0 312 return $entities_to_return;
Chris@0 313 }
Chris@0 314
Chris@0 315 /**
Chris@0 316 * {@inheritdoc}
Chris@0 317 */
Chris@0 318 public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names, $dry_run = TRUE) {
Chris@0 319 $dependency_manager = $this->getConfigDependencyManager();
Chris@0 320
Chris@12 321 // Store the list of dependents in three separate variables. This allows us
Chris@12 322 // to determine how the dependency graph changes as entities are fixed by
Chris@12 323 // calling the onDependencyRemoval() method.
Chris@12 324
Chris@12 325 // The list of original dependents on $names. This list never changes.
Chris@12 326 $original_dependents = $this->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
Chris@12 327
Chris@12 328 // The current list of dependents on $names. This list is recalculated when
Chris@12 329 // calling an entity's onDependencyRemoval() method results in the entity
Chris@12 330 // changing. This list is passed to each entity's onDependencyRemoval()
Chris@12 331 // method as the list of affected entities.
Chris@12 332 $current_dependents = $original_dependents;
Chris@12 333
Chris@12 334 // The list of dependents to process. This list changes as entities are
Chris@12 335 // processed and are either fixed or deleted.
Chris@12 336 $dependents_to_process = $original_dependents;
Chris@12 337
Chris@12 338 // Initialize other variables.
Chris@12 339 $affected_uuids = [];
Chris@0 340 $return = [
Chris@0 341 'update' => [],
Chris@0 342 'delete' => [],
Chris@0 343 'unchanged' => [],
Chris@0 344 ];
Chris@0 345
Chris@12 346 // Try to fix the dependents and find out what will happen to the dependency
Chris@12 347 // graph. Entities are processed in the order of most dependent first. For
Chris@12 348 // example, this ensures that Menu UI third party dependencies on node types
Chris@12 349 // are fixed before processing the node type's other dependents.
Chris@12 350 while ($dependent = array_pop($dependents_to_process)) {
Chris@0 351 /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $dependent */
Chris@0 352 if ($dry_run) {
Chris@0 353 // Clone the entity so any changes do not change any static caches.
Chris@0 354 $dependent = clone $dependent;
Chris@0 355 }
Chris@0 356 $fixed = FALSE;
Chris@12 357 if ($this->callOnDependencyRemoval($dependent, $current_dependents, $type, $names)) {
Chris@0 358 // Recalculate dependencies and update the dependency graph data.
Chris@0 359 $dependent->calculateDependencies();
Chris@0 360 $dependency_manager->updateData($dependent->getConfigDependencyName(), $dependent->getDependencies());
Chris@12 361 // Based on the updated data rebuild the list of current dependents.
Chris@12 362 // This will remove entities that are no longer dependent after the
Chris@12 363 // recalculation.
Chris@12 364 $current_dependents = $this->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
Chris@12 365 // Rebuild the list of entities that we need to process using the new
Chris@12 366 // list of current dependents and removing any entities that we've
Chris@12 367 // already processed.
Chris@12 368 $dependents_to_process = array_filter($current_dependents, function ($current_dependent) use ($affected_uuids) {
Chris@12 369 return !in_array($current_dependent->uuid(), $affected_uuids);
Chris@0 370 });
Chris@12 371 // Ensure that the dependent has actually been fixed. It is possible
Chris@12 372 // that other dependencies cause it to still be in the list.
Chris@0 373 $fixed = TRUE;
Chris@12 374 foreach ($dependents_to_process as $key => $entity) {
Chris@0 375 if ($entity->uuid() == $dependent->uuid()) {
Chris@0 376 $fixed = FALSE;
Chris@12 377 unset($dependents_to_process[$key]);
Chris@0 378 break;
Chris@0 379 }
Chris@0 380 }
Chris@0 381 if ($fixed) {
Chris@12 382 $affected_uuids[] = $dependent->uuid();
Chris@0 383 $return['update'][] = $dependent;
Chris@0 384 }
Chris@0 385 }
Chris@0 386 // If the entity cannot be fixed then it has to be deleted.
Chris@0 387 if (!$fixed) {
Chris@12 388 $affected_uuids[] = $dependent->uuid();
Chris@0 389 // Deletes should occur in the order of the least dependent first. For
Chris@0 390 // example, this ensures that fields are removed before field storages.
Chris@0 391 array_unshift($return['delete'], $dependent);
Chris@0 392 }
Chris@0 393 }
Chris@12 394 // Use the list of affected UUIDs to filter the original list to work out
Chris@12 395 // which configuration entities are unchanged.
Chris@12 396 $return['unchanged'] = array_filter($original_dependents, function ($dependent) use ($affected_uuids) {
Chris@12 397 return !(in_array($dependent->uuid(), $affected_uuids));
Chris@0 398 });
Chris@0 399
Chris@0 400 return $return;
Chris@0 401 }
Chris@0 402
Chris@0 403 /**
Chris@0 404 * {@inheritdoc}
Chris@0 405 */
Chris@0 406 public function getConfigCollectionInfo() {
Chris@0 407 if (!isset($this->configCollectionInfo)) {
Chris@0 408 $this->configCollectionInfo = new ConfigCollectionInfo();
Chris@0 409 $this->eventDispatcher->dispatch(ConfigEvents::COLLECTION_INFO, $this->configCollectionInfo);
Chris@0 410 }
Chris@0 411 return $this->configCollectionInfo;
Chris@0 412 }
Chris@0 413
Chris@0 414 /**
Chris@0 415 * Calls an entity's onDependencyRemoval() method.
Chris@0 416 *
Chris@0 417 * A helper method to call onDependencyRemoval() with the correct list of
Chris@0 418 * affected entities. This list should only contain dependencies on the
Chris@0 419 * entity. Configuration and content entity dependencies will be converted
Chris@0 420 * into entity objects.
Chris@0 421 *
Chris@0 422 * @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
Chris@0 423 * The entity to call onDependencyRemoval() on.
Chris@0 424 * @param \Drupal\Core\Config\Entity\ConfigEntityInterface[] $dependent_entities
Chris@0 425 * The list of dependent configuration entities.
Chris@0 426 * @param string $type
Chris@0 427 * The type of dependency being checked. Either 'module', 'theme', 'config'
Chris@0 428 * or 'content'.
Chris@0 429 * @param array $names
Chris@0 430 * The specific names to check. If $type equals 'module' or 'theme' then it
Chris@0 431 * should be a list of module names or theme names. In the case of 'config'
Chris@0 432 * or 'content' it should be a list of configuration dependency names.
Chris@0 433 *
Chris@0 434 * @return bool
Chris@0 435 * TRUE if the entity has changed as a result of calling the
Chris@0 436 * onDependencyRemoval() method, FALSE if not.
Chris@0 437 */
Chris@0 438 protected function callOnDependencyRemoval(ConfigEntityInterface $entity, array $dependent_entities, $type, array $names) {
Chris@0 439 $entity_dependencies = $entity->getDependencies();
Chris@0 440 if (empty($entity_dependencies)) {
Chris@0 441 // No dependent entities nothing to do.
Chris@0 442 return FALSE;
Chris@0 443 }
Chris@0 444
Chris@0 445 $affected_dependencies = [
Chris@0 446 'config' => [],
Chris@0 447 'content' => [],
Chris@0 448 'module' => [],
Chris@0 449 'theme' => [],
Chris@0 450 ];
Chris@0 451
Chris@0 452 // Work out if any of the entity's dependencies are going to be affected.
Chris@0 453 if (isset($entity_dependencies[$type])) {
Chris@0 454 // Work out which dependencies the entity has in common with the provided
Chris@0 455 // $type and $names.
Chris@0 456 $affected_dependencies[$type] = array_intersect($entity_dependencies[$type], $names);
Chris@0 457
Chris@0 458 // If the dependencies are entities we need to convert them into objects.
Chris@0 459 if ($type == 'config' || $type == 'content') {
Chris@0 460 $affected_dependencies[$type] = array_map(function ($name) use ($type) {
Chris@0 461 if ($type == 'config') {
Chris@0 462 return $this->loadConfigEntityByName($name);
Chris@0 463 }
Chris@0 464 else {
Chris@0 465 // Ignore the bundle.
Chris@0 466 list($entity_type_id,, $uuid) = explode(':', $name);
Chris@18 467 return $this->entityRepository->loadEntityByConfigTarget($entity_type_id, $uuid);
Chris@0 468 }
Chris@0 469 }, $affected_dependencies[$type]);
Chris@0 470 }
Chris@0 471 }
Chris@0 472
Chris@0 473 // Merge any other configuration entities into the list of affected
Chris@0 474 // dependencies if necessary.
Chris@0 475 if (isset($entity_dependencies['config'])) {
Chris@0 476 foreach ($dependent_entities as $dependent_entity) {
Chris@0 477 if (in_array($dependent_entity->getConfigDependencyName(), $entity_dependencies['config'])) {
Chris@0 478 $affected_dependencies['config'][] = $dependent_entity;
Chris@0 479 }
Chris@0 480 }
Chris@0 481 }
Chris@0 482
Chris@0 483 // Key the entity arrays by config dependency name to make searching easy.
Chris@0 484 foreach (['config', 'content'] as $dependency_type) {
Chris@0 485 $affected_dependencies[$dependency_type] = array_combine(
Chris@0 486 array_map(function ($entity) {
Chris@0 487 return $entity->getConfigDependencyName();
Chris@0 488 }, $affected_dependencies[$dependency_type]),
Chris@0 489 $affected_dependencies[$dependency_type]
Chris@0 490 );
Chris@0 491 }
Chris@0 492
Chris@0 493 // Inform the entity.
Chris@0 494 return $entity->onDependencyRemoval($affected_dependencies);
Chris@0 495 }
Chris@0 496
Chris@0 497 /**
Chris@0 498 * {@inheritdoc}
Chris@0 499 */
Chris@0 500 public function findMissingContentDependencies() {
Chris@0 501 $content_dependencies = [];
Chris@0 502 $missing_dependencies = [];
Chris@0 503 foreach ($this->activeStorage->readMultiple($this->activeStorage->listAll()) as $config_data) {
Chris@0 504 if (isset($config_data['dependencies']['content'])) {
Chris@0 505 $content_dependencies = array_merge($content_dependencies, $config_data['dependencies']['content']);
Chris@0 506 }
Chris@0 507 if (isset($config_data['dependencies']['enforced']['content'])) {
Chris@0 508 $content_dependencies = array_merge($content_dependencies, $config_data['dependencies']['enforced']['content']);
Chris@0 509 }
Chris@0 510 }
Chris@0 511 foreach (array_unique($content_dependencies) as $content_dependency) {
Chris@0 512 // Format of the dependency is entity_type:bundle:uuid.
Chris@0 513 list($entity_type, $bundle, $uuid) = explode(':', $content_dependency, 3);
Chris@18 514 if (!$this->entityRepository->loadEntityByUuid($entity_type, $uuid)) {
Chris@0 515 $missing_dependencies[$uuid] = [
Chris@0 516 'entity_type' => $entity_type,
Chris@0 517 'bundle' => $bundle,
Chris@0 518 'uuid' => $uuid,
Chris@0 519 ];
Chris@0 520 }
Chris@0 521 }
Chris@0 522 return $missing_dependencies;
Chris@0 523 }
Chris@0 524
Chris@0 525 }