1<?php 2 3namespace dokuwiki\plugin\config\core\Setting; 4 5use dokuwiki\plugin\config\core\Configuration; 6 7/** 8 * Class Setting 9 */ 10class Setting 11{ 12 /** @var string unique identifier of this setting */ 13 protected $key = ''; 14 15 /** @var mixed the default value of this setting */ 16 protected $default; 17 /** @var mixed the local value of this setting */ 18 protected $local; 19 /** @var mixed the protected value of this setting */ 20 protected $protected; 21 22 /** @var array valid alerts, images matching the alerts are in the plugin's images directory */ 23 static protected $validCautions = ['warning', 'danger', 'security']; 24 25 protected $pattern = ''; 26 protected $error = false; // only used by those classes which error check 27 protected $input; // only used by those classes which error check 28 protected $caution; // used by any setting to provide an alert along with the setting 29 30 /** 31 * Constructor. 32 * 33 * The given parameters will be set up as class properties 34 * 35 * @see initialize() to set the actual value of the setting 36 * 37 * @param string $key 38 * @param array|null $params array with metadata of setting 39 */ 40 public function __construct($key, $params = null) { 41 $this->key = $key; 42 43 if(is_array($params)) { 44 foreach($params as $property => $value) { 45 $property = trim($property, '_'); // we don't use underscores anymore 46 $this->$property = $value; 47 } 48 } 49 } 50 51 /** 52 * Set the current values for the setting $key 53 * 54 * This is used to initialize the setting with the data read form the config files. 55 * 56 * @see update() to set a new value 57 * @param mixed $default default setting value 58 * @param mixed $local local setting value 59 * @param mixed $protected protected setting value 60 */ 61 public function initialize($default = null, $local = null, $protected = null) { 62 $this->default = $this->cleanValue($default); 63 $this->local = $this->cleanValue($local); 64 $this->protected = $this->cleanValue($protected); 65 } 66 67 /** 68 * update changed setting with validated user provided value $input 69 * - if changed value fails validation check, save it to $this->input (to allow echoing later) 70 * - if changed value passes validation check, set $this->local to the new value 71 * 72 * @param mixed $input the new value 73 * @return boolean true if changed, false otherwise 74 */ 75 public function update($input) { 76 if(is_null($input)) return false; 77 if($this->isProtected()) return false; 78 $input = $this->cleanValue($input); 79 80 $value = is_null($this->local) ? $this->default : $this->local; 81 if($value == $input) return false; 82 83 // validate new value 84 if($this->pattern && !preg_match($this->pattern, $input)) { 85 $this->error = true; 86 $this->input = $input; 87 return false; 88 } 89 90 // update local copy of this setting with new value 91 $this->local = $input; 92 93 // setting ready for update 94 return true; 95 } 96 97 /** 98 * Clean a value read from a config before using it internally 99 * 100 * Default implementation returns $value as is. Subclasses can override. 101 * Note: null should always be returned as null! 102 * 103 * This is applied in initialize() and update() 104 * 105 * @param mixed $value 106 * @return mixed 107 */ 108 protected function cleanValue($value) { 109 return $value; 110 } 111 112 /** 113 * Should this type of config have a default? 114 * 115 * @return bool 116 */ 117 public function shouldHaveDefault() { 118 return true; 119 } 120 121 /** 122 * Get this setting's unique key 123 * 124 * @return string 125 */ 126 public function getKey() { 127 return $this->key; 128 } 129 130 /** 131 * Get the key of this setting marked up human readable 132 * 133 * @param bool $url link to dokuwiki.org manual? 134 * @return string 135 */ 136 public function getPrettyKey($url = true) { 137 $out = str_replace(Configuration::KEYMARKER, "»", $this->key); 138 if($url && !strstr($out, '»')) {//provide no urls for plugins, etc. 139 if($out == 'start') { 140 // exception, because this config name is clashing with our actual start page 141 return '<a href="https://www.dokuwiki.org/config:startpage">' . $out . '</a>'; 142 } else { 143 return '<a href="https://www.dokuwiki.org/config:' . $out . '">' . $out . '</a>'; 144 } 145 } 146 return $out; 147 } 148 149 /** 150 * Returns setting key as an array key separator 151 * 152 * This is used to create form output 153 * 154 * @return string key 155 */ 156 public function getArrayKey() { 157 return str_replace(Configuration::KEYMARKER, "']['", $this->key); 158 } 159 160 /** 161 * What type of configuration is this 162 * 163 * Returns one of 164 * 165 * 'plugin' for plugin configuration 166 * 'template' for template configuration 167 * 'dokuwiki' for core configuration 168 * 169 * @return string 170 */ 171 public function getType() { 172 if (substr($this->getKey(), 0, 10) == 'plugin' . Configuration::KEYMARKER) { 173 return 'plugin'; 174 } elseif (substr($this->getKey(), 0, 7) == 'tpl' . Configuration::KEYMARKER) { 175 return 'template'; 176 } else { 177 return 'dokuwiki'; 178 } 179 } 180 181 /** 182 * Build html for label and input of setting 183 * 184 * @param \admin_plugin_config $plugin object of config plugin 185 * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting 186 * @return string[] with content array(string $label_html, string $input_html) 187 */ 188 public function html(\admin_plugin_config $plugin, $echo = false) { 189 $disable = ''; 190 191 if ($this->isProtected()) { 192 $value = $this->protected; 193 $disable = 'disabled="disabled"'; 194 } elseif ($echo && $this->error) { 195 $value = $this->input; 196 } else { 197 $value = is_null($this->local) ? $this->default : $this->local; 198 } 199 200 $key = htmlspecialchars($this->key); 201 $value = formText($value); 202 203 $label = '<label for="config___' . $key . '">' . $this->prompt($plugin) . '</label>'; 204 $input = '<textarea rows="3" cols="40" id="config___' . $key . 205 '" name="config[' . $key . ']" class="edit" ' . $disable . '>' . $value . '</textarea>'; 206 return [$label, $input]; 207 } 208 209 /** 210 * Should the current local value be saved? 211 * 212 * @see out() to run when this returns true 213 * @return bool 214 */ 215 public function shouldBeSaved() { 216 if($this->isProtected()) return false; 217 if($this->local === null) return false; 218 if($this->default == $this->local) return false; 219 return true; 220 } 221 222 /** 223 * Escaping 224 * 225 * @param string $string 226 * @return string 227 */ 228 protected function escape($string) { 229 $tr = ["\\" => '\\\\', "'" => '\\\'']; 230 return "'" . strtr(cleanText($string), $tr) . "'"; 231 } 232 233 /** 234 * Generate string to save local setting value to file according to $fmt 235 * 236 * @see shouldBeSaved() to check if this should be called 237 * @param string $var name of variable 238 * @param string $fmt save format 239 * @return string 240 */ 241 public function out($var, $fmt = 'php') { 242 if ($fmt != 'php') return ''; 243 244 if (is_array($this->local)) { 245 $value = 'array(' . implode(', ', array_map([$this, 'escape'], $this->local)) . ')'; 246 } else { 247 $value = $this->escape($this->local); 248 } 249 250 $out = '$' . $var . "['" . $this->getArrayKey() . "'] = $value;\n"; 251 252 return $out; 253 } 254 255 /** 256 * Returns the localized prompt 257 * 258 * @param \admin_plugin_config $plugin object of config plugin 259 * @return string text 260 */ 261 public function prompt(\admin_plugin_config $plugin) { 262 $prompt = $plugin->getLang($this->key); 263 if(!$prompt) $prompt = htmlspecialchars(str_replace(['____', '_'], ' ', $this->key)); 264 return $prompt; 265 } 266 267 /** 268 * Is setting protected 269 * 270 * @return bool 271 */ 272 public function isProtected() { 273 return !is_null($this->protected); 274 } 275 276 /** 277 * Is setting the default? 278 * 279 * @return bool 280 */ 281 public function isDefault() { 282 return !$this->isProtected() && is_null($this->local); 283 } 284 285 /** 286 * Has an error? 287 * 288 * @return bool 289 */ 290 public function hasError() { 291 return $this->error; 292 } 293 294 /** 295 * Returns caution 296 * 297 * @return false|string caution string, otherwise false for invalid caution 298 */ 299 public function caution() { 300 if(empty($this->caution)) return false; 301 if(!in_array($this->caution, Setting::$validCautions)) { 302 throw new \RuntimeException( 303 'Invalid caution string (' . $this->caution . ') in metadata for setting "' . $this->key . '"' 304 ); 305 } 306 return $this->caution; 307 } 308} 309