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