Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / themes / contrib / bootstrap / src / ThemeSettings.php
1 <?php
2
3 namespace Drupal\bootstrap;
4
5 use Drupal\Core\Theme\ThemeSettings as CoreThemeSettings;
6 use Drupal\Component\Utility\DiffArray;
7 use Drupal\Component\Utility\NestedArray;
8 use Drupal\Core\Config\Config;
9 use Drupal\Core\Config\StorageException;
10
11 /**
12  * Provides a configuration API wrapper for runtime merged theme settings.
13  *
14  * This is a wrapper around theme_get_setting() since it does not inherit
15  * base theme config nor handle default/overridden values very well.
16  *
17  * @ingroup utility
18  */
19 class ThemeSettings extends Config {
20
21   /**
22    * The default settings.
23    *
24    * @var array
25    */
26   protected $defaults;
27
28   /**
29    * The current theme object.
30    *
31    * @var \Drupal\bootstrap\Theme
32    */
33   protected $theme;
34
35   /**
36    * {@inheritdoc}
37    */
38   public function __construct(Theme $theme) {
39     parent::__construct($theme->getName() . '.settings', \Drupal::service('config.storage'), \Drupal::service('event_dispatcher'), \Drupal::service('config.typed'));
40     $this->theme = $theme;
41
42     // Retrieve cache.
43     $cache = $theme->getCache('settings');
44
45     // Use cached settings.
46     if ($defaults = $cache->get('defaults')) {
47       $this->defaults = $defaults;
48       $this->initWithData($cache->get('data', []));
49       return;
50     }
51
52     // Retrieve the global settings from configuration.
53     $this->defaults = \Drupal::config('system.theme.global')->get();
54
55     // Retrieve the theme setting plugin discovery defaults (code).
56     foreach ($theme->getSettingPlugin() as $name => $setting) {
57       $this->defaults[$name] = $setting->getDefaultValue();
58     }
59
60     // Retrieve the theme ancestry.
61     $ancestry = $theme->getAncestry();
62
63     // Remove the active theme from the ancestry.
64     $active_theme = array_pop($ancestry);
65
66     // Iterate and merge all ancestor theme config into the defaults.
67     foreach ($ancestry as $ancestor) {
68       $this->defaults = NestedArray::mergeDeepArray([$this->defaults, $this->getThemeConfig($ancestor)], TRUE);
69     }
70
71     // Merge the active theme config.
72     $this->initWithData($this->getThemeConfig($active_theme, TRUE));
73
74     // Cache the data and defaults.
75     $cache->set('data', $this->data);
76     $cache->set('defaults', $this->defaults);
77   }
78
79   /**
80    * {@inheritdoc}
81    */
82   public function getCacheTags() {
83     return ['rendered'];
84   }
85
86   /**
87    * {@inheritdoc}
88    */
89   public function get($key = '') {
90     if (empty($key)) {
91       return NestedArray::mergeDeepArray([$this->defaults, $this->data], TRUE);
92     }
93     else {
94       $value = parent::get($key);
95       if (!isset($value)) {
96         $value = $this->getOriginal($key);
97       }
98     }
99     return $value;
100   }
101
102   /**
103    * {@inheritdoc}
104    */
105   public function getOriginal($key = '', $apply_overrides = TRUE) {
106     $original_data = $this->defaults;
107     if ($apply_overrides) {
108       // Apply overrides.
109       if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
110         $original_data = NestedArray::mergeDeepArray([$original_data, $this->moduleOverrides], TRUE);
111       }
112       if (isset($this->settingsOverrides) && is_array($this->settingsOverrides)) {
113         $original_data = NestedArray::mergeDeepArray([$original_data, $this->settingsOverrides], TRUE);
114       }
115     }
116
117     if (empty($key)) {
118       return $original_data;
119     }
120     else {
121       $parts = explode('.', $key);
122       if (count($parts) == 1) {
123         return isset($original_data[$key]) ? $original_data[$key] : NULL;
124       }
125       else {
126         $value = NestedArray::getValue($original_data, $parts, $key_exists);
127         return $key_exists ? $value : NULL;
128       }
129     }
130   }
131
132   /**
133    * Retrieves a specific theme's stored config settings.
134    *
135    * @param \Drupal\bootstrap\Theme $theme
136    *   A theme object.
137    * @param bool $active_theme
138    *   Flag indicating whether or not $theme is the active theme.
139    *
140    * @return array
141    *   A array diff of overridden config theme settings.
142    */
143   public function getThemeConfig(Theme $theme, $active_theme = FALSE) {
144     $config = new CoreThemeSettings($theme->getName());
145
146     // Retrieve configured theme-specific settings, if any.
147     try {
148       if ($theme_settings = \Drupal::config($theme->getName() . '.settings')->get()) {
149         // Remove schemas if not the active theme.
150         if (!$active_theme) {
151           unset($theme_settings['schemas']);
152         }
153         $config->merge($theme_settings);
154       }
155     }
156     catch (StorageException $e) {
157     }
158
159     // If the theme does not support a particular feature, override the
160     // global setting and set the value to NULL.
161     $info = $theme->getInfo();
162     if (!empty($info['features'])) {
163       foreach (_system_default_theme_features() as $feature) {
164         if (!in_array($feature, $info['features'])) {
165           $config->set('features.' . $feature, NULL);
166         }
167       }
168     }
169
170     // Generate the path to the logo image.
171     if ($config->get('features.logo')) {
172       $logo_url = FALSE;
173       foreach (['svg', 'png', 'jpg'] as $type) {
174         if (file_exists($theme->getPath() . "/logo.$type")) {
175           $logo_url = file_create_url($theme->getPath() . "/logo.$type");
176           break;
177         }
178       }
179       if ($config->get('logo.use_default') && $logo_url) {
180         $config->set('logo.url', $logo_url);
181       }
182       elseif (($logo_path = $config->get('logo.path')) && file_exists($logo_path)) {
183         $config->set('logo.url', file_create_url($logo_path));
184       }
185     }
186
187     // Generate the path to the favicon.
188     if ($config->get('features.favicon')) {
189       $favicon_url = $theme->getPath() . '/favicon.ico';
190       if ($config->get('favicon.use_default') && file_exists($favicon_url)) {
191         $config->set('favicon.url', file_create_url($favicon_url));
192       }
193       elseif ($favicon_path = $config->get('favicon.path')) {
194         $config->set('favicon.url', file_create_url($favicon_path));
195       }
196     }
197
198     // Retrieve the config data.
199     $data = $config->get();
200
201     // Retrieve a diff of settings that override the defaults.
202     $diff = DiffArray::diffAssocRecursive($data, $this->defaults);
203
204     // Ensure core features are always present in the diff. The theme settings
205     // form will not work properly otherwise.
206     // @todo Just rebuild the features section of the form?
207     foreach (['favicon', 'features', 'logo'] as $key) {
208       $arrays = [];
209       $arrays[] = isset($this->defaults[$key]) ? $this->defaults[$key] : [];
210       $arrays[] = isset($data[$key]) ? $data[$key] : [];
211       $diff[$key] = NestedArray::mergeDeepArray($arrays, TRUE);
212     }
213
214     return $diff;
215   }
216
217   /**
218    * Determines if a setting overrides the default value.
219    *
220    * @param string $name
221    *   The name of the setting to check.
222    * @param mixed $value
223    *   The new value to check.
224    *
225    * @return bool
226    *   TRUE or FALSE
227    */
228   public function overridesValue($name, $value) {
229     // Retrieve the currently stored value for comparison purposes.
230     $current_value = $this->get($name);
231
232     // Due to the nature of DiffArray::diffAssocRecursive, if the provided
233     // value is an empty array, it cannot be iterated over to determine if
234     // the values are different. Instead, it must be checked explicitly.
235     // @see https://www.drupal.org/node/2771121
236     if ($value === [] && $current_value !== []) {
237       return TRUE;
238     }
239
240     // Otherwise, determine if value is overridden by any array differences.
241     return !!DiffArray::diffAssocRecursive([$name => $value], [$name => $current_value]);
242   }
243
244   /**
245    * {@inheritdoc}
246    */
247   public function save($has_trusted_data = FALSE) {
248     parent::save($has_trusted_data);
249     $this->theme->getCache('settings')->deleteAll();
250     return $this;
251   }
252
253 }