xref: /dokuwiki/lib/plugins/config/admin.php (revision 5675a07c0fd72003cd7cbd0a02af629f8175300f)
1<?php
2/**
3 * Configuration Manager admin plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Christopher Smith <chris@jalakai.co.uk>
7 * @author     Ben Coburn <btcoburn@silicodon.net>
8 */
9
10use dokuwiki\plugin\config\core\Configuration;
11use dokuwiki\plugin\config\core\Setting;
12use dokuwiki\plugin\config\core\SettingFieldset;
13use dokuwiki\plugin\config\core\SettingHidden;
14
15/**
16 * All DokuWiki plugins to extend the admin function
17 * need to inherit from this class
18 */
19class admin_plugin_config extends DokuWiki_Admin_Plugin {
20
21    const METADATA = __DIR__ . 'settings/config.metadata.php';
22    const IMGDIR = DOKU_BASE . 'lib/plugins/config/images/';
23
24    protected $_localised_prompts = false;
25
26    /** @var Configuration */
27    protected $configuration;
28
29    /**
30     * admin_plugin_config constructor.
31     */
32    public function __construct() {
33        $this->configuration = new Configuration();
34    }
35
36    /**
37     * handle user request
38     */
39    public function handle() {
40        global $ID, $INPUT;
41
42        if(!$INPUT->bool('save') || !checkSecurityToken()) {
43            return;
44        }
45
46        // don't go any further if the configuration is locked
47        if($this->configuration->isLocked()) return;
48
49        // update settings and redirect of successful
50        $ok = $this->configuration->updateSettings($INPUT->arr('config'));
51        if($ok) { // no errors
52            try {
53                if($this->configuration->hasChanged()) {
54                    $this->configuration->save();
55                } else {
56                    $this->configuration->touch();
57                }
58                msg($this->getLang('updated'), -1);
59            } catch(Exception $e) {
60                msg($this->getLang('error'), -1);
61            }
62            send_redirect(wl($ID, array('do' => 'admin', 'page' => 'config'), true, '&'));
63        }
64    }
65
66    /**
67     * output appropriate html
68     */
69    public function html() {
70        $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here.
71        global $lang;
72        global $ID;
73
74        $this->setupLocale(true);
75
76        print $this->locale_xhtml('intro');
77
78        ptln('<div id="config__manager">');
79
80        if($this->configuration->isLocked()) {
81            ptln('<div class="info">' . $this->getLang('locked') . '</div>');
82        }
83
84        // POST to script() instead of wl($ID) so config manager still works if
85        // rewrite config is broken. Add $ID as hidden field to remember
86        // current ID in most cases.
87        ptln('<form action="' . script() . '" method="post">');
88        ptln('<div class="no"><input type="hidden" name="id" value="' . $ID . '" /></div>');
89        formSecurityToken();
90        $this->_print_h1('dokuwiki_settings', $this->getLang('_header_dokuwiki'));
91
92        $in_fieldset = false;
93        $first_plugin_fieldset = true;
94        $first_template_fieldset = true;
95        foreach($this->configuration->getSettings() as $setting) {
96            if(is_a($setting, SettingHidden::class)) {
97                continue;
98            } else if(is_a($setting, settingFieldset::class)) {
99                // config setting group
100                if($in_fieldset) {
101                    ptln('  </table>');
102                    ptln('  </div>');
103                    ptln('  </fieldset>');
104                } else {
105                    $in_fieldset = true;
106                }
107                // fixme this should probably be a function in setting:
108                if($first_plugin_fieldset && substr($setting->getKey(), 0, 10) == 'plugin' . Configuration::KEYMARKER) {
109                    $this->_print_h1('plugin_settings', $this->getLang('_header_plugin'));
110                    $first_plugin_fieldset = false;
111                } else if($first_template_fieldset && substr($setting->getKey(), 0, 7) == 'tpl' . Configuration::KEYMARKER) {
112                    $this->_print_h1('template_settings', $this->getLang('_header_template'));
113                    $first_template_fieldset = false;
114                }
115                ptln('  <fieldset id="' . $setting->getKey() . '">');
116                ptln('  <legend>' . $setting->prompt($this) . '</legend>');
117                ptln('  <div class="table">');
118                ptln('  <table class="inline">');
119            } else {
120                // config settings
121                list($label, $input) = $setting->html($this, $this->_error);
122
123                $class = $setting->is_default()
124                    ? ' class="default"'
125                    : ($setting->is_protected() ? ' class="protected"' : '');
126                $error = $setting->error()
127                    ? ' class="value error"'
128                    : ' class="value"';
129                $icon = $setting->caution()
130                    ? '<img src="' . self::IMGDIR . $setting->caution() . '.png" ' .
131                    'alt="' . $setting->caution() . '" title="' . $this->getLang($setting->caution()) . '" />'
132                    : '';
133
134                ptln('    <tr' . $class . '>');
135                ptln('      <td class="label">');
136                ptln('        <span class="outkey">' . $setting->_out_key(true, true) . '</span>');
137                ptln('        ' . $icon . $label);
138                ptln('      </td>');
139                ptln('      <td' . $error . '>' . $input . '</td>');
140                ptln('    </tr>');
141            }
142        }
143
144        ptln('  </table>');
145        ptln('  </div>');
146        if($in_fieldset) {
147            ptln('  </fieldset>');
148        }
149
150        // show undefined settings list
151        $undefined_settings = $this->configuration->getUndefined();
152        if($allow_debug && !empty($undefined_settings)) {
153            /**
154             * Callback for sorting settings
155             *
156             * @param Setting $a
157             * @param Setting $b
158             * @return int if $a is lower/equal/higher than $b
159             */
160            function _setting_natural_comparison($a, $b) {
161                return strnatcmp($a->getKey(), $b->getKey());
162            }
163
164            usort($undefined_settings, '_setting_natural_comparison');
165            $this->_print_h1('undefined_settings', $this->getLang('_header_undefined'));
166            ptln('<fieldset>');
167            ptln('<div class="table">');
168            ptln('<table class="inline">');
169            $undefined_setting_match = array();
170            foreach($undefined_settings as $setting) {
171                if(
172                preg_match(
173                    '/^(?:plugin|tpl)' . Configuration::KEYMARKER . '.*?' . Configuration::KEYMARKER . '(.*)$/',
174                    $setting->getKey(),
175                    $undefined_setting_match
176                )
177                ) {
178                    $undefined_setting_key = $undefined_setting_match[1];
179                } else {
180                    $undefined_setting_key = $setting->getKey();
181                }
182                ptln('  <tr>');
183                ptln(
184                    '    <td class="label"><span title="$meta[\'' . $undefined_setting_key . '\']">$' .
185                    'conf' . '[\'' . $setting->_out_key() . '\']</span></td>'
186                );
187                ptln('    <td>' . $this->getLang('_msg_' . get_class($setting)) . '</td>');
188                ptln('  </tr>');
189            }
190            ptln('</table>');
191            ptln('</div>');
192            ptln('</fieldset>');
193        }
194
195        // finish up form
196        ptln('<p>');
197        ptln('  <input type="hidden" name="do"     value="admin" />');
198        ptln('  <input type="hidden" name="page"   value="config" />');
199
200        if(!$this->configuration->isLocked()) {
201            ptln('  <input type="hidden" name="save"   value="1" />');
202            ptln('  <button type="submit" name="submit" accesskey="s">' . $lang['btn_save'] . '</button>');
203            ptln('  <button type="reset">' . $lang['btn_reset'] . '</button>');
204        }
205
206        ptln('</p>');
207
208        ptln('</form>');
209        ptln('</div>');
210    }
211
212    /**
213     * @param bool $prompts
214     */
215    public function setupLocale($prompts = false) {
216        parent::setupLocale();
217        if(!$prompts || $this->_localised_prompts) return;
218        $this->configuration->getLangs();
219        $this->_localised_prompts = true;
220    }
221
222    /**
223     * Generates a two-level table of contents for the config plugin.
224     *
225     * @author Ben Coburn <btcoburn@silicodon.net>
226     *
227     * @return array
228     */
229    public function getTOC() {
230        $this->setupLocale(true);
231
232        $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here.
233
234        // gather toc data
235        $toc = array('conf' => array(), 'plugin' => array(), 'template' => null);
236        foreach($this->configuration->getSettings() as $setting) {
237            if(is_a($setting, 'setting_fieldset')) {
238                // FIXME as above this should go into Setting class
239                if(substr($setting->getKey(), 0, 10) == 'plugin' . Configuration::KEYMARKER) {
240                    $toc['plugin'][] = $setting;
241                } else if(substr($setting->getKey(), 0, 7) == 'tpl' . Configuration::KEYMARKER) {
242                    $toc['template'] = $setting;
243                } else {
244                    $toc['conf'][] = $setting;
245                }
246            }
247        }
248
249        // build toc
250        $t = array();
251
252        $check = false;
253        $title = $this->getLang('_configuration_manager');
254        $t[] = html_mktocitem(sectionID($title, $check), $title, 1);
255        $t[] = html_mktocitem('dokuwiki_settings', $this->getLang('_header_dokuwiki'), 1);
256        /** @var setting $setting */
257        foreach($toc['conf'] as $setting) {
258            $name = $setting->prompt($this);
259            $t[] = html_mktocitem($setting->getKey(), $name, 2);
260        }
261        if(!empty($toc['plugin'])) {
262            $t[] = html_mktocitem('plugin_settings', $this->getLang('_header_plugin'), 1);
263        }
264        foreach($toc['plugin'] as $setting) {
265            $name = $setting->prompt($this);
266            $t[] = html_mktocitem($setting->getKey(), $name, 2);
267        }
268        if(isset($toc['template'])) {
269            $t[] = html_mktocitem('template_settings', $this->getLang('_header_template'), 1);
270            $setting = $toc['template'];
271            $name = $setting->prompt($this);
272            $t[] = html_mktocitem($setting->getKey(), $name, 2);
273        }
274        if(count($this->configuration->getUndefined()) && $allow_debug) {
275            $t[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1);
276        }
277
278        return $t;
279    }
280
281    /**
282     * @param string $id
283     * @param string $text
284     */
285    protected function _print_h1($id, $text) {
286        ptln('<h1 id="' . $id . '">' . $text . '</h1>');
287    }
288
289    /**
290     * Adds a translation to this plugin's language array
291     *
292     * @param string $key
293     * @param string $value
294     */
295    public function addLang($key, $value) {
296        if(!$this->localised) $this->setupLocale();
297        $this->lang[$key] = $value;
298    }
299}
300