ConfigFactory.php 9.78 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5
 * Contains \Drupal\Core\Config\ConfigFactory.
6 7 8 9
 */

namespace Drupal\Core\Config;

10
use Drupal\Component\Utility\NestedArray;
11
use Drupal\Core\Cache\Cache;
12
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
13
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
14

15 16 17 18 19 20
/**
 * Defines the configuration object factory.
 *
 * The configuration object factory instantiates a Config object for each
 * configuration object name that is accessed and returns it to callers.
 *
21
 * @see \Drupal\Core\Config\Config
22
 *
23
 * Each configuration object gets a storage object injected, which
24
 * is used for reading and writing the configuration data.
25
 *
26
 * @see \Drupal\Core\Config\StorageInterface
27 28
 *
 * @ingroup config_api
29
 */
30
class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface {
31

32
  /**
33
   * A storage instance for reading and writing configuration data.
34
   *
35
   * @var \Drupal\Core\Config\StorageInterface
36
   */
37
  protected $storage;
38

39
  /**
40 41
   * An event dispatcher instance to use for configuration events.
   *
42
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
43 44 45 46 47 48 49 50 51 52
   */
  protected $eventDispatcher;

  /**
   * A flag indicating if we should use overrides.
   *
   * @var boolean
   */
  protected $useOverrides = TRUE;

53 54 55
  /**
   * Cached configuration objects.
   *
56
   * @var \Drupal\Core\Config\Config[]
57 58 59
   */
  protected $cache = array();

60 61 62
  /**
   * The typed config manager.
   *
63
   * @var \Drupal\Core\Config\TypedConfigManagerInterface
64 65 66
   */
  protected $typedConfigManager;

67 68 69 70 71 72 73
  /**
   * An array of config factory override objects ordered by priority.
   *
   * @var \Drupal\Core\Config\ConfigFactoryOverrideInterface[]
   */
  protected $configFactoryOverrides = array();

74 75 76
  /**
   * Constructs the Config factory.
   *
77
   * @param \Drupal\Core\Config\StorageInterface $storage
78
   *   The configuration storage engine.
79
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
80
   *   An event dispatcher instance to use for configuration events.
81
   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
82
   *   The typed configuration manager.
83
   */
84
  public function __construct(StorageInterface $storage, EventDispatcherInterface $event_dispatcher, TypedConfigManagerInterface $typed_config) {
85
    $this->storage = $storage;
86
    $this->eventDispatcher = $event_dispatcher;
87
    $this->typedConfigManager = $typed_config;
88 89 90
  }

  /**
91
   * {@inheritdoc}
92
   */
93 94
  public function setOverrideState($state) {
    $this->useOverrides = $state;
95 96 97 98
    return $this;
  }

  /**
99
   * {@inheritdoc}
100
   */
101 102
  public function getOverrideState() {
    return $this->useOverrides;
103 104 105
  }

  /**
106
   * {@inheritdoc}
107 108
   */
  public function get($name) {
109 110
    if ($config = $this->loadMultiple(array($name))) {
      return $config[$name];
111
    }
112
    else {
113 114
      // If the configuration object does not exist in the configuration
      // storage, create a new object and add it to the static cache.
115
      $cache_key = $this->getConfigCacheKey($name);
116
      $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
117

118 119 120 121 122 123 124 125 126
      if ($this->useOverrides) {
        // Get and apply any overrides.
        $overrides = $this->loadOverrides(array($name));
        if (isset($overrides[$name])) {
          $this->cache[$cache_key]->setModuleOverride($overrides[$name]);
        }
        // Apply any settings.php overrides.
        if (isset($GLOBALS['config'][$name])) {
          $this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
127 128 129 130
        }
      }
      return $this->cache[$cache_key];
    }
131
  }
132

133
  /**
134
   * {@inheritdoc}
135 136 137
   */
  public function loadMultiple(array $names) {
    $list = array();
138

139
    foreach ($names as $key => $name) {
140
      $cache_key = $this->getConfigCacheKey($name);
141
      if (isset($this->cache[$cache_key])) {
142 143 144 145 146 147 148
        $list[$name] = $this->cache[$cache_key];
        unset($names[$key]);
      }
    }

    // Pre-load remaining configuration files.
    if (!empty($names)) {
149 150
      // Initialise override information.
      $module_overrides = array();
151
      $storage_data = $this->storage->readMultiple($names);
152 153

      if ($this->useOverrides && !empty($storage_data)) {
154 155
        // Only get module overrides if we have configuration to override.
        $module_overrides = $this->loadOverrides($names);
156 157
      }

158
      foreach ($storage_data as $name => $data) {
159
        $cache_key = $this->getConfigCacheKey($name);
160

161
        $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
162
        $this->cache[$cache_key]->initWithData($data);
163
        if ($this->useOverrides) {
164 165 166
          if (isset($module_overrides[$name])) {
            $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]);
          }
167 168
          if (isset($GLOBALS['config'][$name])) {
            $this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
169 170
          }
        }
171 172 173
        $list[$name] = $this->cache[$cache_key];
      }
    }
174

175 176 177
    return $list;
  }

178 179 180 181 182 183 184 185 186
  /**
   * Get arbitrary overrides for the named configuration objects from modules.
   *
   * @param array $names
   *   The names of the configuration objects to get overrides for.
   *
   * @return array
   *   An array of overrides keyed by the configuration object name.
   */
