3 namespace Drupal\Core\Config;
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Core\Cache\Cache;
7 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
8 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
11 * Defines the configuration object factory.
13 * The configuration object factory instantiates a Config object for each
14 * configuration object name that is accessed and returns it to callers.
16 * @see \Drupal\Core\Config\Config
18 * Each configuration object gets a storage object injected, which
19 * is used for reading and writing the configuration data.
21 * @see \Drupal\Core\Config\StorageInterface
25 class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface {
28 * A storage instance for reading and writing configuration data.
30 * @var \Drupal\Core\Config\StorageInterface
35 * An event dispatcher instance to use for configuration events.
37 * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
39 protected $eventDispatcher;
42 * Cached configuration objects.
44 * @var \Drupal\Core\Config\Config[]
46 protected $cache = [];
49 * The typed config manager.
51 * @var \Drupal\Core\Config\TypedConfigManagerInterface
53 protected $typedConfigManager;
56 * An array of config factory override objects ordered by priority.
58 * @var \Drupal\Core\Config\ConfigFactoryOverrideInterface[]
60 protected $configFactoryOverrides = [];
63 * Constructs the Config factory.
65 * @param \Drupal\Core\Config\StorageInterface $storage
66 * The configuration storage engine.
67 * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
68 * An event dispatcher instance to use for configuration events.
69 * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
70 * The typed configuration manager.
72 public function __construct(StorageInterface $storage, EventDispatcherInterface $event_dispatcher, TypedConfigManagerInterface $typed_config) {
73 $this->storage = $storage;
74 $this->eventDispatcher = $event_dispatcher;
75 $this->typedConfigManager = $typed_config;
81 public function getEditable($name) {
82 return $this->doGet($name, FALSE);
88 public function get($name) {
89 return $this->doGet($name);
93 * Returns a configuration object for a given name.
96 * The name of the configuration object to construct.
97 * @param bool $immutable
98 * (optional) Create an immutable configuration object. Defaults to TRUE.
100 * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
101 * A configuration object.
103 protected function doGet($name, $immutable = TRUE) {
104 if ($config = $this->doLoadMultiple([$name], $immutable)) {
105 return $config[$name];
108 // If the configuration object does not exist in the configuration
109 // storage, create a new object.
110 $config = $this->createConfigObject($name, $immutable);
113 // Get and apply any overrides.
114 $overrides = $this->loadOverrides([$name]);
115 if (isset($overrides[$name])) {
116 $config->setModuleOverride($overrides[$name]);
118 // Apply any settings.php overrides.
119 if (isset($GLOBALS['config'][$name])) {
120 $config->setSettingsOverride($GLOBALS['config'][$name]);
124 foreach ($this->configFactoryOverrides as $override) {
125 $config->addCacheableDependency($override->getCacheableMetadata($name));
135 public function loadMultiple(array $names) {
136 return $this->doLoadMultiple($names);
140 * Returns a list of configuration objects for the given names.
142 * @param array $names
143 * List of names of configuration objects.
144 * @param bool $immutable
145 * (optional) Create an immutable configuration objects. Defaults to TRUE.
147 * @return \Drupal\Core\Config\Config[]|\Drupal\Core\Config\ImmutableConfig[]
148 * List of successfully loaded configuration objects, keyed by name.
150 protected function doLoadMultiple(array $names, $immutable = TRUE) {
153 foreach ($names as $key => $name) {
154 $cache_key = $this->getConfigCacheKey($name, $immutable);
155 if (isset($this->cache[$cache_key])) {
156 $list[$name] = $this->cache[$cache_key];
161 // Pre-load remaining configuration files.
162 if (!empty($names)) {
163 // Initialise override information.
164 $module_overrides = [];
165 $storage_data = $this->storage->readMultiple($names);
167 if ($immutable && !empty($storage_data)) {
168 // Only get module overrides if we have configuration to override.
169 $module_overrides = $this->loadOverrides($names);
172 foreach ($storage_data as $name => $data) {
173 $cache_key = $this->getConfigCacheKey($name, $immutable);
175 $this->cache[$cache_key] = $this->createConfigObject($name, $immutable);
176 $this->cache[$cache_key]->initWithData($data);
178 if (isset($module_overrides[$name])) {
179 $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]);
181 if (isset($GLOBALS['config'][$name])) {
182 $this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
186 $this->propagateConfigOverrideCacheability($cache_key, $name);
188 $list[$name] = $this->cache[$cache_key];
196 * Get arbitrary overrides for the named configuration objects from modules.
198 * @param array $names
199 * The names of the configuration objects to get overrides for.
202 * An array of overrides keyed by the configuration object name.
204 protected function loadOverrides(array $names) {
206 foreach ($this->configFactoryOverrides as $override) {
207 // Existing overrides take precedence since these will have been added
208 // by events with a higher priority.
209 $overrides = NestedArray::mergeDeepArray([$override->loadOverrides($names), $overrides], TRUE);
215 * Propagates cacheability of config overrides to cached config objects.
217 * @param string $cache_key
218 * The key of the cached config object to update.
219 * @param string $name
220 * The name of the configuration object to construct.
222 protected function propagateConfigOverrideCacheability($cache_key, $name) {
223 foreach ($this->configFactoryOverrides as $override) {
224 $this->cache[$cache_key]->addCacheableDependency($override->getCacheableMetadata($name));
231 public function reset($name = NULL) {
233 // Clear all cached configuration for this name.
234 foreach ($this->getConfigCacheKeys($name) as $cache_key) {
235 unset($this->cache[$cache_key]);
242 // Clear the static list cache if supported by the storage.
243 if ($this->storage instanceof StorageCacheInterface) {
244 $this->storage->resetListCache();
252 public function rename($old_name, $new_name) {
253 Cache::invalidateTags($this->get($old_name)->getCacheTags());
254 $this->storage->rename($old_name, $new_name);
256 // Clear out the static cache of any references to the old name.
257 foreach ($this->getConfigCacheKeys($old_name) as $old_cache_key) {
258 unset($this->cache[$old_cache_key]);
261 // Prime the cache and load the configuration with the correct overrides.
262 $config = $this->get($new_name);
263 $this->eventDispatcher->dispatch(ConfigEvents::RENAME, new ConfigRenameEvent($config, $old_name));
270 public function getCacheKeys() {
271 // Because get() adds overrides both from $GLOBALS and from
272 // $this->configFactoryOverrides, add cache keys for each.
273 $keys[] = 'global_overrides';
274 foreach ($this->configFactoryOverrides as $override) {
275 $keys[] = $override->getCacheSuffix();
281 * Gets the static cache key for a given config name.
283 * @param string $name
284 * The name of the configuration object.
285 * @param bool $immutable
286 * Whether or not the object is mutable.
291 protected function getConfigCacheKey($name, $immutable) {
294 $suffix = ':' . implode(':', $this->getCacheKeys());
296 return $name . $suffix;
300 * Gets all the cache keys that match the provided config name.
302 * @param string $name
303 * The name of the configuration object.
306 * An array of cache keys that match the provided config name.
308 protected function getConfigCacheKeys($name) {
309 return array_filter(array_keys($this->cache), function ($key) use ($name) {
310 // Return TRUE if the key is the name or starts with the configuration
311 // name plus the delimiter.
312 return $key === $name || strpos($key, $name . ':') === 0;
319 public function clearStaticCache() {
327 public function listAll($prefix = '') {
328 return $this->storage->listAll($prefix);
332 * Updates stale static cache entries when configuration is saved.
334 * @param ConfigCrudEvent $event
335 * The configuration event.
337 public function onConfigSave(ConfigCrudEvent $event) {
338 // Ensure that the static cache contains up to date configuration objects by
339 // replacing the data on any entries for the configuration object apart
340 // from the one that references the actual config object being saved.
341 $saved_config = $event->getConfig();
342 foreach ($this->getConfigCacheKeys($saved_config->getName()) as $cache_key) {
343 $cached_config = $this->cache[$cache_key];
344 if ($cached_config !== $saved_config) {
345 // We can not just update the data since other things about the object
346 // might have changed. For example, whether or not it is new.
347 $this->cache[$cache_key]->initWithData($saved_config->getRawData());
353 * Removes stale static cache entries when configuration is deleted.
355 * @param \Drupal\Core\Config\ConfigCrudEvent $event
356 * The configuration event.
358 public function onConfigDelete(ConfigCrudEvent $event) {
359 // Ensure that the static cache does not contain deleted configuration.
360 foreach ($this->getConfigCacheKeys($event->getConfig()->getName()) as $cache_key) {
361 unset($this->cache[$cache_key]);
368 public static function getSubscribedEvents() {
369 $events[ConfigEvents::SAVE][] = ['onConfigSave', 255];
370 $events[ConfigEvents::DELETE][] = ['onConfigDelete', 255];
377 public function addOverride(ConfigFactoryOverrideInterface $config_factory_override) {
378 $this->configFactoryOverrides[] = $config_factory_override;
382 * Creates a configuration object.
384 * @param string $name
385 * Configuration object name.
386 * @param bool $immutable
387 * Determines whether a mutable or immutable config object is returned.
389 * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
390 * The configuration object.
392 protected function createConfigObject($name, $immutable) {
394 return new ImmutableConfig($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
396 return new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);