ConfigFactory.php 11.6 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\Core\Language\Language;
11
use Drupal\Core\Language\LanguageDefault;
12
use Symfony\Component\EventDispatcher\EventDispatcher;
13
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
14
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15

16
17
18
19
20
21
/**
 * 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.
 *
22
 * @see \Drupal\Core\Config\Config
23
 *
24
25
 * Each configuration object gets a storage controller object injected, which
 * is used for reading and writing the configuration data.
26
 *
27
 * @see \Drupal\Core\Config\StorageInterface
28
 */
29
class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface {
30

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

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

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

  /**
   * The language object used to override configuration data.
54
   *
55
   * @var \Drupal\Core\Language\Language
56
   */
57
  protected $language;
58

59
60
61
  /**
   * Cached configuration objects.
   *
62
   * @var \Drupal\Core\Config\Config[]
63
64
65
   */
  protected $cache = array();

66
67
68
69
70
71
72
  /**
   * The typed config manager.
   *
   * @var \Drupal\Core\Config\TypedConfigManager
   */
  protected $typedConfigManager;

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

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

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

  /**
105
   * {@inheritdoc}
106
107
   */
  public function get($name) {
108
109
110
111
    global $conf;

    if ($config = $this->loadMultiple(array($name))) {
      return $config[$name];
112
    }
113
114
115
116
117
118
119
120
121
122
123
    else {
      $cache_key = $this->getCacheKey($name);
      // If the config object has been deleted it will already exist in the
      // cache but self::loadMultiple does not return such objects.
      // @todo Explore making ConfigFactory a listener to the config.delete
      //   event to reset the static cache when this occurs.
      if (!isset($this->cache[$cache_key])) {
        // If the configuration object does not exist in the configuration
        // storage or static cache create a new object and add it to the static
        // cache.
        $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language);
124

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
        if ($this->canOverride($name)) {
          // Get and apply any language overrides.
          if ($this->language) {
            $language_overrides = $this->storage->read($this->getLanguageConfigName($this->language->id, $name));
          }
          else {
            $language_overrides = FALSE;
          }
          if (is_array($language_overrides)) {
            $this->cache[$cache_key]->setLanguageOverride($language_overrides);
          }
          // Get and apply any module overrides.
          $module_overrides = $this->loadModuleOverrides(array($name));
          if (isset($module_overrides[$name])) {
            $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]);
          }
          // Apply any settings.php overrides.
          if (isset($conf[$name])) {
            $this->cache[$cache_key]->setSettingsOverride($conf[$name]);
          }
        }
      }
      return $this->cache[$cache_key];
    }
149
  }
150

151
  /**
152
   * {@inheritdoc}
153
154
   */
  public function loadMultiple(array $names) {
155
    global $conf;
156
157

    $list = array();
158

159
160
    foreach ($names as $key => $name) {
      // @todo: Deleted configuration stays in $this->cache, only return
161
162
      //   configuration objects that are not new.
      $cache_key = $this->getCacheKey($name);
163
164
165
166
167
168
169
170
      if (isset($this->cache[$cache_key]) && !$this->cache[$cache_key]->isNew()) {
        $list[$name] = $this->cache[$cache_key];
        unset($names[$key]);
      }
    }

    // Pre-load remaining configuration files.
    if (!empty($names)) {
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
      // Initialise override information.
      $module_overrides = array();
      $language_names = array();

      if ($this->useOverrides) {
        // In order to make just one call to storage, add in language names.
        // Keep track of them separately, so we can get language override data
        // returned from storage and set it on new Config objects.
        $language_names = $this->getLanguageConfigNames($names);
      }

      $storage_data = $this->storage->readMultiple(array_merge($names, array_values($language_names)));

      if ($this->useOverrides && !empty($storage_data)) {
        // Only fire module override event if we have configuration to override.
        $module_overrides = $this->loadModuleOverrides($names);
      }

189
      foreach ($storage_data as $name => $data) {
190
191
192
193
194
195
196
197
198
199
        if (in_array($name, $language_names)) {
          // Language override configuration is used to override other
          // configuration. Therefore, when it has been added to the
          // $storage_data it is not statically cached in the config factory or
          // overridden in any way.
          continue;
        }
        $cache_key = $this->getCacheKey($name);

        $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language);
200
        $this->cache[$cache_key]->initWithData($data);
201
202
203
204
205
206
207
208
209
210
211
        if ($this->canOverride($name)) {
          if (isset($language_names[$name]) && isset($storage_data[$language_names[$name]])) {
            $this->cache[$cache_key]->setLanguageOverride($storage_data[$language_names[$name]]);
          }
          if (isset($module_overrides[$name])) {
            $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]);
          }
          if (isset($conf[$name])) {
            $this->cache[$cache_key]->setSettingsOverride($conf[$name]);
          }
        }
