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