View source
<?php
namespace Drupal\Core\Config;
use Drupal\Component\Diff\Diff;
use Drupal\Core\Config\Entity\ConfigDependencyManager;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class ConfigManager implements ConfigManagerInterface {
use StringTranslationTrait;
use DeprecatedServicePropertyTrait;
use StorageCopyTrait;
protected $deprecatedProperties = [
'entityManager' => 'entity.manager',
];
protected $entityTypeManager;
protected $entityRepository;
protected $configFactory;
protected $typedConfigManager;
protected $activeStorage;
protected $eventDispatcher;
protected $configCollectionInfo;
protected $storages;
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) {
if ($entity_type_manager instanceof EntityManagerInterface) {
@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);
$this->entityTypeManager = \Drupal::entityTypeManager();
}
else {
$this->entityTypeManager = $entity_type_manager;
}
$this->configFactory = $config_factory;
$this->typedConfigManager = $typed_config_manager;
$this->stringTranslation = $string_translation;
$this->activeStorage = $active_storage;
$this->eventDispatcher = $event_dispatcher;
if ($entity_repository) {
$this->entityRepository = $entity_repository;
}
else {
@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);
$this->entityRepository = \Drupal::service('entity.repository');
}
}
public function getEntityTypeIdByName($name) {
$entities = array_filter($this->entityTypeManager
->getDefinitions(), function (EntityTypeInterface $entity_type) use ($name) {
return $entity_type instanceof ConfigEntityTypeInterface && ($config_prefix = $entity_type
->getConfigPrefix()) && strpos($name, $config_prefix . '.') === 0;
});
return key($entities);
}
public function loadConfigEntityByName($name) {
$entity_type_id = $this
->getEntityTypeIdByName($name);
if ($entity_type_id) {
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
$id = substr($name, strlen($entity_type
->getConfigPrefix()) + 1);
return $this->entityTypeManager
->getStorage($entity_type_id)
->load($id);
}
return NULL;
}
public function getEntityManager() {
@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);
return \Drupal::service('entity.manager');
}
public function getEntityTypeManager() {
return $this->entityTypeManager;
}
public function getConfigFactory() {
return $this->configFactory;
}
public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL, $collection = StorageInterface::DEFAULT_COLLECTION) {
if ($collection != StorageInterface::DEFAULT_COLLECTION) {
$source_storage = $source_storage
->createCollection($collection);
$target_storage = $target_storage
->createCollection($collection);
}
if (!isset($target_name)) {
$target_name = $source_name;
}
$source_data = explode("\n", Yaml::encode($source_storage
->read($source_name)));
$target_data = explode("\n", Yaml::encode($target_storage
->read($target_name)));
if ($source_data === [
'false',
]) {
$source_data = [
(string) $this
->t('File added'),
];
}
if ($target_data === [
'false',
]) {
$target_data = [
(string) $this
->t('File removed'),
];
}
return new Diff($source_data, $target_data);
}
public function createSnapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
self::replaceStorageContents($source_storage, $snapshot_storage);
}
public function uninstall($type, $name) {
$entities = $this
->getConfigEntitiesToChangeOnDependencyRemoval($type, [
$name,
], FALSE);
foreach ($entities['update'] as $entity) {
$entity
->save();
}
foreach ($entities['delete'] as $entity) {
$entity
->setUninstalling(TRUE);
$entity
->delete();
}
$config_names = $this->configFactory
->listAll($name . '.');
foreach ($config_names as $config_name) {
$this->configFactory
->getEditable($config_name)
->delete();
}
foreach ($this->activeStorage
->getAllCollectionNames() as $collection) {
$collection_storage = $this->activeStorage
->createCollection($collection);
$collection_storage
->deleteAll($name . '.');
}
$schema_dir = drupal_get_path($type, $name) . '/' . InstallStorage::CONFIG_SCHEMA_DIRECTORY;
if (is_dir($schema_dir)) {
$this->typedConfigManager
->clearCachedDefinitions();
}
}
public function getConfigDependencyManager() {
$dependency_manager = new ConfigDependencyManager();
$data = array_map(function ($config) {
$data = $config
->get();
if (isset($data['uuid'])) {
return $data;
}
return FALSE;
}, $this->configFactory
->loadMultiple($this->activeStorage
->listAll()));
$dependency_manager
->setData(array_filter($data));
return $dependency_manager;
}
public function findConfigEntityDependents($type, array $names, ConfigDependencyManager $dependency_manager = NULL) {
if (!$dependency_manager) {
$dependency_manager = $this
->getConfigDependencyManager();
}
$dependencies = [];
foreach ($names as $name) {
$dependencies = array_merge($dependencies, $dependency_manager
->getDependentEntities($type, $name));
}
return $dependencies;
}
public function findConfigEntityDependentsAsEntities($type, array $names, ConfigDependencyManager $dependency_manager = NULL) {
$dependencies = $this
->findConfigEntityDependents($type, $names, $dependency_manager);
$entities = [];
$definitions = $this->entityTypeManager
->getDefinitions();
foreach ($dependencies as $config_name => $dependency) {
$entity_type_id = $this
->getEntityTypeIdByName($config_name);
if ($entity_type_id) {
$id = substr($config_name, strlen($definitions[$entity_type_id]
->getConfigPrefix()) + 1);
$entities[$entity_type_id][] = $id;
}
}
$entities_to_return = [];
foreach ($entities as $entity_type_id => $entities_to_load) {
$storage = $this->entityTypeManager
->getStorage($entity_type_id);
$entities_to_return = array_merge($entities_to_return, array_values($storage
->loadMultiple($entities_to_load)));
}
return $entities_to_return;
}
public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names, $dry_run = TRUE) {
$dependency_manager = $this
->getConfigDependencyManager();
$original_dependents = $this
->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
$current_dependents = $original_dependents;
$dependents_to_process = $original_dependents;
$affected_uuids = [];
$return = [
'update' => [],
'delete' => [],
'unchanged' => [],
];
while ($dependent = array_pop($dependents_to_process)) {
if ($dry_run) {
$dependent = clone $dependent;
}
$fixed = FALSE;
if ($this
->callOnDependencyRemoval($dependent, $current_dependents, $type, $names)) {
$dependent
->calculateDependencies();
$dependency_manager
->updateData($dependent
->getConfigDependencyName(), $dependent
->getDependencies());
$current_dependents = $this
->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
$dependents_to_process = array_filter($current_dependents, function ($current_dependent) use ($affected_uuids) {
return !in_array($current_dependent
->uuid(), $affected_uuids);
});
$fixed = TRUE;
foreach ($dependents_to_process as $key => $entity) {
if ($entity
->uuid() == $dependent
->uuid()) {
$fixed = FALSE;
unset($dependents_to_process[$key]);
break;
}
}
if ($fixed) {
$affected_uuids[] = $dependent
->uuid();
$return['update'][] = $dependent;
}
}
if (!$fixed) {
$affected_uuids[] = $dependent
->uuid();
array_unshift($return['delete'], $dependent);
}
}
$return['unchanged'] = array_filter($original_dependents, function ($dependent) use ($affected_uuids) {
return !in_array($dependent
->uuid(), $affected_uuids);
});
return $return;
}
public function getConfigCollectionInfo() {
if (!isset($this->configCollectionInfo)) {
$this->configCollectionInfo = new ConfigCollectionInfo();
$this->eventDispatcher
->dispatch(ConfigEvents::COLLECTION_INFO, $this->configCollectionInfo);
}
return $this->configCollectionInfo;
}
protected function callOnDependencyRemoval(ConfigEntityInterface $entity, array $dependent_entities, $type, array $names) {
$entity_dependencies = $entity
->getDependencies();
if (empty($entity_dependencies)) {
return FALSE;
}
$affected_dependencies = [
'config' => [],
'content' => [],
'module' => [],
'theme' => [],
];
if (isset($entity_dependencies[$type])) {
$affected_dependencies[$type] = array_intersect($entity_dependencies[$type], $names);
if ($type == 'config' || $type == 'content') {
$affected_dependencies[$type] = array_map(function ($name) use ($type) {
if ($type == 'config') {
return $this
->loadConfigEntityByName($name);
}
else {
list($entity_type_id, , $uuid) = explode(':', $name);
return $this->entityRepository
->loadEntityByConfigTarget($entity_type_id, $uuid);
}
}, $affected_dependencies[$type]);
}
}
if (isset($entity_dependencies['config'])) {
foreach ($dependent_entities as $dependent_entity) {
if (in_array($dependent_entity
->getConfigDependencyName(), $entity_dependencies['config'])) {
$affected_dependencies['config'][] = $dependent_entity;
}
}
}
foreach ([
'config',
'content',
] as $dependency_type) {
$affected_dependencies[$dependency_type] = array_combine(array_map(function ($entity) {
return $entity
->getConfigDependencyName();
}, $affected_dependencies[$dependency_type]), $affected_dependencies[$dependency_type]);
}
return $entity
->onDependencyRemoval($affected_dependencies);
}
public function findMissingContentDependencies() {
$content_dependencies = [];
$missing_dependencies = [];
foreach ($this->activeStorage
->readMultiple($this->activeStorage
->listAll()) as $config_data) {
if (isset($config_data['dependencies']['content'])) {
$content_dependencies = array_merge($content_dependencies, $config_data['dependencies']['content']);
}
if (isset($config_data['dependencies']['enforced']['content'])) {
$content_dependencies = array_merge($content_dependencies, $config_data['dependencies']['enforced']['content']);
}
}
foreach (array_unique($content_dependencies) as $content_dependency) {
list($entity_type, $bundle, $uuid) = explode(':', $content_dependency, 3);
if (!$this->entityRepository
->loadEntityByUuid($entity_type, $uuid)) {
$missing_dependencies[$uuid] = [
'entity_type' => $entity_type,
'bundle' => $bundle,
'uuid' => $uuid,
];
}
}
return $missing_dependencies;
}
}