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