xref: /dokuwiki/inc/Extension/RemotePlugin.php (revision 6547cfc7454f26cc353587c1314f9fde93a0a056)
1<?php
2
3namespace dokuwiki\Extension;
4
5use dokuwiki\Remote\Api;
6use ReflectionException;
7use ReflectionMethod;
8
9/**
10 * Remote Plugin prototype
11 *
12 * Add functionality to the remote API in a plugin
13 */
14abstract class RemotePlugin extends Plugin
15{
16    private Api $api;
17
18    /**
19     * Constructor
20     */
21    public function __construct()
22    {
23        $this->api = new Api();
24    }
25
26    /**
27     * Get all available methods with remote access.
28     *
29     * By default it exports all public methods of a remote plugin. Methods beginning
30     * with an underscore are skipped.
31     *
32     * @return array Information about all provided methods. {@see dokuwiki\Remote\RemoteAPI}.
33     * @throws ReflectionException
34     */
35    public function _getMethods()
36    {
37        $result = [];
38
39        $reflection = new \ReflectionClass($this);
40        foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
41            // skip parent methods, only methods further down are exported
42            $declaredin = $method->getDeclaringClass()->name;
43            if ($declaredin === 'dokuwiki\Extension\Plugin' || $declaredin === 'dokuwiki\Extension\RemotePlugin') {
44                continue;
45            }
46            $method_name = $method->name;
47            if (strpos($method_name, '_') === 0) {
48                continue;
49            }
50
51            // strip asterisks
52            $doc = $method->getDocComment();
53            $doc = preg_replace(
54                ['/^[ \t]*\/\*+[ \t]*/m', '/[ \t]*\*+[ \t]*/m', '/\*+\/\s*$/m', '/\s*\/\s*$/m'],
55                ['', '', '', ''],
56                $doc
57            );
58
59            // prepare data
60            $data = [];
61            $data['name'] = $method_name;
62            $data['public'] = 0;
63            $data['doc'] = $doc;
64            $data['args'] = [];
65
66            // get parameter type from doc block type hint
67            foreach ($method->getParameters() as $parameter) {
68                $name = $parameter->name;
69                $type = 'string'; // we default to string
70                if (preg_match('/^@param[ \t]+([\w|\[\]]+)[ \t]\$' . $name . '/m', $doc, $m)) {
71                    $type = $this->cleanTypeHint($m[1]);
72                }
73                $data['args'][] = $type;
74            }
75
76            // get return type from doc block type hint
77            if (preg_match('/^@return[ \t]+([\w|\[\]]+)/m', $doc, $m)) {
78                $data['return'] = $this->cleanTypeHint($m[1]);
79            } else {
80                $data['return'] = 'string';
81            }
82
83            // add to result
84            $result[$method_name] = $data;
85        }
86
87        return $result;
88    }
89
90    /**
91     * Matches the given type hint against the valid options for the remote API
92     *
93     * @param string $hint
94     * @return string
95     */
96    protected function cleanTypeHint($hint)
97    {
98        $types = explode('|', $hint);
99        foreach ($types as $t) {
100            if (substr($t, -2) === '[]') {
101                return 'array';
102            }
103            if ($t === 'boolean') {
104                return 'bool';
105            }
106            if (in_array($t, ['array', 'string', 'int', 'double', 'bool', 'null', 'date', 'file'])) {
107                return $t;
108            }
109        }
110        return 'string';
111    }
112
113    /**
114     * @return Api
115     */
116    protected function getApi()
117    {
118        return $this->api;
119    }
120}
121