1<?php 2 3namespace dokuwiki\plugin\config\core; 4 5/** 6 * Holds all the current settings and proxies the Loader and Writer 7 * 8 * @author Chris Smith <chris@jalakai.co.uk> 9 * @author Ben Coburn <btcoburn@silicodon.net> 10 * @author Andreas Gohr <andi@splitbrain.org> 11 */ 12class Configuration { 13 14 const KEYMARKER = '____'; 15 16 /** @var Setting[] metadata as array of Settings objects */ 17 protected $settings = array(); 18 /** @var array problematic keys */ 19 protected $errors; 20 /** @var Setting[] undefined settings */ 21 protected $undefined = array(); 22 23 /** @var array all metadata */ 24 protected $metadata; 25 /** @var array all default settings */ 26 protected $default; 27 /** @var array all local settings */ 28 protected $local; 29 /** @var array all protected settings */ 30 protected $protected; 31 32 /** @var bool have the settings been changed since loading from disk? */ 33 protected $changed = false; 34 35 /** @var Loader */ 36 protected $loader; 37 /** @var Writer */ 38 protected $writer; 39 40 /** 41 * ConfigSettings constructor. 42 */ 43 public function __construct() { 44 $this->loader = new Loader(new ConfigParser()); 45 $this->writer = new Writer(); 46 47 $this->metadata = $this->loader->loadMeta(); 48 $this->default = $this->loader->loadDefaults(); 49 $this->local = $this->loader->loadLocal(); 50 $this->protected = $this->loader->loadProtected(); 51 52 $this->initSettings(); 53 } 54 55 /** 56 * Get all settings 57 * 58 * @return Setting[] 59 */ 60 public function getSettings() { 61 return $this->settings; 62 } 63 64 /** 65 * Get all unknown settings 66 * 67 * @return Setting[] 68 */ 69 public function getUndefined() { 70 return $this->undefined; 71 } 72 73 /** 74 * Get the settings that had some kind of setup problem 75 * 76 * @return array associative error, key is the setting, value the error 77 */ 78 public function getErrors() { 79 return $this->errors; 80 } 81 82 /** 83 * Have the settings been changed since loading from disk? 84 * 85 * @return bool 86 */ 87 public function hasChanged() { 88 return $this->changed; 89 } 90 91 /** 92 * Check if the config can be written 93 * 94 * @return bool 95 */ 96 public function isLocked() { 97 return $this->writer->isLocked(); 98 } 99 100 /** 101 * Update the settings using the data provided 102 * 103 * @param array $input as posted 104 * @return bool true if all updates went through, false on errors 105 */ 106 public function updateSettings($input) { 107 $ok = true; 108 109 foreach($this->settings as $key => $obj) { 110 $value = isset($input[$key]) ? $input[$key] : null; 111 if($obj->update($value)) { 112 $this->changed = true; 113 } 114 if($obj->hasError()) $ok = false; 115 } 116 117 return $ok; 118 } 119 120 /** 121 * Save the settings 122 * 123 * @throws \Exception 124 */ 125 public function save() { 126 $this->writer->save($this->settings); 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->errors[$key] = 'no default'; 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[] = $obj; 188 } else { 189 $obj = new SettingUndefined($key); 190 $this->undefined[] = $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($class) { 205 $modern = str_replace('_', '', ucwords($class, '_')); 206 $modern = '\\dokuwiki\\plugin\\config\\core\\' . $modern; 207 if($modern && class_exists($modern)) return $modern; 208 // class wasn't found add to errors 209 $this->errors[$key] = 'unknown class'; 210 } else { 211 // no class given, add to errors 212 $this->errors[$key] = 'no class'; 213 } 214 return '\\dokuwiki\\plugin\\config\\core\\Setting'; 215 } 216 217} 218