xref: /dokuwiki/lib/plugins/config/core/Configuration.php (revision 0a5b05eba6ee3c7824187b015b4e1bbc9658bb5d)
1c6639e6aSAndreas Gohr<?php
2c6639e6aSAndreas Gohr
3c6639e6aSAndreas Gohrnamespace dokuwiki\plugin\config\core;
4*0a5b05ebSAndreas Gohruse dokuwiki\plugin\config\core\Setting\Setting;
5*0a5b05ebSAndreas Gohruse dokuwiki\plugin\config\core\Setting\SettingUndefined;
6c6639e6aSAndreas Gohr
7c6639e6aSAndreas Gohr/**
85675a07cSAndreas Gohr * Holds all the current settings and proxies the Loader and Writer
9077c27b2SAndreas Gohr *
10077c27b2SAndreas Gohr * @author Chris Smith <chris@jalakai.co.uk>
11077c27b2SAndreas Gohr * @author Ben Coburn <btcoburn@silicodon.net>
12077c27b2SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
13c6639e6aSAndreas Gohr */
14c6639e6aSAndreas Gohrclass Configuration {
15c6639e6aSAndreas Gohr
16c6639e6aSAndreas Gohr    const KEYMARKER = '____';
17c6639e6aSAndreas Gohr
18077c27b2SAndreas Gohr    /** @var Setting[] metadata as array of Settings objects */
19077c27b2SAndreas Gohr    protected $settings = array();
20077c27b2SAndreas Gohr    /** @var array problematic keys */
21077c27b2SAndreas Gohr    protected $errors;
22077c27b2SAndreas Gohr    /** @var Setting[] undefined settings */
23077c27b2SAndreas Gohr    protected $undefined = array();
248ea5685fSAndreas Gohr
25077c27b2SAndreas Gohr    /** @var array all metadata */
26077c27b2SAndreas Gohr    protected $metadata;
27077c27b2SAndreas Gohr    /** @var array all default settings */
28077c27b2SAndreas Gohr    protected $default;
29077c27b2SAndreas Gohr    /** @var array all local settings */
30077c27b2SAndreas Gohr    protected $local;
31077c27b2SAndreas Gohr    /** @var array all protected settings */
32077c27b2SAndreas Gohr    protected $protected;
33077c27b2SAndreas Gohr
34077c27b2SAndreas Gohr    /** @var bool have the settings been changed since loading from disk? */
35077c27b2SAndreas Gohr    protected $changed = false;
36077c27b2SAndreas Gohr
375675a07cSAndreas Gohr    /** @var Loader */
385675a07cSAndreas Gohr    protected $loader;
39077c27b2SAndreas Gohr    /** @var Writer */
40077c27b2SAndreas Gohr    protected $writer;
418ea5685fSAndreas Gohr
42c6639e6aSAndreas Gohr    /**
43077c27b2SAndreas Gohr     * ConfigSettings constructor.
44c6639e6aSAndreas Gohr     */
455a38a129SAndreas Gohr    public function __construct() {
465675a07cSAndreas Gohr        $this->loader = new Loader(new ConfigParser());
47077c27b2SAndreas Gohr        $this->writer = new Writer();
48077c27b2SAndreas Gohr
495675a07cSAndreas Gohr        $this->metadata = $this->loader->loadMeta();
505675a07cSAndreas Gohr        $this->default = $this->loader->loadDefaults();
515675a07cSAndreas Gohr        $this->local = $this->loader->loadLocal();
525675a07cSAndreas Gohr        $this->protected = $this->loader->loadProtected();
53077c27b2SAndreas Gohr
54077c27b2SAndreas Gohr        $this->initSettings();
55c6639e6aSAndreas Gohr    }
56c6639e6aSAndreas Gohr
57c6639e6aSAndreas Gohr    /**
58077c27b2SAndreas Gohr     * Get all settings
59c6639e6aSAndreas Gohr     *
60077c27b2SAndreas Gohr     * @return Setting[]
61c6639e6aSAndreas Gohr     */
62077c27b2SAndreas Gohr    public function getSettings() {
63077c27b2SAndreas Gohr        return $this->settings;
64c6639e6aSAndreas Gohr    }
65c6639e6aSAndreas Gohr
66077c27b2SAndreas Gohr    /**
67077c27b2SAndreas Gohr     * Get all unknown settings
68077c27b2SAndreas Gohr     *
69077c27b2SAndreas Gohr     * @return Setting[]
70077c27b2SAndreas Gohr     */
71077c27b2SAndreas Gohr    public function getUndefined() {
72077c27b2SAndreas Gohr        return $this->undefined;
73c6639e6aSAndreas Gohr    }
74c6639e6aSAndreas Gohr
75077c27b2SAndreas Gohr    /**
76077c27b2SAndreas Gohr     * Get the settings that had some kind of setup problem
77077c27b2SAndreas Gohr     *
78077c27b2SAndreas Gohr     * @return array associative error, key is the setting, value the error
79077c27b2SAndreas Gohr     */
80077c27b2SAndreas Gohr    public function getErrors() {
81077c27b2SAndreas Gohr        return $this->errors;
82077c27b2SAndreas Gohr    }
83077c27b2SAndreas Gohr
84077c27b2SAndreas Gohr    /**
85077c27b2SAndreas Gohr     * Have the settings been changed since loading from disk?
86077c27b2SAndreas Gohr     *
87077c27b2SAndreas Gohr     * @return bool
88077c27b2SAndreas Gohr     */
89077c27b2SAndreas Gohr    public function hasChanged() {
90077c27b2SAndreas Gohr        return $this->changed;
91077c27b2SAndreas Gohr    }
92077c27b2SAndreas Gohr
93077c27b2SAndreas Gohr    /**
94077c27b2SAndreas Gohr     * Check if the config can be written
95077c27b2SAndreas Gohr     *
96077c27b2SAndreas Gohr     * @return bool
97077c27b2SAndreas Gohr     */
98077c27b2SAndreas Gohr    public function isLocked() {
99077c27b2SAndreas Gohr        return $this->writer->isLocked();
100077c27b2SAndreas Gohr    }
101077c27b2SAndreas Gohr
102077c27b2SAndreas Gohr    /**
103077c27b2SAndreas Gohr     * Update the settings using the data provided
104077c27b2SAndreas Gohr     *
105077c27b2SAndreas Gohr     * @param array $input as posted
106077c27b2SAndreas Gohr     * @return bool true if all updates went through, false on errors
107077c27b2SAndreas Gohr     */
108077c27b2SAndreas Gohr    public function updateSettings($input) {
109077c27b2SAndreas Gohr        $ok = true;
110077c27b2SAndreas Gohr
111077c27b2SAndreas Gohr        foreach($this->settings as $key => $obj) {
112077c27b2SAndreas Gohr            $value = isset($input[$key]) ? $input[$key] : null;
113077c27b2SAndreas Gohr            if($obj->update($value)) {
114077c27b2SAndreas Gohr                $this->changed = true;
115077c27b2SAndreas Gohr            }
1165c17d2d3SAndreas Gohr            if($obj->hasError()) $ok = false;
117077c27b2SAndreas Gohr        }
118077c27b2SAndreas Gohr
119077c27b2SAndreas Gohr        return $ok;
120077c27b2SAndreas Gohr    }
121077c27b2SAndreas Gohr
122077c27b2SAndreas Gohr    /**
123077c27b2SAndreas Gohr     * Save the settings
124077c27b2SAndreas Gohr     *
125077c27b2SAndreas Gohr     * @throws \Exception
126077c27b2SAndreas Gohr     */
127077c27b2SAndreas Gohr    public function save() {
128077c27b2SAndreas Gohr        $this->writer->save($this->settings);
129077c27b2SAndreas Gohr    }
130077c27b2SAndreas Gohr
131077c27b2SAndreas Gohr    /**
132077c27b2SAndreas Gohr     * Touch the settings
133077c27b2SAndreas Gohr     *
134077c27b2SAndreas Gohr     * @throws \Exception
135077c27b2SAndreas Gohr     */
136077c27b2SAndreas Gohr    public function touch() {
137077c27b2SAndreas Gohr        $this->writer->touch();
138077c27b2SAndreas Gohr    }
139077c27b2SAndreas Gohr
140077c27b2SAndreas Gohr    /**
1415675a07cSAndreas Gohr     * Load the extension language strings
1425675a07cSAndreas Gohr     *
1435675a07cSAndreas Gohr     * @return array
1445675a07cSAndreas Gohr     */
1455675a07cSAndreas Gohr    public function getLangs() {
1465675a07cSAndreas Gohr        return $this->loader->loadLangs();
1475675a07cSAndreas Gohr    }
1485675a07cSAndreas Gohr
1495675a07cSAndreas Gohr    /**
150077c27b2SAndreas Gohr     * Initalizes the $settings and $undefined properties
151077c27b2SAndreas Gohr     */
152077c27b2SAndreas Gohr    protected function initSettings() {
153077c27b2SAndreas Gohr        $keys = array_merge(
154077c27b2SAndreas Gohr            array_keys($this->metadata),
155077c27b2SAndreas Gohr            array_keys($this->default),
156077c27b2SAndreas Gohr            array_keys($this->local),
157077c27b2SAndreas Gohr            array_keys($this->protected)
158077c27b2SAndreas Gohr        );
159077c27b2SAndreas Gohr        $keys = array_unique($keys);
160077c27b2SAndreas Gohr
161077c27b2SAndreas Gohr        foreach($keys as $key) {
162077c27b2SAndreas Gohr            $obj = $this->instantiateClass($key);
163077c27b2SAndreas Gohr
164077c27b2SAndreas Gohr            if($obj->shouldHaveDefault() && !isset($this->default[$key])) {
165077c27b2SAndreas Gohr                $this->errors[$key] = 'no default';
166077c27b2SAndreas Gohr            }
167077c27b2SAndreas Gohr
168077c27b2SAndreas Gohr            $d = isset($this->default[$key]) ? $this->default[$key] : null;
169077c27b2SAndreas Gohr            $l = isset($this->local[$key]) ? $this->local[$key] : null;
170077c27b2SAndreas Gohr            $p = isset($this->protected[$key]) ? $this->protected[$key] : null;
171077c27b2SAndreas Gohr
172077c27b2SAndreas Gohr            $obj->initialize($d, $l, $p);
173077c27b2SAndreas Gohr        }
174077c27b2SAndreas Gohr    }
175077c27b2SAndreas Gohr
176077c27b2SAndreas Gohr    /**
177077c27b2SAndreas Gohr     * Instantiates the proper class for the given config key
178077c27b2SAndreas Gohr     *
179077c27b2SAndreas Gohr     * The class is added to the $settings or $undefined arrays and returned
180077c27b2SAndreas Gohr     *
181077c27b2SAndreas Gohr     * @param string $key
182077c27b2SAndreas Gohr     * @return Setting
183077c27b2SAndreas Gohr     */
184077c27b2SAndreas Gohr    protected function instantiateClass($key) {
185077c27b2SAndreas Gohr        if(isset($this->metadata[$key])) {
186077c27b2SAndreas Gohr            $param = $this->metadata[$key];
187077c27b2SAndreas Gohr            $class = $this->determineClassName(array_shift($param), $key); // first param is class
188077c27b2SAndreas Gohr            $obj = new $class($key, $param);
189077c27b2SAndreas Gohr            $this->settings[] = $obj;
190077c27b2SAndreas Gohr        } else {
191077c27b2SAndreas Gohr            $obj = new SettingUndefined($key);
192077c27b2SAndreas Gohr            $this->undefined[] = $obj;
193077c27b2SAndreas Gohr        }
194077c27b2SAndreas Gohr        return $obj;
195077c27b2SAndreas Gohr    }
196077c27b2SAndreas Gohr
197077c27b2SAndreas Gohr    /**
198077c27b2SAndreas Gohr     * Return the class to load
199077c27b2SAndreas Gohr     *
200077c27b2SAndreas Gohr     * @param string $class the class name as given in the meta file
201077c27b2SAndreas Gohr     * @param string $key the settings key
202077c27b2SAndreas Gohr     * @return string
203077c27b2SAndreas Gohr     */
204077c27b2SAndreas Gohr    protected function determineClassName($class, $key) {
205077c27b2SAndreas Gohr        // try namespaced class first
206077c27b2SAndreas Gohr        if($class) {
207077c27b2SAndreas Gohr            $modern = str_replace('_', '', ucwords($class, '_'));
208*0a5b05ebSAndreas Gohr            $modern = '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting' . $modern;
209077c27b2SAndreas Gohr            if($modern && class_exists($modern)) return $modern;
210*0a5b05ebSAndreas Gohr            // try class as given
211*0a5b05ebSAndreas Gohr            if(class_exists($class)) return $class;
212077c27b2SAndreas Gohr            // class wasn't found add to errors
213077c27b2SAndreas Gohr            $this->errors[$key] = 'unknown class';
214077c27b2SAndreas Gohr        } else {
215077c27b2SAndreas Gohr            // no class given, add to errors
216077c27b2SAndreas Gohr            $this->errors[$key] = 'no class';
217077c27b2SAndreas Gohr        }
218*0a5b05ebSAndreas Gohr        return '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting';
219077c27b2SAndreas Gohr    }
220077c27b2SAndreas Gohr
221077c27b2SAndreas Gohr}
222