Skip to content

Commit aac6d9c

Browse files
Ocramiusteohhanhui
authored andcommitted
Conditionally fall back to JSON-Schema compatible with Swagger/OpenAPI v2
OpenAPI V2 has no way to generate accurate nullable types, so we need to disable nullable `oneOf` syntax in JSON-Schema by providing some context to the `TypeFactory` when not operating under OpenAPI v3 or newer considerations. In future, Swagger/OpenAPIV2 will (finally) at some point disappear, so we will be able to get rid of these conditionals once that happens.
1 parent 2839eb3 commit aac6d9c

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

SchemaFactory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,19 +258,19 @@ private function getMetadata(string $className, string $type = Schema::TYPE_OUTP
258258

259259
return [
260260
$resourceMetadata,
261-
$serializerContext ?? $this->getSerializerContext($resourceMetadata, $type, $operationType, $operationName),
261+
$this->getSerializerContext($resourceMetadata, $type, $operationType, $operationName, $serializerContext),
262262
$inputOrOutput['class'],
263263
];
264264
}
265265

266-
private function getSerializerContext(ResourceMetadata $resourceMetadata, string $type = Schema::TYPE_OUTPUT, ?string $operationType, ?string $operationName): array
266+
private function getSerializerContext(ResourceMetadata $resourceMetadata, string $type = Schema::TYPE_OUTPUT, ?string $operationType, ?string $operationName, ?array $previousSerializerContext): array
267267
{
268268
$attribute = Schema::TYPE_OUTPUT === $type ? 'normalization_context' : 'denormalization_context';
269269

270270
if (null === $operationType || null === $operationName) {
271-
return $resourceMetadata->getAttribute($attribute, []);
271+
return array_merge($resourceMetadata->getAttribute($attribute, []), (array) $previousSerializerContext);
272272
}
273273

274-
return $resourceMetadata->getTypedOperationAttribute($operationType, $operationName, $attribute, [], true);
274+
return array_merge($resourceMetadata->getTypedOperationAttribute($operationType, $operationName, $attribute, [], true), (array) $previousSerializerContext);
275275
}
276276
}

TypeFactory.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@
2727
*/
2828
final class TypeFactory implements TypeFactoryInterface
2929
{
30+
/**
31+
* This constant is to be provided as serializer context key to conditionally enable types to be generated in
32+
* a format that is compatible with OpenAPI specifications **PREVIOUS** to 3.0.
33+
*
34+
* Without this flag being set, the generated format will only be compatible with Swagger 3.0 or newer.
35+
*
36+
* Once support for OpenAPI < 3.0 is gone, this constant **WILL BE REMOVED**
37+
*
38+
* @internal Once support for OpenAPI < 3.0 is gone, this constant **WILL BE REMOVED** - do not rely on
39+
* it in downstream projects!
40+
*/
41+
public const CONTEXT_SERIALIZATION_FORMAT_OPENAPI_PRE_V3_0 = self::class.'::CONTEXT_SERIALIZATION_FORMAT_OPENAPI_PRE_V3_0';
42+
3043
use ResourceClassInfoTrait;
3144

3245
/**
@@ -60,7 +73,8 @@ public function getType(Type $type, string $format = 'json', ?bool $readableLink
6073
'type' => 'object',
6174
'additionalProperties' => $this->getType($subType, $format, $readableLink, $serializerContext, $schema),
6275
],
63-
$type
76+
$type,
77+
(array) $serializerContext
6478
);
6579
}
6680

@@ -69,13 +83,15 @@ public function getType(Type $type, string $format = 'json', ?bool $readableLink
6983
'type' => 'array',
7084
'items' => $this->getType($subType, $format, $readableLink, $serializerContext, $schema),
7185
],
72-
$type
86+
$type,
87+
(array) $serializerContext
7388
);
7489
}
7590

7691
return $this->addNullabilityToTypeDefinition(
7792
$this->makeBasicType($type, $format, $readableLink, $serializerContext, $schema),
78-
$type
93+
$type,
94+
(array) $serializerContext
7995
);
8096
}
8197

@@ -98,7 +114,7 @@ private function makeBasicType(Type $type, string $format = 'json', ?bool $reada
98114
/**
99115
* Gets the JSON Schema document which specifies the data type corresponding to the given PHP class, and recursively adds needed new schema to the current schema if provided.
100116
*/
101-
private function getClassType(?string $className, string $format = 'json', ?bool $readableLink = null, ?array $serializerContext = null, ?Schema $schema = null): array
117+
private function getClassType(?string $className, string $format, ?bool $readableLink, ?array $serializerContext, ?Schema $schema): array
102118
{
103119
if (null === $className) {
104120
return ['type' => 'object'];
@@ -154,8 +170,12 @@ private function getClassType(?string $className, string $format = 'json', ?bool
154170
*
155171
* @return array<string, mixed>
156172
*/
157-
private function addNullabilityToTypeDefinition(array $jsonSchema, Type $type): array
173+
private function addNullabilityToTypeDefinition(array $jsonSchema, Type $type, array $serializerContext): array
158174
{
175+
if (\array_key_exists(self::CONTEXT_SERIALIZATION_FORMAT_OPENAPI_PRE_V3_0, $serializerContext)) {
176+
return $jsonSchema;
177+
}
178+
159179
if (!$type->isNullable()) {
160180
return $jsonSchema;
161181
}

0 commit comments

Comments
 (0)