212
213
214
        $list[$name] = $this->cache[$cache_key];
      }
    }
215

216
217
218
    return $list;
  }

219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  /**
   * 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.
   */
  protected function loadModuleOverrides(array $names) {
    $configOverridesEvent = new ConfigModuleOverridesEvent($names, $this->language);
    $this->eventDispatcher->dispatch('config.module.overrides', $configOverridesEvent);
    return $configOverridesEvent->getOverrides();
  }

234
  /**
235
   * {@inheritdoc}
236
237
238
   */
  public function reset($name = NULL) {
    if ($name) {
239
      // Clear all cached configuration for this name.
240
      foreach ($this->getCacheKeys($name) as $cache_key) {
241
        unset($this->cache[$cache_key]);
242
243
244
      }
    }
    else {
245
      $this->cache = array();
246
    }
247
248
249
250
251

    // Clear the static list cache if supported by the storage.
    if ($this->storage instanceof StorageCacheInterface) {
      $this->storage->resetListCache();
    }
252
    return $this;
253
254
255
  }

  /**
256
   * {@inheritdoc}
257
258
   */
  public function rename($old_name, $new_name) {
259
260
    $this->storage->rename($old_name, $new_name);
    $old_cache_key = $this->getCacheKey($old_name);
261
    if (isset($this->cache[$old_cache_key])) {
262
263
      unset($this->cache[$old_cache_key]);
    }
264
265
266

    $new_cache_key = $this->getCacheKey($new_name);
    $this->cache[$new_cache_key] = new Config($new_name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language);
267
268
269
    if ($data = $this->storage->read($new_name)) {
      $this->cache[$new_cache_key]->initWithData($data);
    }
270
271
272
273
    return $this->cache[$new_cache_key];
  }

  /**
274
   * {@inheritdoc}
275
276
277
278
279
280
281
   */
  public function getCacheKey($name) {
    $can_override = $this->canOverride($name);
    $cache_key = $name . ':' . ($can_override ? 'overrides' : 'raw');

    if ($can_override && isset($this->language)) {
      $cache_key =  $cache_key . ':' . $this->language->id;
282
    }
283
284
    return $cache_key;
  }
285

286
  /**
287
   * {@inheritdoc}
288
289
290
291
292
293
   */
  public function getCacheKeys($name) {
    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;
    });
294
  }
295
296

  /**
297
   * {@inheritdoc}
298
299
300
301
302
303
304
   */
  public function clearStaticCache() {
    $this->cache = array();
    return $this;
  }

  /**
305
   * {@inheritdoc}
306
   */
307
308
  public function setLanguage(Language $language = NULL) {
    $this->language = $language;
309
310
311
    return $this;
  }

312
  /**
313
   * {@inheritdoc}
314
315
316
317
318
319
   */
  public function setLanguageFromDefault(LanguageDefault $language_default) {
    $this->language = $language_default->get();
    return $this;
  }

320
  /**
321
   * {@inheritdoc}
322
   */
323
324
  public function getLanguage() {
    return $this->language;
325
326
327
  }

  /**
328
   * {@inheritdoc}
329
   */
330
331
332
333
334
335
336
337
  public function getLanguageConfigNames(array $names) {
    $language_names = array();
    if (isset($this->language)) {
      foreach ($names as $name) {
        if ($language_name = $this->getLanguageConfigName($this->language->id, $name)) {
          $language_names[$name] = $language_name;
        }
      }
338
    }
339
    return $language_names;
340
341
  }

342
  /**
343
   * {@inheritdoc}
344
   */
345
346
347
348
349
  public function getLanguageConfigName($langcode, $name) {
    if (strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0) {
      return FALSE;
    }
    return static::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.' . $name;
350
351
352
  }

  /**
353
354
355
   * Determines if a particular configuration object can be overridden.
   *
   * Language override configuration should not be overridden.
356
357
358
359
   *
   * @param string $name
   *   The name of the configuration object.
   *
360
361
   * @return bool
   *   TRUE if the configuration object can be overridden.
362
   */
363
364
  protected function canOverride($name) {
    return $this->useOverrides && !(strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0);
365
  }
366
367

  /**
368
   * Removes stale static cache entries when configuration is saved.
369
   *
370
371
   * @param ConfigEvent $event
   *   The configuration event.
372
   */
373
374
375
376
377
378
379
380
381
382
383
  public function onConfigSave(ConfigEvent $event) {
    // 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();
    foreach ($this->getCacheKeys($saved_config->getName()) as $cache_key) {
      $cached_config = $this->cache[$cache_key];
      if ($cached_config !== $saved_config) {
        $this->cache[$cache_key]->setData($saved_config->getRawData());
      }
    }
384
  }
385
386
387
388
389
390
391
392
393

  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {
    $events['config.save'][] = array('onConfigSave', 255);
    return $events;
  }

394
}