Skip to content

Commit d4e14ae

Browse files
committed
Added MapType
1 parent 1708081 commit d4e14ae

3 files changed

Lines changed: 188 additions & 39 deletions

File tree

src/TypeParser.php

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@
22

33
namespace rethink\typedphp;
44

5-
use rethink\typedphp\types\BooleanType;
5+
use InvalidArgumentException;
6+
use phpDocumentor\Reflection\DocBlockFactory;
67
use rethink\typedphp\types\BinaryType;
8+
use rethink\typedphp\types\BooleanType;
79
use rethink\typedphp\types\DateType;
810
use rethink\typedphp\types\DictType;
911
use rethink\typedphp\types\InputType;
1012
use rethink\typedphp\types\IntegerType;
11-
use rethink\typedphp\types\ProductType;
13+
use rethink\typedphp\types\MapType;
1214
use rethink\typedphp\types\NumberType;
15+
use rethink\typedphp\types\ProductType;
1316
use rethink\typedphp\types\StringType;
1417
use rethink\typedphp\types\SumType;
1518
use rethink\typedphp\types\TimestampType;
1619
use rethink\typedphp\types\TimeType;
1720
use rethink\typedphp\types\Type;
18-
use phpDocumentor\Reflection\DocBlockFactory;
1921

2022
/**
2123
* Class TypeParser
@@ -25,8 +27,8 @@
2527
class 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');

src/types/MapType.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace rethink\typedphp\types;
4+
5+
/**
6+
* Class MapType
7+
*
8+
* Powerful version of DictType
9+
*
10+
* @package rethink\typedphp\types
11+
*/
12+
abstract class MapType implements Type
13+
{
14+
public static function name()
15+
{
16+
$parts = explode('\\', static::class);
17+
18+
$name = end($parts);
19+
20+
return substr($name, 0, strlen($name) - 4);
21+
}
22+
23+
public static function toArray()
24+
{
25+
return [
26+
'type' => 'object',
27+
];
28+
}
29+
30+
abstract public static function valueType(): string;
31+
32+
abstract public static function example(): array;
33+
}

0 commit comments

Comments
 (0)