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