You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

281 lines
7.7 KiB

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