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\Setting; 12use dokuwiki\plugin\config\core\Setting\SettingFieldset; 13use dokuwiki\plugin\config\core\Setting\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 IMGDIR = DOKU_BASE . 'lib/plugins/config/images/'; 22 23 /** @var Configuration */ 24 protected $configuration; 25 26 /** @var bool were there any errors in the submitted data? */ 27 protected $hasErrors = false; 28 29 /** @var bool have the settings translations been loaded? */ 30 protected $promptsLocalized = false; 31 32 /** 33 * admin_plugin_config constructor. 34 */ 35 public function __construct() { 36 $this->configuration = new Configuration(); 37 } 38 39 /** 40 * handle user request 41 */ 42 public function handle() { 43 global $ID, $INPUT; 44 45 if(!$INPUT->bool('save') || !checkSecurityToken()) { 46 return; 47 } 48 49 // don't go any further if the configuration is locked 50 if($this->configuration->isLocked()) return; 51 52 // update settings and redirect of successful 53 $ok = $this->configuration->updateSettings($INPUT->arr('config')); 54 if($ok) { // no errors 55 try { 56 if($this->configuration->hasChanged()) { 57 $this->configuration->save(); 58 } else { 59 $this->configuration->touch(); 60 } 61 msg($this->getLang('updated'), 1); 62 } catch(Exception $e) { 63 msg($this->getLang('error'), -1); 64 } 65 send_redirect(wl($ID, array('do' => 'admin', 'page' => 'config'), true, '&')); 66 } else { 67 $this->hasErrors = true; 68 } 69 } 70 71 /** 72 * output appropriate html 73 */ 74 public function html() { 75 $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 76 global $lang; 77 global $ID; 78 79 $this->setupLocale(true); 80 81 echo $this->locale_xhtml('intro'); 82 83 echo '<div id="config__manager">'; 84 85 if($this->configuration->isLocked()) { 86 echo '<div class="info">' . $this->getLang('locked') . '</div>'; 87 } 88 89 // POST to script() instead of wl($ID) so config manager still works if 90 // rewrite config is broken. Add $ID as hidden field to remember 91 // current ID in most cases. 92 echo '<form action="' . script() . '" method="post">'; 93 echo '<div class="no"><input type="hidden" name="id" value="' . $ID . '" /></div>'; 94 formSecurityToken(); 95 $this->printH1('dokuwiki_settings', $this->getLang('_header_dokuwiki')); 96 97 $in_fieldset = false; 98 $first_plugin_fieldset = true; 99 $first_template_fieldset = true; 100 foreach($this->configuration->getSettings() as $setting) { 101 if(is_a($setting, SettingHidden::class)) { 102 continue; 103 } else if(is_a($setting, settingFieldset::class)) { 104 // config setting group 105 if($in_fieldset) { 106 echo '</table>'; 107 echo '</div>'; 108 echo '</fieldset>'; 109 } else { 110 $in_fieldset = true; 111 } 112 if($first_plugin_fieldset && $setting->getType() == 'plugin') { 113 $this->printH1('plugin_settings', $this->getLang('_header_plugin')); 114 $first_plugin_fieldset = false; 115 } else if($first_template_fieldset && $setting->getType() == 'template') { 116 $this->printH1('template_settings', $this->getLang('_header_template')); 117 $first_template_fieldset = false; 118 } 119 echo '<fieldset id="' . $setting->getKey() . '">'; 120 echo '<legend>' . $setting->prompt($this) . '</legend>'; 121 echo '<div class="table">'; 122 echo '<table class="inline">'; 123 } else { 124 // config settings 125 list($label, $input) = $setting->html($this, $this->hasErrors); 126 127 $class = $setting->isDefault() 128 ? ' class="default"' 129 : ($setting->isProtected() ? ' class="protected"' : ''); 130 $error = $setting->hasError() 131 ? ' class="value error"' 132 : ' class="value"'; 133 $icon = $setting->caution() 134 ? '<img src="' . self::IMGDIR . $setting->caution() . '.png" ' . 135 'alt="' . $setting->caution() . '" title="' . $this->getLang($setting->caution()) . '" />' 136 : ''; 137 138 echo '<tr' . $class . '>'; 139 echo '<td class="label">'; 140 echo '<span class="outkey">' . $setting->getPrettyKey() . '</span>'; 141 echo $icon . $label; 142 echo '</td>'; 143 echo '<td' . $error . '>' . $input . '</td>'; 144 echo '</tr>'; 145 } 146 } 147 148 echo '</table>'; 149 echo '</div>'; 150 if($in_fieldset) { 151 echo '</fieldset>'; 152 } 153 154 // show undefined settings list 155 $undefined_settings = $this->configuration->getUndefined(); 156 if($allow_debug && !empty($undefined_settings)) { 157 /** 158 * Callback for sorting settings 159 * 160 * @param Setting $a 161 * @param Setting $b 162 * @return int if $a is lower/equal/higher than $b 163 */ 164 function settingNaturalComparison($a, $b) { 165 return strnatcmp($a->getKey(), $b->getKey()); 166 } 167 168 usort($undefined_settings, 'settingNaturalComparison'); 169 $this->printH1('undefined_settings', $this->getLang('_header_undefined')); 170 echo '<fieldset>'; 171 echo '<div class="table">'; 172 echo '<table class="inline">'; 173 foreach($undefined_settings as $setting) { 174 list($label, $input) = $setting->html($this); 175 echo '<tr>'; 176 echo '<td class="label">' . $label . '</td>'; 177 echo '<td>' . $input . '</td>'; 178 echo '</tr>'; 179 } 180 echo '</table>'; 181 echo '</div>'; 182 echo '</fieldset>'; 183 } 184 185 // finish up form 186 echo '<p>'; 187 echo '<input type="hidden" name="do" value="admin" />'; 188 echo '<input type="hidden" name="page" value="config" />'; 189 190 if(!$this->configuration->isLocked()) { 191 echo '<input type="hidden" name="save" value="1" />'; 192 echo '<button type="submit" name="submit" accesskey="s">' . $lang['btn_save'] . '</button>'; 193 echo '<button type="reset">' . $lang['btn_reset'] . '</button>'; 194 } 195 196 echo '</p>'; 197 198 echo '</form>'; 199 echo '</div>'; 200 } 201 202 /** 203 * @param bool $prompts 204 */ 205 public function setupLocale($prompts = false) { 206 parent::setupLocale(); 207 if(!$prompts || $this->promptsLocalized) return; 208 $this->lang = array_merge($this->lang, $this->configuration->getLangs()); 209 $this->promptsLocalized = true; 210 } 211 212 /** 213 * Generates a two-level table of contents for the config plugin. 214 * 215 * @author Ben Coburn <btcoburn@silicodon.net> 216 * 217 * @return array 218 */ 219 public function getTOC() { 220 $this->setupLocale(true); 221 222 $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 223 $toc = array(); 224 $check = false; 225 226 // gather settings data into three sub arrays 227 $labels = ['dokuwiki' => [], 'plugin' => [], 'template' => []]; 228 foreach($this->configuration->getSettings() as $setting) { 229 if(is_a($setting, SettingFieldset::class)) { 230 $labels[$setting->getType()][] = $setting; 231 } 232 } 233 234 // top header 235 $title = $this->getLang('_configuration_manager'); 236 $toc[] = html_mktocitem(sectionID($title, $check), $title, 1); 237 238 // main entries 239 foreach(['dokuwiki', 'plugin', 'template'] as $section) { 240 if(empty($labels[$section])) continue; // no entries, skip 241 242 // create main header 243 $toc[] = html_mktocitem( 244 $section . '_settings', 245 $this->getLang('_header_' . $section), 246 1 247 ); 248 249 // create sub headers 250 foreach($labels[$section] as $setting) { 251 /** @var SettingFieldset $setting */ 252 $name = $setting->prompt($this); 253 $toc[] = html_mktocitem($setting->getKey(), $name, 2); 254 } 255 } 256 257 // undefined settings if allowed 258 if(count($this->configuration->getUndefined()) && $allow_debug) { 259 $toc[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1); 260 } 261 262 return $toc; 263 } 264 265 /** 266 * @param string $id 267 * @param string $text 268 */ 269 protected function printH1($id, $text) { 270 echo '<h1 id="' . $id . '">' . $text . '</h1>'; 271 } 272 273 /** 274 * Adds a translation to this plugin's language array 275 * 276 * Used by some settings to set up dynamic translations 277 * 278 * @param string $key 279 * @param string $value 280 */ 281 public function addLang($key, $value) { 282 if(!$this->localised) $this->setupLocale(); 283 $this->lang[$key] = $value; 284 } 285} 286