class ConfigManager in Drupal 9
Same name and namespace in other branches
- 8 core/lib/Drupal/Core/Config/ConfigManager.php \Drupal\Core\Config\ConfigManager
The ConfigManager provides helper functions for the configuration system.
Hierarchy
- class \Drupal\Core\Config\ConfigManager implements ConfigManagerInterface uses StorageCopyTrait, StringTranslationTrait
Expanded class hierarchy of ConfigManager
1 string reference to 'ConfigManager'
- core.services.yml in core/
core.services.yml - core/core.services.yml
1 service uses ConfigManager
File
- core/
lib/ Drupal/ Core/ Config/ ConfigManager.php, line 21
Namespace
Drupal\Core\ConfigView source
class ConfigManager implements ConfigManagerInterface {
use StringTranslationTrait;
use StorageCopyTrait;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity repository.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* The configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The typed config manager.
*
* @var \Drupal\Core\Config\TypedConfigManagerInterface
*/
protected $typedConfigManager;
/**
* The active configuration storage.
*
* @var \Drupal\Core\Config\StorageInterface
*/
protected $activeStorage;
/**
* The event dispatcher.
*
* @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* The configuration collection info.
*
* @var \Drupal\Core\Config\ConfigCollectionInfo
*/
protected $configCollectionInfo;
/**
* The configuration storages keyed by collection name.
*
* @var \Drupal\Core\Config\StorageInterface[]
*/
protected $storages;
/**
* The extension path resolver.
*
* @var \Drupal\Core\Extension\ExtensionPathResolver
*/
protected $extensionPathResolver;
/**
* Creates ConfigManager objects.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
* The typed config manager.
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
* The string translation service.
* @param \Drupal\Core\Config\StorageInterface $active_storage
* The active configuration storage.
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Extension\ExtensionPathResolver $extension_path_resolver
* The extension path resolver.
*/
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, ExtensionPathResolver $extension_path_resolver = NULL) {
$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;
$this->entityRepository = $entity_repository;
if (!$extension_path_resolver) {
@trigger_error('Calling ConfigManager::__construct without the $extension_path_resolver argument is deprecated in drupal:9.3.0 and is required in drupal:10.0.0. See https://www.drupal.org/node/2940438', E_USER_DEPRECATED);
$extension_path_resolver = \Drupal::service('extension.path.resolver');
}
$this->extensionPathResolver = $extension_path_resolver;
}
/**
* {@inheritdoc}
*/
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);
}
/**
* {@inheritdoc}
*/
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;
}
/**
* {@inheritdoc}
*/
public function getEntityTypeManager() {
return $this->entityTypeManager;
}
/**
* {@inheritdoc}
*/
public function getConfigFactory() {
return $this->configFactory;
}
/**
* {@inheritdoc}
*/
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;
}
// The output should show configuration object differences formatted as YAML.
// But the configuration is not necessarily stored in files. Therefore, they
// need to be read and parsed, and lastly, dumped into YAML strings.
$source_data = explode("\n", Yaml::encode($source_storage
->read($source_name)));
$target_data = explode("\n", Yaml::encode($target_storage
->read($target_name)));
// Check for new or removed files.
if ($source_data === [
'false',
]) {
// Added file.
// Cast the result of t() to a string, as the diff engine doesn't know
// about objects.
$source_data = [
(string) $this
->t('File added'),
];
}
if ($target_data === [
'false',
]) {
// Deleted file.
// Cast the result of t() to a string, as the diff engine doesn't know
// about objects.
$target_data = [
(string) $this
->t('File removed'),
];
}
return new Diff($source_data, $target_data);
}
/**
* {@inheritdoc}
*/
public function createSnapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
self::replaceStorageContents($source_storage, $snapshot_storage);
}
/**
* {@inheritdoc}
*/
public function uninstall($type, $name) {
$entities = $this
->getConfigEntitiesToChangeOnDependencyRemoval($type, [
$name,
], FALSE);
// Fix all dependent configuration entities.
/** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
foreach ($entities['update'] as $entity) {
$entity
->save();
}
// Remove all dependent configuration entities.
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();
}
// Remove any matching configuration from collections.
foreach ($this->activeStorage
->getAllCollectionNames() as $collection) {
$collection_storage = $this->activeStorage
->createCollection($collection);
$collection_storage
->deleteAll($name . '.');
}
$schema_dir = $this->extensionPathResolver
->getPath($type, $name) . '/' . InstallStorage::CONFIG_SCHEMA_DIRECTORY;
if (is_dir($schema_dir)) {
// Refresh the schema cache if uninstalling an extension that provides
// configuration schema.
$this->typedConfigManager
->clearCachedDefinitions();
}
}
/**
* {@inheritdoc}
*/
public function getConfigDependencyManager() {
$dependency_manager = new ConfigDependencyManager();
// Read all configuration using the factory. This ensures that multiple
// deletes during the same request benefit from the static cache. Using the
// factory also ensures configuration entity dependency discovery has no
// dependencies on the config entity classes. Assume data with UUID is a
// config entity. Only configuration entities can be depended on so we can
// ignore everything else.
$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;
}
/**
* {@inheritdoc}
*/
public function findConfigEntityDependencies($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;
}
/**
* {@inheritdoc}
*/
public function findConfigEntityDependenciesAsEntities($type, array $names, ConfigDependencyManager $dependency_manager = NULL) {
$dependencies = $this
->findConfigEntityDependencies($type, $names, $dependency_manager);
$entities = [];
$definitions = $this->entityTypeManager
->getDefinitions();
foreach ($dependencies as $config_name => $dependency) {
// Group by entity type to efficient load entities using
// \Drupal\Core\Entity\EntityStorageInterface::loadMultiple().
$entity_type_id = $this
->getEntityTypeIdByName($config_name);
// It is possible that a non-configuration entity will be returned if a
// simple configuration object has a UUID key. This would occur if the
// dependents of the system module are calculated since system.site has
// a UUID key.
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);
// Remove the keys since there are potential ID clashes from different
// configuration entity types.
$entities_to_return = array_merge($entities_to_return, array_values($storage
->loadMultiple($entities_to_load)));
}
return $entities_to_return;
}
/**
* {@inheritdoc}
*/
public function findConfigEntityDependents($type, array $names, ConfigDependencyManager $dependency_manager = NULL) {
@trigger_error('ConfigManagerInterface::findConfigEntityDependents() is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Instead you should use ConfigManagerInterface::findConfigEntityDependencies(). See https://www.drupal.org/node/3225357', E_USER_DEPRECATED);
return $this
->findConfigEntityDependencies($type, $names, $dependency_manager);
}
/**
* {@inheritdoc}
*/
public function findConfigEntityDependentsAsEntities($type, array $names, ConfigDependencyManager $dependency_manager = NULL) {
@trigger_error('ConfigManagerInterface::findConfigEntityDependentsAsEntities() is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Instead you should use ConfigManagerInterface::findConfigEntityDependenciesAsEntities(). See https://www.drupal.org/node/3225357', E_USER_DEPRECATED);
return $this
->findConfigEntityDependenciesAsEntities($type, $names, $dependency_manager);
}
/**
* {@inheritdoc}
*/
public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names, $dry_run = TRUE) {
$dependency_manager = $this
->getConfigDependencyManager();
// Store the list of dependents in three separate variables. This allows us
// to determine how the dependency graph changes as entities are fixed by
// calling the onDependencyRemoval() method.
// The list of original dependents on $names. This list never changes.
$original_dependents = $this
->findConfigEntityDependenciesAsEntities($type, $names, $dependency_manager);
// The current list of dependents on $names. This list is recalculated when
// calling an entity's onDependencyRemoval() method results in the entity
// changing. This list is passed to each entity's onDependencyRemoval()
// method as the list of affected entities.
$current_dependents = $original_dependents;
// The list of dependents to process. This list changes as entities are
// processed and are either fixed or deleted.
$dependents_to_process = $original_dependents;
// Initialize other variables.
$affected_uuids = [];
$return = [
'update' => [],
'delete' => [],
'unchanged' => [],
];
// Try to fix the dependents and find out what will happen to the dependency
// graph. Entities are processed in the order of most dependent first. For
// example, this ensures that Menu UI third party dependencies on node types
// are fixed before processing the node type's other dependents.
while ($dependent = array_pop($dependents_to_process)) {
/** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $dependent */
if ($dry_run) {
// Clone the entity so any changes do not change any static caches.
$dependent = clone $dependent;
}
$fixed = FALSE;
if ($this
->callOnDependencyRemoval($dependent, $current_dependents, $type, $names)) {
// Recalculate dependencies and update the dependency graph data.
$dependent
->calculateDependencies();
$dependency_manager
->updateData($dependent
->getConfigDependencyName(), $dependent
->getDependencies());
// Based on the updated data rebuild the list of current dependents.
// This will remove entities that are no longer dependent after the
// recalculation.
$current_dependents = $this
->findConfigEntityDependenciesAsEntities($type, $names, $dependency_manager);
// Rebuild the list of entities that we need to process using the new
// list of current dependents and removing any entities that we've
// already processed.
$dependents_to_process = array_filter($current_dependents, function ($current_dependent) use ($affected_uuids) {
return !in_array($current_dependent
->uuid(), $affected_uuids);
});
// Ensure that the dependent has actually been fixed. It is possible
// that other dependencies cause it to still be in the list.
$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 the entity cannot be fixed then it has to be deleted.
if (!$fixed) {
$affected_uuids[] = $dependent
->uuid();
// Deletes should occur in the order of the least dependent first. For
// example, this ensures that fields are removed before field storages.
array_unshift($return['delete'], $dependent);
}
}
// Use the list of affected UUIDs to filter the original list to work out
// which configuration entities are unchanged.
$return['unchanged'] = array_filter($original_dependents, function ($dependent) use ($affected_uuids) {
return !in_array($dependent
->uuid(), $affected_uuids);
});
return $return;
}
/**
* {@inheritdoc}
*/
public function getConfigCollectionInfo() {
if (!isset($this->configCollectionInfo)) {
$this->configCollectionInfo = new ConfigCollectionInfo();
$this->eventDispatcher
->dispatch($this->configCollectionInfo, ConfigEvents::COLLECTION_INFO);
}
return $this->configCollectionInfo;
}
/**
* Calls an entity's onDependencyRemoval() method.
*
* A helper method to call onDependencyRemoval() with the correct list of
* affected entities. This list should only contain dependencies on the
* entity. Configuration and content entity dependencies will be converted
* into entity objects.
*
* @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
* The entity to call onDependencyRemoval() on.
* @param \Drupal\Core\Config\Entity\ConfigEntityInterface[] $dependent_entities
* The list of dependent configuration entities.
* @param string $type
* The type of dependency being checked. Either 'module', 'theme', 'config'
* or 'content'.
* @param array $names
* The specific names to check. If $type equals 'module' or 'theme' then it
* should be a list of module names or theme names. In the case of 'config'
* or 'content' it should be a list of configuration dependency names.
*
* @return bool
* TRUE if the entity has changed as a result of calling the
* onDependencyRemoval() method, FALSE if not.
*/
protected function callOnDependencyRemoval(ConfigEntityInterface $entity, array $dependent_entities, $type, array $names) {
$entity_dependencies = $entity
->getDependencies();
if (empty($entity_dependencies)) {
// No dependent entities nothing to do.
return FALSE;
}
$affected_dependencies = [
'config' => [],
'content' => [],
'module' => [],
'theme' => [],
];
// Work out if any of the entity's dependencies are going to be affected.
if (isset($entity_dependencies[$type])) {
// Work out which dependencies the entity has in common with the provided
// $type and $names.
$affected_dependencies[$type] = array_intersect($entity_dependencies[$type], $names);
// If the dependencies are entities we need to convert them into objects.
if ($type == 'config' || $type == 'content') {
$affected_dependencies[$type] = array_map(function ($name) use ($type) {
if ($type == 'config') {
return $this
->loadConfigEntityByName($name);
}
else {
// Ignore the bundle.
list($entity_type_id, , $uuid) = explode(':', $name);
return $this->entityRepository
->loadEntityByConfigTarget($entity_type_id, $uuid);
}
}, $affected_dependencies[$type]);
}
}
// Merge any other configuration entities into the list of affected
// dependencies if necessary.
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;
}
}
}
// Key the entity arrays by config dependency name to make searching easy.
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]);
}
// Inform the entity.
return $entity
->onDependencyRemoval($affected_dependencies);
}
/**
* {@inheritdoc}
*/
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) {
// Format of the dependency is entity_type:bundle:uuid.
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;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ConfigManager:: |
protected | property | The active configuration storage. | |
ConfigManager:: |
protected | property | The configuration collection info. | |
ConfigManager:: |
protected | property | The configuration factory. | |
ConfigManager:: |
protected | property | The entity repository. | |
ConfigManager:: |
protected | property | The entity type manager. | |
ConfigManager:: |
protected | property | The event dispatcher. | |
ConfigManager:: |
protected | property | The extension path resolver. | |
ConfigManager:: |
protected | property | The configuration storages keyed by collection name. | |
ConfigManager:: |
protected | property | The typed config manager. | |
ConfigManager:: |
protected | function | Calls an entity's onDependencyRemoval() method. | |
ConfigManager:: |
public | function |
Creates a configuration snapshot following a successful import. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Creates a Diff object using the config data from the two storages. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Finds config entities that are dependent on extensions or entities. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Finds config entities that are dependent on extensions or entities. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Deprecated method to find config entity dependencies. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Deprecated method to find config entity dependencies as entities. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Finds missing content dependencies declared in configuration entities. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Gets available collection information using the event system. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Creates and populates a ConfigDependencyManager object. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Lists which config entities to update and delete on removal of a dependency. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Gets the config factory. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Returns the entity type of a configuration object. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Gets the entity type manager. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Loads a configuration entity using the configuration name. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function |
Uninstalls the configuration of a given extension. Overrides ConfigManagerInterface:: |
|
ConfigManager:: |
public | function | Creates ConfigManager objects. | |
StorageCopyTrait:: |
protected static | function | Copy the configuration from one storage to another and remove stale items. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |