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 $undefined_setting_match = array(); 174 foreach($undefined_settings as $setting) { 175 if( 176 preg_match( 177 '/^(?:plugin|tpl)' . Configuration::KEYMARKER . '.*?' . Configuration::KEYMARKER . '(.*)$/', 178 $setting->getKey(), 179 $undefined_setting_match 180 ) 181 ) { 182 $undefined_setting_key = $undefined_setting_match[1]; 183 } else { 184 $undefined_setting_key = $setting->getKey(); 185 } 186 echo '<tr>'; 187 echo 188 '<td class="label"><span title="$meta[\'' . $undefined_setting_key . '\']">$' . 189 'conf' . '[\'' . $setting->getArrayKey() . '\']</span></td>'; 190 echo '<td>' . $this->getLang('_msg_' . get_class($setting)) . '</td>'; 191 echo '</tr>'; 192 } 193 echo '</table>'; 194 echo '</div>'; 195 echo '</fieldset>'; 196 } 197 198 // finish up form 199 echo '<p>'; 200 echo '<input type="hidden" name="do" value="admin" />'; 201 echo '<input type="hidden" name="page" value="config" />'; 202 203 if(!$this->configuration->isLocked()) { 204 echo '<input type="hidden" name="save" value="1" />'; 205 echo '<button type="submit" name="submit" accesskey="s">' . $lang['btn_save'] . '</button>'; 206 echo '<button type="reset">' . $lang['btn_reset'] . '</button>'; 207 } 208 209 echo '</p>'; 210 211 echo '</form>'; 212 echo '</div>'; 213 } 214 215 /** 216 * @param bool $prompts 217 */ 218 public function setupLocale($prompts = false) { 219 parent::setupLocale(); 220 if(!$prompts || $this->promptsLocalized) return; 221 $this->lang = array_merge($this->lang, $this->configuration->getLangs()); 222 $this->promptsLocalized = true; 223 } 224 225 /** 226 * Generates a two-level table of contents for the config plugin. 227 * 228 * @author Ben Coburn <btcoburn@silicodon.net> 229 * 230 * @return array 231 */ 232 public function getTOC() { 233 $this->setupLocale(true); 234 235 $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 236 $toc = array(); 237 $check = false; 238 239 // gather settings data into three sub arrays 240 $labels = ['dokuwiki' => [], 'plugin' => [], 'template' => []]; 241 foreach($this->configuration->getSettings() as $setting) { 242 if(is_a($setting, SettingFieldset::class)) { 243 $labels[$setting->getType()][] = $setting; 244 } 245 } 246 247 // top header 248 $title = $this->getLang('_configuration_manager'); 249 $toc[] = html_mktocitem(sectionID($title, $check), $title, 1); 250 251 // main entries 252 foreach(['dokuwiki', 'plugin', 'template'] as $section) { 253 if(empty($labels[$section])) continue; // no entries, skip 254 255 // create main header 256 $toc[] = html_mktocitem( 257 $section . '_settings', 258 $this->getLang('_header_'.$section), 259 1 260 ); 261 262 // create sub headers 263 foreach($labels[$section] as $setting) { 264 /** @var SettingFieldset $setting */ 265 $name = $setting->prompt($this); 266 $toc[] = html_mktocitem($setting->getKey(), $name, 2); 267 } 268 } 269 270 // undefined settings if allowed 271 if(count($this->configuration->getUndefined()) && $allow_debug) { 272 $toc[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1); 273 } 274 275 return $toc; 276 } 277 278 /** 279 * @param string $id 280 * @param string $text 281 */ 282 protected function printH1($id, $text) { 283 echo '<h1 id="' . $id . '">' . $text . '</h1>'; 284 } 285 286 /** 287 * Adds a translation to this plugin's language array 288 * 289 * Used by some settings to set up dynamic translations 290 * 291 * @param string $key 292 * @param string $value 293 */ 294 public function addLang($key, $value) { 295 if(!$this->localised) $this->setupLocale(); 296 $this->lang[$key] = $value; 297 } 298} 299