xref: /dokuwiki/lib/plugins/config/core/Configuration.php (revision 077c27b25c8a3979615b1fd09426bce452b27423)
1<?php
2
3namespace dokuwiki\plugin\config\core;
4
5/**
6 * Holds all the current settings
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 Writer */
36    protected $writer;
37
38    /**
39     * ConfigSettings constructor.
40     */
41    public function __construct() {
42        $loader = new Loader(new ConfigParser());
43        $this->writer = new Writer();
44
45        $this->metadata = $loader->loadMeta();
46        $this->default = $loader->loadDefaults();
47        $this->local = $loader->loadLocal();
48        $this->protected = $loader->loadProtected();
49
50        $this->initSettings();
51    }
52
53    /**
54     * Get all settings
55     *
56     * @return Setting[]
57     */
58    public function getSettings() {
59        return $this->settings;
60    }
61
62    /**
63     * Get all unknown settings
64     *
65     * @return Setting[]
66     */
67    public function getUndefined() {
68        return $this->undefined;
69    }
70
71    /**
72     * Get the settings that had some kind of setup problem
73     *
74     * @return array associative error, key is the setting, value the error
75     */
76    public function getErrors() {
77        return $this->errors;
78    }
79
80    /**
81     * Have the settings been changed since loading from disk?
82     *
83     * @return bool
84     */
85    public function hasChanged() {
86        return $this->changed;
87    }
88
89    /**
90     * Check if the config can be written
91     *
92     * @return bool
93     */
94    public function isLocked() {
95        return $this->writer->isLocked();
96    }
97
98    /**
99     * Update the settings using the data provided
100     *
101     * @param array $input as posted
102     * @return bool true if all updates went through, false on errors
103     */
104    public function updateSettings($input) {
105        $ok = true;
106
107        foreach($this->settings as $key => $obj) {
108            $value = isset($input[$key]) ? $input[$key] : null;
109            if($obj->update($value)) {
110                $this->changed = true;
111            }
112            if($obj->error()) $ok = false;
113        }
114
115        return $ok;
116    }
117
118    /**
119     * Save the settings
120     *
121     * @throws \Exception
122     */
123    public function save() {
124        $this->writer->save($this->settings);
125    }
126
127    /**
128     * Touch the settings
129     *
130     * @throws \Exception
131     */
132    public function touch() {
133        $this->writer->touch();
134    }
135
136    /**
137     * Initalizes the $settings and $undefined properties
138     */
139    protected function initSettings() {
140        $keys = array_merge(
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
148        foreach($keys as $key) {
149            $obj = $this->instantiateClass($key);
150
151            if($obj->shouldHaveDefault() && !isset($this->default[$key])) {
152                $this->errors[$key] = 'no default';
153            }
154
155            $d = isset($this->default[$key]) ? $this->default[$key] : null;
156            $l = isset($this->local[$key]) ? $this->local[$key] : null;
157            $p = isset($this->protected[$key]) ? $this->protected[$key] : null;
158
159            $obj->initialize($d, $l, $p);
160        }
161    }
162
163    /**
164     * Instantiates the proper class for the given config key
165     *
166     * The class is added to the $settings or $undefined arrays and returned
167     *
168     * @param string $key
169     * @return Setting
170     */
171    protected function instantiateClass($key) {
172        if(isset($this->metadata[$key])) {
173            $param = $this->metadata[$key];
174            $class = $this->determineClassName(array_shift($param), $key); // first param is class
175            $obj = new $class($key, $param);
176            $this->settings[] = $obj;
177        } else {
178            $obj = new SettingUndefined($key);
179            $this->undefined[] = $obj;
180        }
181        return $obj;
182    }
183
184    /**
185     * Return the class to load
186     *
187     * @param string $class the class name as given in the meta file
188     * @param string $key the settings key
189     * @return string
190     */
191    protected function determineClassName($class, $key) {
192        // try namespaced class first
193        if($class) {
194            $modern = str_replace('_', '', ucwords($class, '_'));
195            $modern = '\\dokuwiki\\plugin\\config\\core\\' . $modern;
196            if($modern && class_exists($modern)) return $modern;
197            // class wasn't found add to errors
198            $this->errors[$key] = 'unknown class';
199        } else {
200            // no class given, add to errors
201            $this->errors[$key] = 'no class';
202        }
203        return '\\dokuwiki\\plugin\\config\\core\\Setting';
204    }
205
206}
207