22
33namespace rethink \typedphp ;
44
5- use rethink \typedphp \types \BooleanType ;
5+ use InvalidArgumentException ;
6+ use phpDocumentor \Reflection \DocBlockFactory ;
67use rethink \typedphp \types \BinaryType ;
8+ use rethink \typedphp \types \BooleanType ;
79use rethink \typedphp \types \DateType ;
810use rethink \typedphp \types \DictType ;
911use rethink \typedphp \types \InputType ;
1012use rethink \typedphp \types \IntegerType ;
11- use rethink \typedphp \types \ProductType ;
13+ use rethink \typedphp \types \MapType ;
1214use rethink \typedphp \types \NumberType ;
15+ use rethink \typedphp \types \ProductType ;
1316use rethink \typedphp \types \StringType ;
1417use rethink \typedphp \types \SumType ;
1518use rethink \typedphp \types \TimestampType ;
1619use rethink \typedphp \types \TimeType ;
1720use rethink \typedphp \types \Type ;
18- use phpDocumentor \Reflection \DocBlockFactory ;
1921
2022/**
2123 * Class TypeParser
2527class TypeParser
2628{
2729 const MODE_JSON_SCHEMA = 1 ;
28- const MODE_OPEN_API = 2 ;
29- const MODE_REF_SCHEMA = 4 ;
30+ const MODE_OPEN_API = 2 ;
31+ const MODE_REF_SCHEMA = 4 ;
3032
3133 protected $ mode = 0 ;
3234 protected $ builtinTypes = [];
@@ -51,17 +53,17 @@ public function __construct($mode)
5153
5254 public function registerBuiltinType (string $ typeClass )
5355 {
54- if (!is_subclass_of ($ typeClass , Type::class)) {
55- throw new \ InvalidArgumentException ("The type: $ typeClass is invalid, a type should be subclass of Type " );
56+ if (! is_subclass_of ($ typeClass , Type::class)) {
57+ throw new InvalidArgumentException ("The type: $ typeClass is invalid, a type should be subclass of Type " );
5658 }
5759
5860 $ this ->builtinTypes [$ typeClass ::name ()] = $ typeClass ;
5961 }
6062
6163 protected function getValidTypeClass ($ typeName )
6264 {
63- if (!isset ($ this ->builtinTypes [$ typeName ])) {
64- throw new \ InvalidArgumentException ("The type: $ typeName is invalid, not such type existed " );
65+ if (! isset ($ this ->builtinTypes [$ typeName ])) {
66+ throw new InvalidArgumentException ("The type: $ typeName is invalid, not such type existed " );
6567 }
6668
6769 return $ this ->builtinTypes [$ typeName ];
@@ -197,6 +199,9 @@ protected function parseObject($definition)
197199 'properties ' => $ properties ,
198200 'required ' => $ requiredFields ,
199201 ];
202+ if (empty ($ schema ['required ' ])) {
203+ unset($ schema ['required ' ]);
204+ }
200205
201206 if ($ this ->mode & self ::MODE_REF_SCHEMA ) {
202207 $ this ->schemas [$ definitionName ] = $ schema ;
@@ -242,7 +247,7 @@ protected function makeNullableSchema(array $schema, $nullable)
242247 'anyOf ' => [
243248 ['type ' => 'null ' ],
244249 $ schema ,
245- ]
250+ ],
246251 ];
247252 }
248253
@@ -255,25 +260,63 @@ protected function parseScalar($definition)
255260 }
256261
257262 $ typeClass = $ this ->getValidTypeClass ($ definition );
258-
259263 $ schema = $ typeClass ::toArray ();
260264
261265 if (($ this ->mode & self ::MODE_JSON_SCHEMA ) && $ nullable ) {
262266 $ schema ['type ' ] = [$ schema ['type ' ], 'null ' ];
263- } else if (($ this ->mode & self ::MODE_OPEN_API ) && $ nullable ) {
267+ } elseif (($ this ->mode & self ::MODE_OPEN_API ) && $ nullable ) {
264268 $ schema ['nullable ' ] = $ nullable ;
265269 }
266270
267271 return $ schema ;
268272 }
269273
274+ protected function parseMap (string $ definition ): array
275+ {
276+ $ nullable = false ;
277+ if ($ this ->isNullable ($ definition )) {
278+ $ nullable = true ;
279+ $ definition = trim ($ definition , '? ' );
280+ }
281+
282+ assert (is_subclass_of ($ definition , MapType::class));
283+
284+ $ schema = $ definition ::toArray ();
285+
286+ $ valueDefinition = $ definition ::valueType ();
287+ if ($ valueDefinition ) {
288+ $ schema ['additionalProperties ' ] = $ this ->parseString ($ valueDefinition );
289+ }
290+
291+ $ example = $ definition ::example ();
292+ if ($ example ) {
293+ $ schema ['example ' ] = $ example ;
294+ }
295+
296+ if (empty ($ schema ['required ' ])) {
297+ unset($ schema ['required ' ]);
298+ }
299+
300+ $ definitionName = $ definition ::name ();
301+ if ($ this ->mode & self ::MODE_REF_SCHEMA ) {
302+ $ this ->schemas [$ definitionName ] = $ schema ;
303+ return $ this ->makeNullableSchema ([
304+ '$ref ' => '#/components/schemas/ ' . $ definitionName ,
305+ ], $ nullable );
306+ }
307+
308+ return $ this ->makeNullableSchema ($ schema , $ nullable );
309+ }
310+
270311 protected function parseString ($ definition )
271312 {
272313 $ newDefinition = trim ($ definition , '? ' );
273314 if (is_subclass_of ($ newDefinition , ProductType::class)) {
274315 return $ this ->parseObject ($ definition );
275316 } elseif (is_subclass_of ($ newDefinition , SumType::class)) {
276317 return $ this ->parseEnum ($ definition );
318+ } elseif (is_subclass_of ($ newDefinition , MapType::class)) {
319+ return $ this ->parseMap ($ newDefinition );
277320 } else {
278321 return $ this ->parseScalar ($ definition );
279322 }
@@ -290,9 +333,9 @@ public function parse($definition)
290333 {
291334 if (is_array ($ definition )) {
292335 return $ this ->parseArray ($ definition );
293- } else if (is_string ($ definition )) {
336+ } elseif (is_string ($ definition )) {
294337 return $ this ->parseString ($ definition );
295- } else if (is_object ($ definition ) && $ definition instanceof ProductType) {
338+ } elseif (is_object ($ definition ) && $ definition instanceof ProductType) {
296339 return $ this ->parseObject (get_class ($ definition ));
297340 } else {
298341 throw new \InvalidArgumentException ('The definition is invalid ' );
0 commit comments