xref: /dokuwiki/inc/Remote/OpenApiDoc/Type.php (revision 093fe67e98c0cdb4b73fd46938e49b64971483c2)
1<?php
2
3namespace dokuwiki\Remote\OpenApiDoc;
4
5class Type implements \Stringable
6{
7    protected $typehint;
8    protected $context;
9
10    /**
11     * @param string $typehint The typehint as read from the docblock
12     * @param string $context A fully qualified class name in which context the typehint is used
13     */
14    public function __construct($typehint, $context = '')
15    {
16        $this->typehint = $typehint;
17        $this->context = $context;
18    }
19
20    /**
21     * Return the typehint as read from the docblock
22     *
23     * @return string
24     */
25    public function __toString(): string
26    {
27        return (string) $this->typehint;
28    }
29
30    /**
31     * Return the base type
32     *
33     * This is the type this variable is. Eg. a string[] is an array.
34     *
35     * @return string
36     */
37    public function getBaseType()
38    {
39        $typehint = $this->typehint;
40
41        if (str_ends_with($typehint, '[]')) {
42            return 'array';
43        }
44
45        if (in_array($typehint, ['boolean', 'false', 'true'])) {
46            return 'bool';
47        }
48
49        if (in_array($typehint, ['integer', 'date'])) {
50            return 'int';
51        }
52
53        if ($typehint === 'file') {
54            return 'string';
55        }
56
57        // fully qualified class name
58        if ($typehint[0] === '\\') {
59            return ltrim($typehint, '\\');
60        }
61
62        // relative class name, try to resolve
63        if ($this->context && ctype_upper($typehint[0])) {
64            return ClassResolver::getInstance()->resolve($typehint, $this->context);
65        }
66
67        return $typehint;
68    }
69
70    /**
71     * Return a primitive type understood by the XMLRPC server
72     *
73     * @param string $typehint
74     * @return string
75     */
76    public function getJSONRPCType()
77    {
78        return $this->getBaseType();
79    }
80
81    /**
82     * Get the base type as one of the supported OpenAPI types
83     *
84     * Formats (eg. int32 or double) are not supported
85     *
86     * @link https://swagger.io/docs/specification/data-models/data-types/
87     * @return string
88     */
89    public function getOpenApiType()
90    {
91        return match ($this->getBaseType()) {
92            'int' => 'integer',
93            'bool' => 'boolean',
94            'array' => 'array',
95            'string', 'mixed' => 'string',
96            'double', 'float' => 'number',
97            default => 'object',
98        };
99    }
100
101
102    /**
103     * If this is an array, return the type of the array elements
104     *
105     * @return Type|null null if this is not a typed array
106     */
107    public function getSubType()
108    {
109        $type = $this->typehint;
110        if (!str_ends_with($type, '[]')) {
111            return null;
112        }
113        $type = substr($type, 0, -2);
114        return new Type($type, $this->context);
115    }
116
117    /**
118     * Return a type understood by the XMLRPC server
119     *
120     * @return string
121     */
122    public function getXMLRPCType()
123    {
124        $type = $this->typehint;
125
126        // keep custom types
127        if (in_array($type, ['date', 'file', 'struct'])) {
128            return $type;
129        }
130
131        $type = $this->getBaseType($this->typehint);
132
133        // primitive types
134        if (in_array($type, ['int', 'string', 'double', 'bool', 'array'])) {
135            return $type;
136        }
137
138        // everything else is an object
139        return 'object'; //should this return 'struct'?
140    }
141}
142