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