refactor(specs): simplify discriminator resolution

This commit is contained in:
Chirag Aggarwal
2026-04-16 11:15:08 +05:30
parent 6a7280e7dd
commit a0db023860
3 changed files with 38 additions and 26 deletions
+32 -20
View File
@@ -278,20 +278,16 @@ abstract class Format
* @param array<Model> $models
* @return array<string, mixed>|null
*/
protected function getUnionDiscriminator(array $models, string $refPrefix): ?array
protected function getDisciminator(array $models, string $refPrefix): ?array
{
if (\count($models) < 2) {
return null;
}
$candidateKeys = null;
$candidateKeys = \array_keys($models[0]->conditions);
foreach ($models as $model) {
$keys = \array_keys($model->conditions);
$candidateKeys = $candidateKeys === null
? $keys
: \array_values(\array_intersect($candidateKeys, $keys));
foreach (\array_slice($models, 1) as $model) {
$candidateKeys = \array_values(\array_intersect($candidateKeys, \array_keys($model->conditions)));
}
if (empty($candidateKeys)) {
@@ -300,34 +296,44 @@ abstract class Format
foreach ($candidateKeys as $key) {
$mapping = [];
$matchedModels = [];
$isValid = true;
foreach ($models as $model) {
$rules = $model->getRules();
$condition = $model->conditions[$key] ?? null;
if (!isset($rules[$key]) || ($rules[$key]['required'] ?? false) !== true) {
continue 2;
$isValid = false;
break;
}
$condition = $model->conditions[$key];
if (!\is_array($condition)) {
if (!\is_scalar($condition)) {
continue 2;
$isValid = false;
break;
}
$values = [$condition];
} else {
if ($condition === []) {
continue 2;
$isValid = false;
break;
}
$values = $condition;
$hasInvalidValue = false;
foreach ($values as $value) {
if (!\is_scalar($value)) {
continue 3;
$hasInvalidValue = true;
break;
}
}
if ($hasInvalidValue) {
$isValid = false;
break;
}
}
if (isset($rules[$key]['enum']) && \is_array($rules[$key]['enum'])) {
@@ -338,23 +344,29 @@ abstract class Format
}
if ($values === []) {
continue 2;
$isValid = false;
break;
}
$ref = $refPrefix . $model->getType();
foreach ($values as $value) {
$mappingKey = \is_bool($value) ? ($value ? 'true' : 'false') : (string) $value;
if (isset($mapping[$mappingKey]) && $mapping[$mappingKey] !== $refPrefix . $model->getType()) {
continue 2;
if (isset($mapping[$mappingKey]) && $mapping[$mappingKey] !== $ref) {
$isValid = false;
break;
}
$mapping[$mappingKey] = $refPrefix . $model->getType();
$mapping[$mappingKey] = $ref;
}
$matchedModels[$model->getType()] = true;
if (!$isValid) {
break;
}
}
if (\count($matchedModels) !== \count($models)) {
if (!$isValid || $mapping === []) {
continue;
}
@@ -318,7 +318,7 @@ class OpenAPI3 extends Format
$produces => [
'schema' => \array_filter([
'oneOf' => \array_map(fn ($m) => ['$ref' => '#/components/schemas/' . $m->getType()], $model),
'discriminator' => $this->getUnionDiscriminator($model, '#/components/schemas/'),
'discriminator' => $this->getDisciminator($model, '#/components/schemas/'),
]),
],
],
@@ -906,7 +906,7 @@ class OpenAPI3 extends Format
'anyOf' => \array_map(function ($type) {
return ['$ref' => '#/components/schemas/' . $type];
}, $rule['type']),
'discriminator' => $this->getUnionDiscriminator(
'discriminator' => $this->getDisciminator(
\array_map(fn (string $type) => $this->getRegisteredModel($type), $rule['type']),
'#/components/schemas/'
),
@@ -916,7 +916,7 @@ class OpenAPI3 extends Format
'oneOf' => \array_map(function ($type) {
return ['$ref' => '#/components/schemas/' . $type];
}, $rule['type']),
'discriminator' => $this->getUnionDiscriminator(
'discriminator' => $this->getDisciminator(
\array_map(fn (string $type) => $this->getRegisteredModel($type), $rule['type']),
'#/components/schemas/'
),
@@ -326,7 +326,7 @@ class Swagger2 extends Format
'x-oneOf' => \array_map(function ($m) {
return ['$ref' => '#/definitions/' . $m->getType()];
}, $model),
'x-discriminator' => $this->getUnionDiscriminator($model, '#/definitions/'),
'x-discriminator' => $this->getDisciminator($model, '#/definitions/'),
]),
];
} else {
@@ -884,7 +884,7 @@ class Swagger2 extends Format
if ($rule['array']) {
$items = \array_filter([
'x-anyOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/' . $type], $rule['type']),
'x-discriminator' => $this->getUnionDiscriminator(
'x-discriminator' => $this->getDisciminator(
\array_map(fn (string $type) => $this->getRegisteredModel($type), $rule['type']),
'#/definitions/'
),
@@ -892,7 +892,7 @@ class Swagger2 extends Format
} else {
$items = \array_filter([
'x-oneOf' => \array_map(fn ($type) => ['$ref' => '#/definitions/' . $type], $rule['type']),
'x-discriminator' => $this->getUnionDiscriminator(
'x-discriminator' => $this->getDisciminator(
\array_map(fn (string $type) => $this->getRegisteredModel($type), $rule['type']),
'#/definitions/'
),