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