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