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 // fixme this should probably be a function in setting: 113 if($first_plugin_fieldset && $setting->getType() == 'plugin') { 114 $this->printH1('plugin_settings', $this->getLang('_header_plugin')); 115 $first_plugin_fieldset = false; 116 } else if($first_template_fieldset && $setting->getType() == 'template') { 117 $this->printH1('template_settings', $this->getLang('_header_template')); 118 $first_template_fieldset = false; 119 } 120 echo '<fieldset id="' . $setting->getKey() . '">'; 121 echo '<legend>' . $setting->prompt($this) . '</legend>'; 122 echo '<div class="table">'; 123 echo '<table class="inline">'; 124 } else { 125 // config settings 126 list($label, $input) = $setting->html($this, $this->hasErrors); 127 128 $class = $setting->isDefault() 129 ? ' class="default"' 130 : ($setting->isProtected() ? ' class="protected"' : ''); 131 $error = $setting->hasError() 132 ? ' class="value error"' 133 : ' class="value"'; 134 $icon = $setting->caution() 135 ? '<img src="' . self::IMGDIR . $setting->caution() . '.png" ' . 136 'alt="' . $setting->caution() . '" title="' . $this->getLang($setting->caution()) . '" />' 137 : ''; 138 139 echo '<tr' . $class . '>'; 140 echo '<td class="label">'; 141 echo '<span class="outkey">' . $setting->getPrettyKey() . '</span>'; 142 echo $icon . $label; 143 echo '</td>'; 144 echo '<td' . $error . '>' . $input . '</td>'; 145 echo '</tr>'; 146 } 147 } 148 149 echo '</table>'; 150 echo '</div>'; 151 if($in_fieldset) { 152 echo '</fieldset>'; 153 } 154 155 // show undefined settings list 156 $undefined_settings = $this->configuration->getUndefined(); 157 if($allow_debug && !empty($undefined_settings)) { 158 /** 159 * Callback for sorting settings 160 * 161 * @param Setting $a 162 * @param Setting $b 163 * @return int if $a is lower/equal/higher than $b 164 */ 165 function settingNaturalComparison($a, $b) { 166 return strnatcmp($a->getKey(), $b->getKey()); 167 } 168 169 usort($undefined_settings, 'settingNaturalComparison'); 170 $this->printH1('undefined_settings', $this->getLang('_header_undefined')); 171 echo '<fieldset>'; 172 echo '<div class="table">'; 173 echo '<table class="inline">'; 174 $undefined_setting_match = array(); 175 foreach($undefined_settings as $setting) { 176 if( 177 preg_match( 178 '/^(?:plugin|tpl)' . Configuration::KEYMARKER . '.*?' . Configuration::KEYMARKER . '(.*)$/', 179 $setting->getKey(), 180 $undefined_setting_match 181 ) 182 ) { 183 $undefined_setting_key = $undefined_setting_match[1]; 184 } else { 185 $undefined_setting_key = $setting->getKey(); 186 } 187 echo '<tr>'; 188 echo 189 '<td class="label"><span title="$meta[\'' . $undefined_setting_key . '\']">$' . 190 'conf' . '[\'' . $setting->getArrayKey() . '\']</span></td>' 191 ; 192 echo '<td>' . $this->getLang('_msg_' . get_class($setting)) . '</td>'; 193 echo '</tr>'; 194 } 195 echo '</table>'; 196 echo '</div>'; 197 echo '</fieldset>'; 198 } 199 200 // finish up form 201 echo '<p>'; 202 echo '<input type="hidden" name="do" value="admin" />'; 203 echo '<input type="hidden" name="page" value="config" />'; 204 205 if(!$this->configuration->isLocked()) { 206 echo '<input type="hidden" name="save" value="1" />'; 207 echo '<button type="submit" name="submit" accesskey="s">' . $lang['btn_save'] . '</button>'; 208 echo '<button type="reset">' . $lang['btn_reset'] . '</button>'; 209 } 210 211 echo '</p>'; 212 213 echo '</form>'; 214 echo '</div>'; 215 } 216 217 /** 218 * @param bool $prompts 219 */ 220 public function setupLocale($prompts = false) { 221 parent::setupLocale(); 222 if(!$prompts || $this->promptsLocalized) return; 223 $this->configuration->getLangs(); 224 $this->promptsLocalized = true; 225 } 226 227 /** 228 * Generates a two-level table of contents for the config plugin. 229 * 230 * @author Ben Coburn <btcoburn@silicodon.net> 231 * 232 * @return array 233 */ 234 public function getTOC() { 235 $this->setupLocale(true); 236 237 $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 238 239 // gather settings data into three sub arrays 240 $toc = array('conf' => array(), 'plugin' => array(), 'template' => null); 241 foreach($this->configuration->getSettings() as $setting) { 242 if(is_a($setting, 'setting_fieldset')) { 243 $toc[$setting->getType()][] = $setting; 244 } 245 } 246 247 // build toc 248 $t = array(); 249 250 $check = false; 251 $title = $this->getLang('_configuration_manager'); 252 $t[] = html_mktocitem(sectionID($title, $check), $title, 1); 253 $t[] = html_mktocitem('dokuwiki_settings', $this->getLang('_header_dokuwiki'), 1); 254 /** @var Setting $setting */ 255 foreach($toc['conf'] as $setting) { 256 $name = $setting->prompt($this); 257 $t[] = html_mktocitem($setting->getKey(), $name, 2); 258 } 259 if(!empty($toc['plugin'])) { 260 $t[] = html_mktocitem('plugin_settings', $this->getLang('_header_plugin'), 1); 261 } 262 foreach($toc['plugin'] as $setting) { 263 $name = $setting->prompt($this); 264 $t[] = html_mktocitem($setting->getKey(), $name, 2); 265 } 266 if(isset($toc['template'])) { 267 $t[] = html_mktocitem('template_settings', $this->getLang('_header_template'), 1); 268 $setting = $toc['template']; 269 $name = $setting->prompt($this); 270 $t[] = html_mktocitem($setting->getKey(), $name, 2); 271 } 272 if(count($this->configuration->getUndefined()) && $allow_debug) { 273 $t[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1); 274 } 275 276 return $t; 277 } 278 279 /** 280 * @param string $id 281 * @param string $text 282 */ 283 protected function printH1($id, $text) { 284 echo '<h1 id="' . $id . '">' . $text . '</h1>'; 285 } 286 287 /** 288 * Adds a translation to this plugin's language array 289 * 290 * Used by some settings to set up dynamic translations 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