187
  protected function loadOverrides(array $names) {
188 189 190 191 192 193 194
    $overrides = array();
    foreach ($this->configFactoryOverrides as $override) {
      // Existing overrides take precedence since these will have been added
      // by events with a higher priority.
      $overrides = NestedArray::mergeDeepArray(array($override->loadOverrides($names), $overrides), TRUE);
    }
    return $overrides;
195 196
  }

197
  /**
198
   * {@inheritdoc}
199 200 201
   */
  public function reset($name = NULL) {
    if ($name) {
202
      // Clear all cached configuration for this name.
203
      foreach ($this->getConfigCacheKeys($name) as $cache_key) {
204
        unset($this->cache[$cache_key]);
205 206 207
      }
    }
    else {
208
      $this->cache = array();
209
    }
210 211 212 213 214

    // Clear the static list cache if supported by the storage.
    if ($this->storage instanceof StorageCacheInterface) {
      $this->storage->resetListCache();
    }
215
    return $this;
216 217 218
  }

  /**
219
   * {@inheritdoc}
220 221
   */
  public function rename($old_name, $new_name) {
222
    Cache::invalidateTags($this->get($old_name)->getCacheTags());
223
    $this->storage->rename($old_name, $new_name);
224 225 226

    // Clear out the static cache of any references to the old name.
    foreach ($this->getConfigCacheKeys($old_name) as $old_cache_key) {
227 228
      unset($this->cache[$old_cache_key]);
    }
229

230 231 232 233
    // Prime the cache and load the configuration with the correct overrides.
    $config = $this->get($new_name);
    $this->eventDispatcher->dispatch(ConfigEvents::RENAME, new ConfigRenameEvent($config, $old_name));
    return $config;
234 235 236
  }

  /**
237
   * {@inheritdoc}
238
   */
239 240
  public function getCacheKeys() {
    $keys = array();
241
    if ($this->useOverrides) {
242 243 244
      // Because get() adds overrides both from $GLOBALS and from
      // $this->configFactoryOverrides, add cache keys for each.
      $keys[] = 'global_overrides';
245
      foreach($this->configFactoryOverrides as $override) {
246
        $keys[] =  $override->getCacheSuffix();
247 248
      }
    }
249
    return $keys;
250
  }
251

252
  /**
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
   * Gets the cache key for a given config name.
   *
   * @param string $name
   *   The name of the configuration object.
   *
   * @return string
   *   The cache key.
   */
  protected function getConfigCacheKey($name) {
    return $name . ':' . implode(':', $this->getCacheKeys());
  }

  /**
   * Gets all the cache keys that match the provided config name.
   *
   * @param string $name
   *   The name of the configuration object.
   *
   * @return array
   *   An array of cache keys that match the provided config name.
273
   */
274
  protected function getConfigCacheKeys($name) {
275 276 277 278
    return array_filter(array_keys($this->cache), function($key) use ($name) {
      // Return TRUE if the key starts with the configuration name.
      return strpos($key, $name . ':') === 0;
    });
279
  }
280 281

  /**
282
   * {@inheritdoc}
283 284 285 286 287 288
   */
  public function clearStaticCache() {
    $this->cache = array();
    return $this;
  }

289 290 291 292 293 294 295
  /**
   * {@inheritdoc}
   */
  public function listAll($prefix = '') {
    return $this->storage->listAll($prefix);
  }

296
  /**
297
   * Removes stale static cache entries when configuration is saved.
298
   *
299
   * @param ConfigCrudEvent $event
300
   *   The configuration event.
301
   */
302
  public function onConfigSave(ConfigCrudEvent $event) {
303 304 305 306
    // Ensure that the static cache contains up to date configuration objects by
    // replacing the data on any entries for the configuration object apart
    // from the one that references the actual config object being saved.
    $saved_config = $event->getConfig();
307
    foreach ($this->getConfigCacheKeys($saved_config->getName()) as $cache_key) {
308 309 310 311 312
      $cached_config = $this->cache[$cache_key];
      if ($cached_config !== $saved_config) {
        $this->cache[$cache_key]->setData($saved_config->getRawData());
      }
    }
313
  }
314

315 316 317 318 319 320 321 322 323 324 325 326 327
  /**
   * Removes stale static cache entries when configuration is deleted.
   *
   * @param \Drupal\Core\Config\ConfigCrudEvent $event
   *   The configuration event.
   */
  public function onConfigDelete(ConfigCrudEvent $event) {
    // Ensure that the static cache does not contain deleted configuration.
    foreach ($this->getConfigCacheKeys($event->getConfig()->getName()) as $cache_key) {
      unset($this->cache[$cache_key]);
    }
  }

328 329 330 331
  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {
332
    $events[ConfigEvents::SAVE][] = array('onConfigSave', 255);
333
    $events[ConfigEvents::DELETE][] = array('onConfigDelete', 255);
334 335 336
    return $events;
  }

337 338 339 340 341 342 343
  /**
   * {@inheritdoc}
   */
  public function addOverride(ConfigFactoryOverrideInterface $config_factory_override) {
    $this->configFactoryOverrides[] = $config_factory_override;
  }

344
}