Configuration.php 6.0 KB

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