7299d5e642cdc5afe6a0cf8df90b81886ccd44d5
[yaffs-website] / web / core / lib / Drupal / Core / Config / Config.php
1 <?php
2
3 namespace Drupal\Core\Config;
4
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Core\Cache\Cache;
7 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
8
9 /**
10  * Defines the default configuration object.
11  *
12  * Encapsulates all capabilities needed for configuration handling for a
13  * specific configuration object, including support for runtime overrides. The
14  * overrides are handled on top of the stored configuration so they are not
15  * saved back to storage.
16  *
17  * @ingroup config_api
18  */
19 class Config extends StorableConfigBase {
20
21   /**
22    * An event dispatcher instance to use for configuration events.
23    *
24    * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
25    */
26   protected $eventDispatcher;
27
28   /**
29    * The current runtime data.
30    *
31    * The configuration data from storage merged with module and settings
32    * overrides.
33    *
34    * @var array
35    */
36   protected $overriddenData;
37
38   /**
39    * The current module overrides.
40    *
41    * @var array
42    */
43   protected $moduleOverrides;
44
45   /**
46    * The current settings overrides.
47    *
48    * @var array
49    */
50   protected $settingsOverrides;
51
52   /**
53    * Constructs a configuration object.
54    *
55    * @param string $name
56    *   The name of the configuration object being constructed.
57    * @param \Drupal\Core\Config\StorageInterface $storage
58    *   A storage object to use for reading and writing the
59    *   configuration data.
60    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
61    *   An event dispatcher instance to use for configuration events.
62    * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
63    *   The typed configuration manager service.
64    */
65   public function __construct($name, StorageInterface $storage, EventDispatcherInterface $event_dispatcher, TypedConfigManagerInterface $typed_config) {
66     $this->name = $name;
67     $this->storage = $storage;
68     $this->eventDispatcher = $event_dispatcher;
69     $this->typedConfigManager = $typed_config;
70   }
71
72   /**
73    * {@inheritdoc}
74    */
75   public function initWithData(array $data) {
76     parent::initWithData($data);
77     $this->resetOverriddenData();
78     return $this;
79   }
80
81   /**
82    * {@inheritdoc}
83    */
84   public function get($key = '') {
85     if (!isset($this->overriddenData)) {
86       $this->setOverriddenData();
87     }
88     if (empty($key)) {
89       return $this->overriddenData;
90     }
91     else {
92       $parts = explode('.', $key);
93       if (count($parts) == 1) {
94         return isset($this->overriddenData[$key]) ? $this->overriddenData[$key] : NULL;
95       }
96       else {
97         $value = NestedArray::getValue($this->overriddenData, $parts, $key_exists);
98         return $key_exists ? $value : NULL;
99       }
100     }
101   }
102
103   /**
104    * {@inheritdoc}
105    */
106   public function setData(array $data) {
107     parent::setData($data);
108     $this->resetOverriddenData();
109     return $this;
110   }
111
112   /**
113    * Sets settings.php overrides for this configuration object.
114    *
115    * The overridden data only applies to this configuration object.
116    *
117    * @param array $data
118    *   The overridden values of the configuration data.
119    *
120    * @return \Drupal\Core\Config\Config
121    *   The configuration object.
122    */
123   public function setSettingsOverride(array $data) {
124     $this->settingsOverrides = $data;
125     $this->resetOverriddenData();
126     return $this;
127   }
128
129   /**
130    * Sets module overrides for this configuration object.
131    *
132    * @param array $data
133    *   The overridden values of the configuration data.
134    *
135    * @return \Drupal\Core\Config\Config
136    *   The configuration object.
137    */
138   public function setModuleOverride(array $data) {
139     $this->moduleOverrides = $data;
140     $this->resetOverriddenData();
141     return $this;
142   }
143
144   /**
145    * Sets the current data for this configuration object.
146    *
147    * Configuration overrides operate at two distinct layers: modules and
148    * settings.php. Overrides in settings.php take precedence over values
149    * provided by modules. Precedence or different module overrides is
150    * determined by the priority of the config.factory.override tagged services.
151    *
152    * @return \Drupal\Core\Config\Config
153    *   The configuration object.
154    */
155   protected function setOverriddenData() {
156     $this->overriddenData = $this->data;
157     if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
158       $this->overriddenData = NestedArray::mergeDeepArray([$this->overriddenData, $this->moduleOverrides], TRUE);
159     }
160     if (isset($this->settingsOverrides) && is_array($this->settingsOverrides)) {
161       $this->overriddenData = NestedArray::mergeDeepArray([$this->overriddenData, $this->settingsOverrides], TRUE);
162     }
163     return $this;
164   }
165
166   /**
167    * Resets the current data, so overrides are re-applied.
168    *
169    * This method should be called after the original data or the overridden data
170    * has been changed.
171    *
172    * @return \Drupal\Core\Config\Config
173    *   The configuration object.
174    */
175   protected function resetOverriddenData() {
176     unset($this->overriddenData);
177     return $this;
178   }
179
180   /**
181    * {@inheritdoc}
182    */
183   public function set($key, $value) {
184     parent::set($key, $value);
185     $this->resetOverriddenData();
186     return $this;
187   }
188
189   /**
190    * {@inheritdoc}
191    */
192   public function clear($key) {
193     parent::clear($key);
194     $this->resetOverriddenData();
195     return $this;
196   }
197
198   /**
199    * {@inheritdoc}
200    */
201   public function save($has_trusted_data = FALSE) {
202     // Validate the configuration object name before saving.
203     static::validateName($this->name);
204
205     // If there is a schema for this configuration object, cast all values to
206     // conform to the schema.
207     if (!$has_trusted_data) {
208       if ($this->typedConfigManager->hasConfigSchema($this->name)) {
209         // Ensure that the schema wrapper has the latest data.
210         $this->schemaWrapper = NULL;
211         foreach ($this->data as $key => $value) {
212           $this->data[$key] = $this->castValue($key, $value);
213         }
214       }
215       else {
216         foreach ($this->data as $key => $value) {
217           $this->validateValue($key, $value);
218         }
219       }
220     }
221
222     $this->storage->write($this->name, $this->data);
223     if (!$this->isNew) {
224       Cache::invalidateTags($this->getCacheTags());
225     }
226     $this->isNew = FALSE;
227     $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this));
228     $this->originalData = $this->data;
229     // Potentially configuration schema could have changed the underlying data's
230     // types.
231     $this->resetOverriddenData();
232     return $this;
233   }
234
235   /**
236    * Deletes the configuration object.
237    *
238    * @return \Drupal\Core\Config\Config
239    *   The configuration object.
240    */
241   public function delete() {
242     $this->data = [];
243     $this->storage->delete($this->name);
244     Cache::invalidateTags($this->getCacheTags());
245     $this->isNew = TRUE;
246     $this->resetOverriddenData();
247     $this->eventDispatcher->dispatch(ConfigEvents::DELETE, new ConfigCrudEvent($this));
248     $this->originalData = $this->data;
249     return $this;
250   }
251
252   /**
253    * Gets the raw data without overrides.
254    *
255    * @return array
256    *   The raw data.
257    */
258   public function getRawData() {
259     return $this->data;
260   }
261
262   /**
263    * Gets original data from this configuration object.
264    *
265    * Original data is the data as it is immediately after loading from
266    * configuration storage before any changes. If this is a new configuration
267    * object it will be an empty array.
268    *
269    * @see \Drupal\Core\Config\Config::get()
270    *
271    * @param string $key
272    *   A string that maps to a key within the configuration data.
273    * @param bool $apply_overrides
274    *   Apply any overrides to the original data. Defaults to TRUE.
275    *
276    * @return mixed
277    *   The data that was requested.
278    */
279   public function getOriginal($key = '', $apply_overrides = TRUE) {
280     $original_data = $this->originalData;
281     if ($apply_overrides) {
282       // Apply overrides.
283       if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
284         $original_data = NestedArray::mergeDeepArray([$original_data, $this->moduleOverrides], TRUE);
285       }
286       if (isset($this->settingsOverrides) && is_array($this->settingsOverrides)) {
287         $original_data = NestedArray::mergeDeepArray([$original_data, $this->settingsOverrides], TRUE);
288       }
289     }
290
291     if (empty($key)) {
292       return $original_data;
293     }
294     else {
295       $parts = explode('.', $key);
296       if (count($parts) == 1) {
297         return isset($original_data[$key]) ? $original_data[$key] : NULL;
298       }
299       else {
300         $value = NestedArray::getValue($original_data, $parts, $key_exists);
301         return $key_exists ? $value : NULL;
302       }
303     }
304   }
305
306   /**
307    * Determines if overrides are applied to a key for this configuration object.
308    *
309    * @param string $key
310    *   (optional) A string that maps to a key within the configuration data.
311    *   For instance in the following configuration array:
312    *   @code
313    *   array(
314    *     'foo' => array(
315    *       'bar' => 'baz',
316    *     ),
317    *   );
318    *   @endcode
319    *   A key of 'foo.bar' would map to the string 'baz'. However, a key of 'foo'
320    *   would map to the array('bar' => 'baz').
321    *   If not supplied TRUE will be returned if there are any overrides at all
322    *   for this configuration object.
323    *
324    * @return bool
325    *   TRUE if there are any overrides for the key, otherwise FALSE.
326    */
327   public function hasOverrides($key = '') {
328     if (empty($key)) {
329       return !(empty($this->moduleOverrides) && empty($this->settingsOverrides));
330     }
331     else {
332       $parts = explode('.', $key);
333       $override_exists = FALSE;
334       if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
335         $override_exists = NestedArray::keyExists($this->moduleOverrides, $parts);
336       }
337       if (!$override_exists && isset($this->settingsOverrides) && is_array($this->settingsOverrides)) {
338         $override_exists = NestedArray::keyExists($this->settingsOverrides, $parts);
339       }
340       return $override_exists;
341     }
342   }
343
344 }