You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

231 lines
6.0 KiB

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