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 */ 188c7c53b0SAndreas Gohrclass Configuration 198c7c53b0SAndreas Gohr{ 20c6639e6aSAndreas Gohr 21bf9be0e3SAndreas Gohr public const KEYMARKER = '____'; 22c6639e6aSAndreas Gohr 23077c27b2SAndreas Gohr /** @var Setting[] metadata as array of Settings objects */ 24467c1427SAndreas Gohr protected $settings = []; 257a0ee538SAndreas Gohr /** @var Setting[] undefined and problematic settings */ 26467c1427SAndreas Gohr protected $undefined = []; 278ea5685fSAndreas Gohr 28077c27b2SAndreas Gohr /** @var array all metadata */ 29077c27b2SAndreas Gohr protected $metadata; 30077c27b2SAndreas Gohr /** @var array all default settings */ 31077c27b2SAndreas Gohr protected $default; 32077c27b2SAndreas Gohr /** @var array all local settings */ 33077c27b2SAndreas Gohr protected $local; 34077c27b2SAndreas Gohr /** @var array all protected settings */ 35077c27b2SAndreas Gohr protected $protected; 36077c27b2SAndreas Gohr 37077c27b2SAndreas Gohr /** @var bool have the settings been changed since loading from disk? */ 38077c27b2SAndreas Gohr protected $changed = false; 39077c27b2SAndreas Gohr 405675a07cSAndreas Gohr /** @var Loader */ 415675a07cSAndreas Gohr protected $loader; 42077c27b2SAndreas Gohr /** @var Writer */ 43077c27b2SAndreas Gohr protected $writer; 448ea5685fSAndreas Gohr 45c6639e6aSAndreas Gohr /** 46077c27b2SAndreas Gohr * ConfigSettings constructor. 47c6639e6aSAndreas Gohr */ 48*d868eb89SAndreas Gohr public function __construct() 49*d868eb89SAndreas Gohr { 505675a07cSAndreas Gohr $this->loader = new Loader(new ConfigParser()); 51077c27b2SAndreas Gohr $this->writer = new Writer(); 52077c27b2SAndreas Gohr 535675a07cSAndreas Gohr $this->metadata = $this->loader->loadMeta(); 545675a07cSAndreas Gohr $this->default = $this->loader->loadDefaults(); 555675a07cSAndreas Gohr $this->local = $this->loader->loadLocal(); 565675a07cSAndreas Gohr $this->protected = $this->loader->loadProtected(); 57077c27b2SAndreas Gohr 58077c27b2SAndreas Gohr $this->initSettings(); 59c6639e6aSAndreas Gohr } 60c6639e6aSAndreas Gohr 61c6639e6aSAndreas Gohr /** 62077c27b2SAndreas Gohr * Get all settings 63c6639e6aSAndreas Gohr * 64077c27b2SAndreas Gohr * @return Setting[] 65c6639e6aSAndreas Gohr */ 66*d868eb89SAndreas Gohr public function getSettings() 67*d868eb89SAndreas Gohr { 68077c27b2SAndreas Gohr return $this->settings; 69c6639e6aSAndreas Gohr } 70c6639e6aSAndreas Gohr 71077c27b2SAndreas Gohr /** 727a0ee538SAndreas Gohr * Get all unknown or problematic settings 73077c27b2SAndreas Gohr * 74077c27b2SAndreas Gohr * @return Setting[] 75077c27b2SAndreas Gohr */ 76*d868eb89SAndreas Gohr public function getUndefined() 77*d868eb89SAndreas Gohr { 78077c27b2SAndreas Gohr return $this->undefined; 79c6639e6aSAndreas Gohr } 80c6639e6aSAndreas Gohr 81077c27b2SAndreas Gohr /** 82077c27b2SAndreas Gohr * Have the settings been changed since loading from disk? 83077c27b2SAndreas Gohr * 84077c27b2SAndreas Gohr * @return bool 85077c27b2SAndreas Gohr */ 86*d868eb89SAndreas Gohr public function hasChanged() 87*d868eb89SAndreas Gohr { 88077c27b2SAndreas Gohr return $this->changed; 89077c27b2SAndreas Gohr } 90077c27b2SAndreas Gohr 91077c27b2SAndreas Gohr /** 92077c27b2SAndreas Gohr * Check if the config can be written 93077c27b2SAndreas Gohr * 94077c27b2SAndreas Gohr * @return bool 95077c27b2SAndreas Gohr */ 96*d868eb89SAndreas Gohr public function isLocked() 97*d868eb89SAndreas Gohr { 98077c27b2SAndreas Gohr return $this->writer->isLocked(); 99077c27b2SAndreas Gohr } 100077c27b2SAndreas Gohr 101077c27b2SAndreas Gohr /** 102077c27b2SAndreas Gohr * Update the settings using the data provided 103077c27b2SAndreas Gohr * 104077c27b2SAndreas Gohr * @param array $input as posted 105077c27b2SAndreas Gohr * @return bool true if all updates went through, false on errors 106077c27b2SAndreas Gohr */ 107*d868eb89SAndreas Gohr public function updateSettings($input) 108*d868eb89SAndreas Gohr { 109077c27b2SAndreas Gohr $ok = true; 110077c27b2SAndreas Gohr 111077c27b2SAndreas Gohr foreach($this->settings as $key => $obj) { 112467c1427SAndreas Gohr $value = $input[$key] ?? null; 113077c27b2SAndreas Gohr if($obj->update($value)) { 114077c27b2SAndreas Gohr $this->changed = true; 115077c27b2SAndreas Gohr } 1165c17d2d3SAndreas Gohr if($obj->hasError()) $ok = false; 117077c27b2SAndreas Gohr } 118077c27b2SAndreas Gohr 119077c27b2SAndreas Gohr return $ok; 120077c27b2SAndreas Gohr } 121077c27b2SAndreas Gohr 122077c27b2SAndreas Gohr /** 123077c27b2SAndreas Gohr * Save the settings 124077c27b2SAndreas Gohr * 12553f3816eSAndreas Gohr * This save the current state as defined in this object, including the 12653f3816eSAndreas Gohr * undefined settings 12753f3816eSAndreas Gohr * 128077c27b2SAndreas Gohr * @throws \Exception 129077c27b2SAndreas Gohr */ 130*d868eb89SAndreas Gohr public function save() 131*d868eb89SAndreas Gohr { 1327a0ee538SAndreas Gohr // only save the undefined settings that have not been handled in settings 1337a0ee538SAndreas Gohr $undefined = array_diff_key($this->undefined, $this->settings); 1347a0ee538SAndreas Gohr $this->writer->save(array_merge($this->settings, $undefined)); 135077c27b2SAndreas Gohr } 136077c27b2SAndreas Gohr 137077c27b2SAndreas Gohr /** 138077c27b2SAndreas Gohr * Touch the settings 139077c27b2SAndreas Gohr * 140077c27b2SAndreas Gohr * @throws \Exception 141077c27b2SAndreas Gohr */ 142*d868eb89SAndreas Gohr public function touch() 143*d868eb89SAndreas Gohr { 144077c27b2SAndreas Gohr $this->writer->touch(); 145077c27b2SAndreas Gohr } 146077c27b2SAndreas Gohr 147077c27b2SAndreas Gohr /** 1485675a07cSAndreas Gohr * Load the extension language strings 1495675a07cSAndreas Gohr * 1505675a07cSAndreas Gohr * @return array 1515675a07cSAndreas Gohr */ 152*d868eb89SAndreas Gohr public function getLangs() 153*d868eb89SAndreas Gohr { 1545675a07cSAndreas Gohr return $this->loader->loadLangs(); 1555675a07cSAndreas Gohr } 1565675a07cSAndreas Gohr 1575675a07cSAndreas Gohr /** 158077c27b2SAndreas Gohr * Initalizes the $settings and $undefined properties 159077c27b2SAndreas Gohr */ 160*d868eb89SAndreas Gohr protected function initSettings() 161*d868eb89SAndreas Gohr { 162467c1427SAndreas Gohr $keys = [ 163467c1427SAndreas Gohr ...array_keys($this->metadata), 164467c1427SAndreas Gohr ...array_keys($this->default), 165467c1427SAndreas Gohr ...array_keys($this->local), 166467c1427SAndreas Gohr ...array_keys($this->protected) 167467c1427SAndreas Gohr ]; 168077c27b2SAndreas Gohr $keys = array_unique($keys); 169077c27b2SAndreas Gohr 170077c27b2SAndreas Gohr foreach($keys as $key) { 171077c27b2SAndreas Gohr $obj = $this->instantiateClass($key); 172077c27b2SAndreas Gohr 173077c27b2SAndreas Gohr if($obj->shouldHaveDefault() && !isset($this->default[$key])) { 1747a0ee538SAndreas Gohr $this->undefined[$key] = new SettingNoDefault($key); 175077c27b2SAndreas Gohr } 176077c27b2SAndreas Gohr 177467c1427SAndreas Gohr $d = $this->default[$key] ?? null; 178467c1427SAndreas Gohr $l = $this->local[$key] ?? null; 179467c1427SAndreas Gohr $p = $this->protected[$key] ?? null; 180077c27b2SAndreas Gohr 181077c27b2SAndreas Gohr $obj->initialize($d, $l, $p); 182077c27b2SAndreas Gohr } 183077c27b2SAndreas Gohr } 184077c27b2SAndreas Gohr 185077c27b2SAndreas Gohr /** 186077c27b2SAndreas Gohr * Instantiates the proper class for the given config key 187077c27b2SAndreas Gohr * 188077c27b2SAndreas Gohr * The class is added to the $settings or $undefined arrays and returned 189077c27b2SAndreas Gohr * 190077c27b2SAndreas Gohr * @param string $key 191077c27b2SAndreas Gohr * @return Setting 192077c27b2SAndreas Gohr */ 193*d868eb89SAndreas Gohr protected function instantiateClass($key) 194*d868eb89SAndreas Gohr { 195077c27b2SAndreas Gohr if(isset($this->metadata[$key])) { 196077c27b2SAndreas Gohr $param = $this->metadata[$key]; 197077c27b2SAndreas Gohr $class = $this->determineClassName(array_shift($param), $key); // first param is class 198077c27b2SAndreas Gohr $obj = new $class($key, $param); 199d6987bddSAndreas Gohr $this->settings[$key] = $obj; 200077c27b2SAndreas Gohr } else { 201077c27b2SAndreas Gohr $obj = new SettingUndefined($key); 202d6987bddSAndreas Gohr $this->undefined[$key] = $obj; 203077c27b2SAndreas Gohr } 204077c27b2SAndreas Gohr return $obj; 205077c27b2SAndreas Gohr } 206077c27b2SAndreas Gohr 207077c27b2SAndreas Gohr /** 208077c27b2SAndreas Gohr * Return the class to load 209077c27b2SAndreas Gohr * 210077c27b2SAndreas Gohr * @param string $class the class name as given in the meta file 211077c27b2SAndreas Gohr * @param string $key the settings key 212077c27b2SAndreas Gohr * @return string 213077c27b2SAndreas Gohr */ 214*d868eb89SAndreas Gohr protected function determineClassName($class, $key) 215*d868eb89SAndreas Gohr { 216077c27b2SAndreas Gohr // try namespaced class first 217b71f2463SAndreas Gohr if(is_string($class)) { 218077c27b2SAndreas Gohr $modern = str_replace('_', '', ucwords($class, '_')); 2190a5b05ebSAndreas Gohr $modern = '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting' . $modern; 220077c27b2SAndreas Gohr if($modern && class_exists($modern)) return $modern; 2210a5b05ebSAndreas Gohr // try class as given 2220a5b05ebSAndreas Gohr if(class_exists($class)) return $class; 223077c27b2SAndreas Gohr // class wasn't found add to errors 2247a0ee538SAndreas Gohr $this->undefined[$key] = new SettingNoKnownClass($key); 225077c27b2SAndreas Gohr } else { 226077c27b2SAndreas Gohr // no class given, add to errors 2277a0ee538SAndreas Gohr $this->undefined[$key] = new SettingNoClass($key); 228077c27b2SAndreas Gohr } 2290a5b05ebSAndreas Gohr return '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting'; 230077c27b2SAndreas Gohr } 231077c27b2SAndreas Gohr} 232