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