Skip to content

Commit 53b9033

Browse files
authored
Merge pull request #7 from devonliu02/map-type
MapType Support
2 parents 1708081 + 7a205a2 commit 53b9033

3 files changed

Lines changed: 188 additions & 42 deletions

File tree

src/TypeParser.php

Lines changed: 57 additions & 17 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];
@@ -142,11 +144,13 @@ protected function parseInputField($definition)
142144

143145
list($_, $schema) = $this->parseField($definition);
144146

145-
return [
147+
$result = [
146148
'in' => $fetcher,
147-
'required' => $required,
148149
'schema' => $schema,
149150
];
151+
if ($required) {
152+
$result['required'] = $required;
153+
}
150154
}
151155

152156
private function isNullable(string $definition): bool
@@ -195,8 +199,10 @@ protected function parseObject($definition)
195199
$schema = [
196200
'type' => 'object',
197201
'properties' => $properties,
198-
'required' => $requiredFields,
199202
];
203+
if ($requiredFields) {
204+
$schema['required'] = $requiredFields;
205+
}
200206

201207
if ($this->mode & self::MODE_REF_SCHEMA) {
202208
$this->schemas[$definitionName] = $schema;
@@ -242,7 +248,7 @@ protected function makeNullableSchema(array $schema, $nullable)
242248
'anyOf' => [
243249
['type' => 'null'],
244250
$schema,
245-
]
251+
],
246252
];
247253
}
248254

@@ -255,25 +261,59 @@ protected function parseScalar($definition)
255261
}
256262

257263
$typeClass = $this->getValidTypeClass($definition);
258-
259264
$schema = $typeClass::toArray();
260265

261266
if (($this->mode & self::MODE_JSON_SCHEMA) && $nullable) {
262267
$schema['type'] = [$schema['type'], 'null'];
263-
} else if (($this->mode & self::MODE_OPEN_API) && $nullable) {
268+
} elseif (($this->mode & self::MODE_OPEN_API) && $nullable) {
264269
$schema['nullable'] = $nullable;
265270
}
266271

267272
return $schema;
268273
}
269274

275+
protected function parseMap(string $definition): array
276+
{
277+
$nullable = false;
278+
if ($this->isNullable($definition)) {
279+
$nullable = true;
280+
$definition = trim($definition, '?');
281+
}
282+
283+
assert(is_subclass_of($definition, MapType::class));
284+
285+
$schema = $definition::toArray();
286+
287+
$valueDefinition = $definition::valueType();
288+
if ($valueDefinition) {
289+
$schema['additionalProperties'] = $this->parseString($valueDefinition);
290+
}
291+
292+
$example = $definition::example();
293+
if ($example) {
294+
$schema['example'] = $example;
295+
}
296+
297+
$definitionName = $definition::name();
298+
if ($this->mode & self::MODE_REF_SCHEMA) {
299+
$this->schemas[$definitionName] = $schema;
300+
return $this->makeNullableSchema([
301+
'$ref' => '#/components/schemas/' . $definitionName,
302+
], $nullable);
303+
}
304+
305+
return $this->makeNullableSchema($schema, $nullable);
306+
}
307+
270308
protected function parseString($definition)
271309
{
272310
$newDefinition = trim($definition, '?');
273311
if (is_subclass_of($newDefinition, ProductType::class)) {
274312
return $this->parseObject($definition);
275313
} elseif (is_subclass_of($newDefinition, SumType::class)) {
276314
return $this->parseEnum($definition);
315+
} elseif (is_subclass_of($newDefinition, MapType::class)) {
316+
return $this->parseMap($newDefinition);
277317
} else {
278318
return $this->parseScalar($definition);
279319
}
@@ -290,9 +330,9 @@ public function parse($definition)
290330
{
291331
if (is_array($definition)) {
292332
return $this->parseArray($definition);
293-
} else if (is_string($definition)) {
333+
} elseif (is_string($definition)) {
294334
return $this->parseString($definition);
295-
} else if (is_object($definition) && $definition instanceof ProductType) {
335+
} elseif (is_object($definition) && $definition instanceof ProductType) {
296336
return $this->parseObject(get_class($definition));
297337
} else {
298338
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)