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