|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace dokuwiki\plugin\config\core; |
| 4 | + |
| 5 | +use dokuwiki\plugin\config\core\Setting\Setting; |
| 6 | +use dokuwiki\plugin\config\core\Setting\SettingNoClass; |
| 7 | +use dokuwiki\plugin\config\core\Setting\SettingNoDefault; |
| 8 | +use dokuwiki\plugin\config\core\Setting\SettingNoKnownClass; |
| 9 | +use dokuwiki\plugin\config\core\Setting\SettingUndefined; |
| 10 | + |
| 11 | +/** |
| 12 | + * Holds all the current settings and proxies the Loader and Writer |
| 13 | + * |
| 14 | + * @author Chris Smith <[email protected]> |
| 15 | + * @author Ben Coburn <[email protected]> |
| 16 | + * @author Andreas Gohr <[email protected]> |
| 17 | + */ |
| 18 | +class Configuration { |
| 19 | + |
| 20 | + const KEYMARKER = '____'; |
| 21 | + |
| 22 | + /** @var Setting[] metadata as array of Settings objects */ |
| 23 | + protected $settings = array(); |
| 24 | + /** @var Setting[] undefined and problematic settings */ |
| 25 | + protected $undefined = array(); |
| 26 | + |
| 27 | + /** @var array all metadata */ |
| 28 | + protected $metadata; |
| 29 | + /** @var array all default settings */ |
| 30 | + protected $default; |
| 31 | + /** @var array all local settings */ |
| 32 | + protected $local; |
| 33 | + /** @var array all protected settings */ |
| 34 | + protected $protected; |
| 35 | + |
| 36 | + /** @var bool have the settings been changed since loading from disk? */ |
| 37 | + protected $changed = false; |
| 38 | + |
| 39 | + /** @var Loader */ |
| 40 | + protected $loader; |
| 41 | + /** @var Writer */ |
| 42 | + protected $writer; |
| 43 | + |
| 44 | + /** |
| 45 | + * ConfigSettings constructor. |
| 46 | + */ |
| 47 | + public function __construct() { |
| 48 | + $this->loader = new Loader(new ConfigParser()); |
| 49 | + $this->writer = new Writer(); |
| 50 | + |
| 51 | + $this->metadata = $this->loader->loadMeta(); |
| 52 | + $this->default = $this->loader->loadDefaults(); |
| 53 | + $this->local = $this->loader->loadLocal(); |
| 54 | + $this->protected = $this->loader->loadProtected(); |
| 55 | + |
| 56 | + $this->initSettings(); |
| 57 | + } |
| 58 | + |
| 59 | + /** |
| 60 | + * Get all settings |
| 61 | + * |
| 62 | + * @return Setting[] |
| 63 | + */ |
| 64 | + public function getSettings() { |
| 65 | + return $this->settings; |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * Get all unknown or problematic settings |
| 70 | + * |
| 71 | + * @return Setting[] |
| 72 | + */ |
| 73 | + public function getUndefined() { |
| 74 | + return $this->undefined; |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * Have the settings been changed since loading from disk? |
| 79 | + * |
| 80 | + * @return bool |
| 81 | + */ |
| 82 | + public function hasChanged() { |
| 83 | + return $this->changed; |
| 84 | + } |
| 85 | + |
| 86 | + /** |
| 87 | + * Check if the config can be written |
| 88 | + * |
| 89 | + * @return bool |
| 90 | + */ |
| 91 | + public function isLocked() { |
| 92 | + return $this->writer->isLocked(); |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Update the settings using the data provided |
| 97 | + * |
| 98 | + * @param array $input as posted |
| 99 | + * @return bool true if all updates went through, false on errors |
| 100 | + */ |
| 101 | + public function updateSettings($input) { |
| 102 | + $ok = true; |
| 103 | + |
| 104 | + foreach($this->settings as $key => $obj) { |
| 105 | + $value = isset($input[$key]) ? $input[$key] : null; |
| 106 | + if($obj->update($value)) { |
| 107 | + $this->changed = true; |
| 108 | + } |
| 109 | + if($obj->hasError()) $ok = false; |
| 110 | + } |
| 111 | + |
| 112 | + return $ok; |
| 113 | + } |
| 114 | + |
| 115 | + /** |
| 116 | + * Save the settings |
| 117 | + * |
| 118 | + * This save the current state as defined in this object, including the |
| 119 | + * undefined settings |
| 120 | + * |
| 121 | + * @throws \Exception |
| 122 | + */ |
| 123 | + public function save() { |
| 124 | + // only save the undefined settings that have not been handled in settings |
| 125 | + $undefined = array_diff_key($this->undefined, $this->settings); |
| 126 | + $this->writer->save(array_merge($this->settings, $undefined)); |
| 127 | + } |
| 128 | + |
| 129 | + /** |
| 130 | + * Touch the settings |
| 131 | + * |
| 132 | + * @throws \Exception |
| 133 | + */ |
| 134 | + public function touch() { |
| 135 | + $this->writer->touch(); |
| 136 | + } |
| 137 | + |
| 138 | + /** |
| 139 | + * Load the extension language strings |
| 140 | + * |
| 141 | + * @return array |
| 142 | + */ |
| 143 | + public function getLangs() { |
| 144 | + return $this->loader->loadLangs(); |
| 145 | + } |
| 146 | + |
| 147 | + /** |
| 148 | + * Initalizes the $settings and $undefined properties |
| 149 | + */ |
| 150 | + protected function initSettings() { |
| 151 | + $keys = array_merge( |
| 152 | + array_keys($this->metadata), |
| 153 | + array_keys($this->default), |
| 154 | + array_keys($this->local), |
| 155 | + array_keys($this->protected) |
| 156 | + ); |
| 157 | + $keys = array_unique($keys); |
| 158 | + |
| 159 | + foreach($keys as $key) { |
| 160 | + $obj = $this->instantiateClass($key); |
| 161 | + |
| 162 | + if($obj->shouldHaveDefault() && !isset($this->default[$key])) { |
| 163 | + $this->undefined[$key] = new SettingNoDefault($key); |
| 164 | + } |
| 165 | + |
| 166 | + $d = isset($this->default[$key]) ? $this->default[$key] : null; |
| 167 | + $l = isset($this->local[$key]) ? $this->local[$key] : null; |
| 168 | + $p = isset($this->protected[$key]) ? $this->protected[$key] : null; |
| 169 | + |
| 170 | + $obj->initialize($d, $l, $p); |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | + /** |
| 175 | + * Instantiates the proper class for the given config key |
| 176 | + * |
| 177 | + * The class is added to the $settings or $undefined arrays and returned |
| 178 | + * |
| 179 | + * @param string $key |
| 180 | + * @return Setting |
| 181 | + */ |
| 182 | + protected function instantiateClass($key) { |
| 183 | + if(isset($this->metadata[$key])) { |
| 184 | + $param = $this->metadata[$key]; |
| 185 | + $class = $this->determineClassName(array_shift($param), $key); // first param is class |
| 186 | + $obj = new $class($key, $param); |
| 187 | + $this->settings[$key] = $obj; |
| 188 | + } else { |
| 189 | + $obj = new SettingUndefined($key); |
| 190 | + $this->undefined[$key] = $obj; |
| 191 | + } |
| 192 | + return $obj; |
| 193 | + } |
| 194 | + |
| 195 | + /** |
| 196 | + * Return the class to load |
| 197 | + * |
| 198 | + * @param string $class the class name as given in the meta file |
| 199 | + * @param string $key the settings key |
| 200 | + * @return string |
| 201 | + */ |
| 202 | + protected function determineClassName($class, $key) { |
| 203 | + // try namespaced class first |
| 204 | + if(is_string($class)) { |
| 205 | + $modern = str_replace('_', '', ucwords($class, '_')); |
| 206 | + $modern = '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting' . $modern; |
| 207 | + if($modern && class_exists($modern)) return $modern; |
| 208 | + // try class as given |
| 209 | + if(class_exists($class)) return $class; |
| 210 | + // class wasn't found add to errors |
| 211 | + $this->undefined[$key] = new SettingNoKnownClass($key); |
| 212 | + } else { |
| 213 | + // no class given, add to errors |
| 214 | + $this->undefined[$key] = new SettingNoClass($key); |
| 215 | + } |
| 216 | + return '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting'; |
| 217 | + } |
| 218 | + |
| 219 | +} |
0 commit comments