1<?php 2 3namespace dokuwiki\Extension; 4 5use dokuwiki\Logger; 6 7/** 8 * Provides standard DokuWiki plugin behaviour 9 */ 10trait PluginTrait 11{ 12 protected $localised = false; // set to true by setupLocale() after loading language dependent strings 13 protected $lang = []; // array to hold language dependent strings, best accessed via ->getLang() 14 protected $configloaded = false; // set to true by loadConfig() after loading plugin configuration variables 15 protected $conf = []; // array to hold plugin settings, best accessed via ->getConf() 16 17 /** 18 * @see PluginInterface::getInfo() 19 */ 20 public function getInfo() 21 { 22 $class = get_class($this); 23 $parts = sexplode('_', $class, 3); 24 $ext = $parts[2]; 25 26 if (empty($ext)) { 27 throw new \RuntimeException('Class does not follow the plugin naming convention'); 28 } 29 30 // class like action_plugin_myplugin_ajax belongs to plugin 'myplugin' 31 $ext = strtok($ext, '_'); 32 33 $base = [ 34 'base' => $ext, 35 'author' => 'Unknown', 36 'email' => 'unknown@example.com', 37 'date' => '0000-00-00', 38 'name' => $ext . ' plugin', 39 'desc' => 'Unknown purpose - bad plugin.info.txt', 40 'url' => 'https://www.dokuwiki.org/plugins/' . $ext, 41 ]; 42 43 $file = DOKU_PLUGIN . '/' . $ext . '/plugin.info.txt'; 44 if (file_exists($file)) { 45 $raw = confToHash($file); 46 47 // check if all required fields are present 48 $msg = 'Extension %s does not provide a valid %s in %s'; 49 foreach (array_keys($base) as $line) { 50 if (empty($raw[$line])) Logger::error(sprintf($msg, $ext, $line, $file)); 51 } 52 53 return array_merge($base, $raw); 54 } 55 56 Logger::error(sprintf('Extension %s does not provide a plugin.info.txt in %s', $ext, $file)); 57 return $base; 58 } 59 60 /** 61 * @see PluginInterface::isSingleton() 62 */ 63 public function isSingleton() 64 { 65 return true; 66 } 67 68 /** 69 * @see PluginInterface::loadHelper() 70 */ 71 public function loadHelper($name, $msg = true) 72 { 73 $obj = plugin_load('helper', $name); 74 if (is_null($obj) && $msg) msg("Helper plugin $name is not available or invalid.", -1); 75 return $obj; 76 } 77 78 // region introspection methods 79 80 /** 81 * @see PluginInterface::getPluginType() 82 */ 83 public function getPluginType() 84 { 85 [$t] = explode('_', get_class($this), 2); 86 return $t; 87 } 88 89 /** 90 * @see PluginInterface::getPluginName() 91 */ 92 public function getPluginName() 93 { 94 [/* t */, /* p */, $n] = sexplode('_', get_class($this), 4, ''); 95 return $n; 96 } 97 98 /** 99 * @see PluginInterface::getPluginComponent() 100 */ 101 public function getPluginComponent() 102 { 103 [/* t */, /* p */, /* n */, $c] = sexplode('_', get_class($this), 4, ''); 104 return $c; 105 } 106 107 // endregion 108 // region localization methods 109 110 /** 111 * @see PluginInterface::getLang() 112 */ 113 public function getLang($id) 114 { 115 if (!$this->localised) $this->setupLocale(); 116 117 return ($this->lang[$id] ?? ''); 118 } 119 120 /** 121 * @see PluginInterface::locale_xhtml() 122 */ 123 public function locale_xhtml($id) 124 { 125 return p_cached_output($this->localFN($id)); 126 } 127 128 /** 129 * @see PluginInterface::localFN() 130 */ 131 public function localFN($id, $ext = 'txt') 132 { 133 global $conf; 134 $plugin = $this->getPluginName(); 135 $file = DOKU_CONF . 'plugin_lang/' . $plugin . '/' . $conf['lang'] . '/' . $id . '.' . $ext; 136 if (!file_exists($file)) { 137 $file = DOKU_PLUGIN . $plugin . '/lang/' . $conf['lang'] . '/' . $id . '.' . $ext; 138 if (!file_exists($file)) { 139 //fall back to english 140 $file = DOKU_PLUGIN . $plugin . '/lang/en/' . $id . '.' . $ext; 141 } 142 } 143 return $file; 144 } 145 146 /** 147 * @see PluginInterface::setupLocale() 148 */ 149 public function setupLocale() 150 { 151 if ($this->localised) return; 152 153 global $conf, $config_cascade; // definitely don't invoke "global $lang" 154 $path = DOKU_PLUGIN . $this->getPluginName() . '/lang/'; 155 156 $lang = []; 157 158 // don't include once, in case several plugin components require the same language file 159 @include($path . 'en/lang.php'); 160 foreach ($config_cascade['lang']['plugin'] as $config_file) { 161 if (file_exists($config_file . $this->getPluginName() . '/en/lang.php')) { 162 include($config_file . $this->getPluginName() . '/en/lang.php'); 163 } 164 } 165 166 if ($conf['lang'] != 'en') { 167 @include($path . $conf['lang'] . '/lang.php'); 168 foreach ($config_cascade['lang']['plugin'] as $config_file) { 169 if (file_exists($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php')) { 170 include($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php'); 171 } 172 } 173 } 174 175 $this->lang = $lang; 176 $this->localised = true; 177 } 178 179 // endregion 180 // region configuration methods 181 182 /** 183 * @see PluginInterface::getConf() 184 */ 185 public function getConf($setting, $notset = false) 186 { 187 188 if (!$this->configloaded) { 189 $this->loadConfig(); 190 } 191 192 if (isset($this->conf[$setting])) { 193 return $this->conf[$setting]; 194 } else { 195 return $notset; 196 } 197 } 198 199 /** 200 * @see PluginInterface::loadConfig() 201 */ 202 public function loadConfig() 203 { 204 global $conf; 205 206 $defaults = $this->readDefaultSettings(); 207 $plugin = $this->getPluginName(); 208 209 foreach ($defaults as $key => $value) { 210 if (isset($conf['plugin'][$plugin][$key])) continue; 211 $conf['plugin'][$plugin][$key] = $value; 212 } 213 214 $this->configloaded = true; 215 $this->conf =& $conf['plugin'][$plugin]; 216 } 217 218 /** 219 * read the plugin's default configuration settings from conf/default.php 220 * this function is automatically called through getConf() 221 * 222 * @return array setting => value 223 */ 224 protected function readDefaultSettings() 225 { 226 227 $path = DOKU_PLUGIN . $this->getPluginName() . '/conf/'; 228 $conf = []; 229 230 if (file_exists($path . 'default.php')) { 231 include($path . 'default.php'); 232 } 233 234 return $conf; 235 } 236 237 // endregion 238 // region output methods 239 240 /** 241 * @see PluginInterface::email() 242 */ 243 public function email($email, $name = '', $class = '', $more = '') 244 { 245 if (!$email) return $name; 246 $email = obfuscate($email); 247 if (!$name) $name = $email; 248 $class = "class='" . ($class ?: 'mail') . "'"; 249 return "<a href='mailto:$email' $class title='$email' $more>$name</a>"; 250 } 251 252 /** 253 * @see PluginInterface::external_link() 254 */ 255 public function external_link($link, $title = '', $class = '', $target = '', $more = '') 256 { 257 global $conf; 258 259 $link = htmlentities($link); 260 if (!$title) $title = $link; 261 if (!$target) $target = $conf['target']['extern']; 262 if ($conf['relnofollow']) $more .= ' rel="nofollow"'; 263 264 if ($class) $class = " class='$class'"; 265 if ($target) $target = " target='$target'"; 266 if ($more) $more = " " . trim($more); 267 268 return "<a href='$link'$class$target$more>$title</a>"; 269 } 270 271 /** 272 * @see PluginInterface::render_text() 273 */ 274 public function render_text($text, $format = 'xhtml') 275 { 276 return p_render($format, p_get_instructions($text), $info); 277 } 278 279 // endregion 280} 281