1c6639e6aSAndreas Gohr<?php 2c6639e6aSAndreas Gohr 3c6639e6aSAndreas Gohrnamespace dokuwiki\plugin\config\core; 47a0ee538SAndreas Gohr 50a5b05ebSAndreas Gohruse dokuwiki\plugin\config\core\Setting\Setting; 67a0ee538SAndreas Gohruse dokuwiki\plugin\config\core\Setting\SettingNoClass; 77a0ee538SAndreas Gohruse dokuwiki\plugin\config\core\Setting\SettingNoDefault; 87a0ee538SAndreas Gohruse dokuwiki\plugin\config\core\Setting\SettingNoKnownClass; 90a5b05ebSAndreas Gohruse dokuwiki\plugin\config\core\Setting\SettingUndefined; 10c6639e6aSAndreas Gohr 11c6639e6aSAndreas Gohr/** 125675a07cSAndreas Gohr * Holds all the current settings and proxies the Loader and Writer 13077c27b2SAndreas Gohr * 14077c27b2SAndreas Gohr * @author Chris Smith <chris@jalakai.co.uk> 15077c27b2SAndreas Gohr * @author Ben Coburn <btcoburn@silicodon.net> 16077c27b2SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 17c6639e6aSAndreas Gohr */ 18c6639e6aSAndreas Gohrclass Configuration { 19c6639e6aSAndreas Gohr 20c6639e6aSAndreas Gohr const KEYMARKER = '____'; 21c6639e6aSAndreas Gohr 22077c27b2SAndreas Gohr /** @var Setting[] metadata as array of Settings objects */ 23*467c1427SAndreas Gohr protected $settings = []; 247a0ee538SAndreas Gohr /** @var Setting[] undefined and problematic settings */ 25*467c1427SAndreas Gohr protected $undefined = []; 268ea5685fSAndreas Gohr 27077c27b2SAndreas Gohr /** @var array all metadata */ 28077c27b2SAndreas Gohr protected $metadata; 29077c27b2SAndreas Gohr /** @var array all default settings */ 30077c27b2SAndreas Gohr protected $default; 31077c27b2SAndreas Gohr /** @var array all local settings */ 32077c27b2SAndreas Gohr protected $local; 33077c27b2SAndreas Gohr /** @var array all protected settings */ 34077c27b2SAndreas Gohr protected $protected; 35077c27b2SAndreas Gohr 36077c27b2SAndreas Gohr /** @var bool have the settings been changed since loading from disk? */ 37077c27b2SAndreas Gohr protected $changed = false; 38077c27b2SAndreas Gohr 395675a07cSAndreas Gohr /** @var Loader */ 405675a07cSAndreas Gohr protected $loader; 41077c27b2SAndreas Gohr /** @var Writer */ 42077c27b2SAndreas Gohr protected $writer; 438ea5685fSAndreas Gohr 44c6639e6aSAndreas Gohr /** 45077c27b2SAndreas Gohr * ConfigSettings constructor. 46c6639e6aSAndreas Gohr */ 475a38a129SAndreas Gohr public function __construct() { 485675a07cSAndreas Gohr $this->loader = new Loader(new ConfigParser()); 49077c27b2SAndreas Gohr $this->writer = new Writer(); 50077c27b2SAndreas Gohr 515675a07cSAndreas Gohr $this->metadata = $this->loader->loadMeta(); 525675a07cSAndreas Gohr $this->default = $this->loader->loadDefaults(); 535675a07cSAndreas Gohr $this->local = $this->loader->loadLocal(); 545675a07cSAndreas Gohr $this->protected = $this->loader->loadProtected(); 55077c27b2SAndreas Gohr 56077c27b2SAndreas Gohr $this->initSettings(); 57c6639e6aSAndreas Gohr } 58c6639e6aSAndreas Gohr 59c6639e6aSAndreas Gohr /** 60077c27b2SAndreas Gohr * Get all settings 61c6639e6aSAndreas Gohr * 62077c27b2SAndreas Gohr * @return Setting[] 63c6639e6aSAndreas Gohr */ 64077c27b2SAndreas Gohr public function getSettings() { 65077c27b2SAndreas Gohr return $this->settings; 66c6639e6aSAndreas Gohr } 67c6639e6aSAndreas Gohr 68077c27b2SAndreas Gohr /** 697a0ee538SAndreas Gohr * Get all unknown or problematic settings 70077c27b2SAndreas Gohr * 71077c27b2SAndreas Gohr * @return Setting[] 72077c27b2SAndreas Gohr */ 73077c27b2SAndreas Gohr public function getUndefined() { 74077c27b2SAndreas Gohr return $this->undefined; 75c6639e6aSAndreas Gohr } 76c6639e6aSAndreas Gohr 77077c27b2SAndreas Gohr /** 78077c27b2SAndreas Gohr * Have the settings been changed since loading from disk? 79077c27b2SAndreas Gohr * 80077c27b2SAndreas Gohr * @return bool 81077c27b2SAndreas Gohr */ 82077c27b2SAndreas Gohr public function hasChanged() { 83077c27b2SAndreas Gohr return $this->changed; 84077c27b2SAndreas Gohr } 85077c27b2SAndreas Gohr 86077c27b2SAndreas Gohr /** 87077c27b2SAndreas Gohr * Check if the config can be written 88077c27b2SAndreas Gohr * 89077c27b2SAndreas Gohr * @return bool 90077c27b2SAndreas Gohr */ 91077c27b2SAndreas Gohr public function isLocked() { 92077c27b2SAndreas Gohr return $this->writer->isLocked(); 93077c27b2SAndreas Gohr } 94077c27b2SAndreas Gohr 95077c27b2SAndreas Gohr /** 96077c27b2SAndreas Gohr * Update the settings using the data provided 97077c27b2SAndreas Gohr * 98077c27b2SAndreas Gohr * @param array $input as posted 99077c27b2SAndreas Gohr * @return bool true if all updates went through, false on errors 100077c27b2SAndreas Gohr */ 101077c27b2SAndreas Gohr public function updateSettings($input) { 102077c27b2SAndreas Gohr $ok = true; 103077c27b2SAndreas Gohr 104077c27b2SAndreas Gohr foreach($this->settings as $key => $obj) { 105*467c1427SAndreas Gohr $value = $input[$key] ?? null; 106077c27b2SAndreas Gohr if($obj->update($value)) { 107077c27b2SAndreas Gohr $this->changed = true; 108077c27b2SAndreas Gohr } 1095c17d2d3SAndreas Gohr if($obj->hasError()) $ok = false; 110077c27b2SAndreas Gohr } 111077c27b2SAndreas Gohr 112077c27b2SAndreas Gohr return $ok; 113077c27b2SAndreas Gohr } 114077c27b2SAndreas Gohr 115077c27b2SAndreas Gohr /** 116077c27b2SAndreas Gohr * Save the settings 117077c27b2SAndreas Gohr * 11853f3816eSAndreas Gohr * This save the current state as defined in this object, including the 11953f3816eSAndreas Gohr * undefined settings 12053f3816eSAndreas Gohr * 121077c27b2SAndreas Gohr * @throws \Exception 122077c27b2SAndreas Gohr */ 123077c27b2SAndreas Gohr public function save() { 1247a0ee538SAndreas Gohr // only save the undefined settings that have not been handled in settings 1257a0ee538SAndreas Gohr $undefined = array_diff_key($this->undefined, $this->settings); 1267a0ee538SAndreas Gohr $this->writer->save(array_merge($this->settings, $undefined)); 127077c27b2SAndreas Gohr } 128077c27b2SAndreas Gohr 129077c27b2SAndreas Gohr /** 130077c27b2SAndreas Gohr * Touch the settings 131077c27b2SAndreas Gohr * 132077c27b2SAndreas Gohr * @throws \Exception 133077c27b2SAndreas Gohr */ 134077c27b2SAndreas Gohr public function touch() { 135077c27b2SAndreas Gohr $this->writer->touch(); 136077c27b2SAndreas Gohr } 137077c27b2SAndreas Gohr 138077c27b2SAndreas Gohr /** 1395675a07cSAndreas Gohr * Load the extension language strings 1405675a07cSAndreas Gohr * 1415675a07cSAndreas Gohr * @return array 1425675a07cSAndreas Gohr */ 1435675a07cSAndreas Gohr public function getLangs() { 1445675a07cSAndreas Gohr return $this->loader->loadLangs(); 1455675a07cSAndreas Gohr } 1465675a07cSAndreas Gohr 1475675a07cSAndreas Gohr /** 148077c27b2SAndreas Gohr * Initalizes the $settings and $undefined properties 149077c27b2SAndreas Gohr */ 150077c27b2SAndreas Gohr protected function initSettings() { 151*467c1427SAndreas Gohr $keys = [ 152*467c1427SAndreas Gohr ...array_keys($this->metadata), 153*467c1427SAndreas Gohr ...array_keys($this->default), 154*467c1427SAndreas Gohr ...array_keys($this->local), 155*467c1427SAndreas Gohr ...array_keys($this->protected) 156*467c1427SAndreas Gohr ]; 157077c27b2SAndreas Gohr $keys = array_unique($keys); 158077c27b2SAndreas Gohr 159077c27b2SAndreas Gohr foreach($keys as $key) { 160077c27b2SAndreas Gohr $obj = $this->instantiateClass($key); 161077c27b2SAndreas Gohr 162077c27b2SAndreas Gohr if($obj->shouldHaveDefault() && !isset($this->default[$key])) { 1637a0ee538SAndreas Gohr $this->undefined[$key] = new SettingNoDefault($key); 164077c27b2SAndreas Gohr } 165077c27b2SAndreas Gohr 166*467c1427SAndreas Gohr $d = $this->default[$key] ?? null; 167*467c1427SAndreas Gohr $l = $this->local[$key] ?? null; 168*467c1427SAndreas Gohr $p = $this->protected[$key] ?? null; 169077c27b2SAndreas Gohr 170077c27b2SAndreas Gohr $obj->initialize($d, $l, $p); 171077c27b2SAndreas Gohr } 172077c27b2SAndreas Gohr } 173077c27b2SAndreas Gohr 174077c27b2SAndreas Gohr /** 175077c27b2SAndreas Gohr * Instantiates the proper class for the given config key 176077c27b2SAndreas Gohr * 177077c27b2SAndreas Gohr * The class is added to the $settings or $undefined arrays and returned 178077c27b2SAndreas Gohr * 179077c27b2SAndreas Gohr * @param string $key 180077c27b2SAndreas Gohr * @return Setting 181077c27b2SAndreas Gohr */ 182077c27b2SAndreas Gohr protected function instantiateClass($key) { 183077c27b2SAndreas Gohr if(isset($this->metadata[$key])) { 184077c27b2SAndreas Gohr $param = $this->metadata[$key]; 185077c27b2SAndreas Gohr $class = $this->determineClassName(array_shift($param), $key); // first param is class 186077c27b2SAndreas Gohr $obj = new $class($key, $param); 187d6987bddSAndreas Gohr $this->settings[$key] = $obj; 188077c27b2SAndreas Gohr } else { 189077c27b2SAndreas Gohr $obj = new SettingUndefined($key); 190d6987bddSAndreas Gohr $this->undefined[$key] = $obj; 191077c27b2SAndreas Gohr } 192077c27b2SAndreas Gohr return $obj; 193077c27b2SAndreas Gohr } 194077c27b2SAndreas Gohr 195077c27b2SAndreas Gohr /** 196077c27b2SAndreas Gohr * Return the class to load 197077c27b2SAndreas Gohr * 198077c27b2SAndreas Gohr * @param string $class the class name as given in the meta file 199077c27b2SAndreas Gohr * @param string $key the settings key 200077c27b2SAndreas Gohr * @return string 201077c27b2SAndreas Gohr */ 202077c27b2SAndreas Gohr protected function determineClassName($class, $key) { 203077c27b2SAndreas Gohr // try namespaced class first 204b71f2463SAndreas Gohr if(is_string($class)) { 205077c27b2SAndreas Gohr $modern = str_replace('_', '', ucwords($class, '_')); 2060a5b05ebSAndreas Gohr $modern = '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting' . $modern; 207077c27b2SAndreas Gohr if($modern && class_exists($modern)) return $modern; 2080a5b05ebSAndreas Gohr // try class as given 2090a5b05ebSAndreas Gohr if(class_exists($class)) return $class; 210077c27b2SAndreas Gohr // class wasn't found add to errors 2117a0ee538SAndreas Gohr $this->undefined[$key] = new SettingNoKnownClass($key); 212077c27b2SAndreas Gohr } else { 213077c27b2SAndreas Gohr // no class given, add to errors 2147a0ee538SAndreas Gohr $this->undefined[$key] = new SettingNoClass($key); 215077c27b2SAndreas Gohr } 2160a5b05ebSAndreas Gohr return '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting'; 217077c27b2SAndreas Gohr } 218077c27b2SAndreas Gohr 219077c27b2SAndreas Gohr} 220