Skip to content

Commit 3beb6b2

Browse files
committed
Support namespace definition on JSON schema type - close #11
1 parent 1792fdc commit 3beb6b2

3 files changed

Lines changed: 100 additions & 11 deletions

File tree

src/Shorthand/Shorthand.php

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,26 @@ private static function convertShorthandStringToJsonSchema(string $shorthandStr)
126126
];
127127
}
128128

129+
$type = $parts[0];
130+
$namespace = '';
131+
$namespaceDetected = false !== \strpos($parts[0], '/');
132+
133+
if ($namespaceDetected) {
134+
$namespace = self::extractNamespace($type);
135+
$type = self::extractType($type);
136+
}
137+
129138
switch (true) {
130-
case \mb_strpos($parts[0], 'string') === 0:
131-
case \mb_strpos($parts[0], 'integer') === 0:
132-
case \mb_strpos($parts[0], 'number') === 0:
133-
case \mb_strpos($parts[0], 'boolean') === 0:
134-
case \mb_strpos($parts[0], 'enum:') === 0:
135-
$type = $parts[0];
139+
case \mb_strpos($type, 'string') === 0:
140+
case \mb_strpos($type, 'integer') === 0:
141+
case \mb_strpos($type, 'number') === 0:
142+
case \mb_strpos($type, 'boolean') === 0:
143+
case \mb_strpos($type, 'enum:') === 0:
136144
$typeKey = 'type';
137145
$typeValue = $type;
138146

139-
if (\mb_strpos($parts[0], 'enum:') === 0) {
140-
$typeValue = \explode(',', \mb_substr($parts[0], 5));
147+
if (\mb_strpos($type, 'enum:') === 0) {
148+
$typeValue = \explode(',', \mb_substr($type, 5));
141149
$typeKey = 'enum';
142150
}
143151

@@ -150,13 +158,19 @@ private static function convertShorthandStringToJsonSchema(string $shorthandStr)
150158
$schema = self::populateSchema($parts);
151159
$schema[$typeKey] = $typeValue;
152160

161+
if ($namespaceDetected) {
162+
$schema['namespace'] = \strlen($namespace) > 1 ? \rtrim($namespace, '/') : $namespace;
163+
}
164+
153165
return $schema;
154166
default:
155-
$type = $parts[0];
156-
157167
$schema = self::populateSchema($parts);
158168

159-
$schema['$ref'] = '#/definitions/'.$type;
169+
$schema['$ref'] = '#/definitions/' . \ltrim($namespace, '/') . $type;
170+
171+
if ($namespaceDetected) {
172+
$schema['namespace'] = \strlen($namespace) > 1 ? \rtrim($namespace, '/') : $namespace;
173+
}
160174

161175
return $schema;
162176
}
@@ -218,4 +232,14 @@ private static function parseShorthandValidation(string $shorthandValidation): a
218232

219233
return [$validationKey, $value];
220234
}
235+
236+
private static function extractType(string $type): string
237+
{
238+
return \trim(\substr($type, \strrpos($type, '/') + 1), '/');
239+
}
240+
241+
private static function extractNamespace(string $type): string
242+
{
243+
return \substr($type, 0, \strrpos($type, '/') + 1);
244+
}
221245
}

tests/Type/ObjectTypeTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,65 @@ public function it_supports_definition_of_objects_shorthand(): void
140140
$this->assertSame(['namespace' => 'Order'], $address->custom());
141141
}
142142

143+
/**
144+
* @test
145+
*/
146+
public function it_supports_definition_of_objects_shorthand_type_ns(): void
147+
{
148+
$json = \file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'schema_with_objects_shorthand_type_ns.json');
149+
$decodedJson = \json_decode($json, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR);
150+
151+
$typeSet = Type::fromShorthand($decodedJson);
152+
153+
$this->assertCount(1, $typeSet);
154+
155+
/** @var ObjectType $type */
156+
$type = $typeSet->first();
157+
$this->assertInstanceOf(ObjectType::class, $type);
158+
$this->assertFalse($type->additionalProperties());
159+
160+
$required = $type->required();
161+
$this->assertCount(4, $required);
162+
$this->assertContains('uuid', $required);
163+
$this->assertContains('salutation', $required);
164+
$this->assertContains('billing_address', $required);
165+
$this->assertContains('shipping_address', $required);
166+
167+
$properties = $type->properties();
168+
$this->assertCount(4, $properties);
169+
$this->assertArrayHasKey('uuid', $properties);
170+
$this->assertArrayHasKey('salutation', $properties);
171+
$this->assertArrayHasKey('shipping_address', $properties);
172+
$this->assertArrayHasKey('shipping_address', $properties);
173+
174+
/** @var StringType $uuid */
175+
$uuid = $properties['uuid']->first();
176+
$this->assertInstanceOf(StringType::class, $uuid);
177+
$this->assertSame('uuid', $uuid->format());
178+
$this->assertSame(['namespace' => '/'], $uuid->custom());
179+
180+
/** @var StringType $salutation */
181+
$salutation = $properties['salutation']->first();
182+
$this->assertInstanceOf(StringType::class, $salutation);
183+
$this->assertSame(['MR', 'MRS'], $salutation->enum());
184+
$this->assertSame(['namespace' => '/Contact'], $salutation->custom());
185+
186+
/** @var ReferenceType $billingAddress */
187+
$billingAddress = $properties['billing_address']->first();
188+
$this->assertInstanceOf(ReferenceType::class, $billingAddress);
189+
$this->assertSame(['namespace' => 'Order'], $billingAddress->custom());
190+
191+
/** @var ArrayType $shippingAddress */
192+
$shippingAddress = $properties['shipping_address']->first();
193+
$this->assertInstanceOf(ArrayType::class, $shippingAddress);
194+
$this->assertSame([], $shippingAddress->custom());
195+
196+
/** @var ReferenceType $address */
197+
$address = $shippingAddress->items()[0]->first();
198+
$this->assertInstanceOf(ReferenceType::class, $address);
199+
$this->assertSame(['namespace' => 'Order'], $address->custom());
200+
}
201+
143202
/**
144203
* @test
145204
*/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"uuid": "/string|format:uuid",
3+
"salutation": "/Contact/enum:MR,MRS",
4+
"billing_address": "Order/Address",
5+
"shipping_address": "Order/Address[]"
6+
}

0 commit comments

Comments
 (0)