Skip to content

Commit

Permalink
use hash to determine unique types (#2201)
Browse files Browse the repository at this point in the history
* use hash to determine unique types

* rework ArrayPropertyDescriber

* fix php < 7.4 test
  • Loading branch information
DjordyKoert committed Jan 26, 2024
1 parent 3cce6fe commit d7f9b80
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 15 deletions.
19 changes: 10 additions & 9 deletions PropertyDescriber/ArrayPropertyDescriber.php
Expand Up @@ -26,19 +26,20 @@ public function describe(array $types, OA\Schema $property, array $groups = null
$property->type = 'array';
$property = Util::getChild($property, OA\Items::class);

// BC layer for symfony < 5.3
$type = method_exists($types[0], 'getCollectionValueTypes') ?
($types[0]->getCollectionValueTypes()[0] ?? null) :
$types[0]->getCollectionValueType();
if (null === $type) {
return;
foreach ($types[0]->getCollectionValueTypes() as $type) {
// Handle list pseudo type
// https://symfony.com/doc/current/components/property_info.html#type-getcollectionkeytypes-type-getcollectionvaluetypes
if ($this->supports([$type]) && empty($type->getCollectionValueTypes())) {
continue;
}

$this->propertyDescriber->describe([$type], $property, $groups, $schema, $context);
}

$this->propertyDescriber->describe([$type], $property, $groups, $schema, $context);
}

public function supports(array $types): bool
{
return 1 === count($types) && $types[0]->isCollection();
return 1 === count($types)
&& $types[0]->isCollection();
}
}
15 changes: 11 additions & 4 deletions PropertyDescriber/PropertyDescriber.php
Expand Up @@ -12,7 +12,7 @@ final class PropertyDescriber implements PropertyDescriberInterface, ModelRegist
{
use ModelRegistryAwareTrait;

/** @var PropertyDescriberInterface[] Recursion helper */
/** @var array<string, PropertyDescriberInterface[]> Recursion helper */
private $called = [];

/** @var PropertyDescriberInterface[] */
Expand All @@ -30,7 +30,7 @@ public function describe(array $types, OA\Schema $property, array $groups = null
return;
}

$this->called[] = $propertyDescriber;
$this->called[$this->getHash($types)][] = $propertyDescriber;
$propertyDescriber->describe($types, $property, $groups, $schema, $context);
$this->called = []; // Reset recursion helper
}
Expand All @@ -40,6 +40,11 @@ public function supports(array $types): bool
return null !== $this->getPropertyDescriber($types);
}

private function getHash(array $types): string
{
return md5(serialize($types));
}

private function getPropertyDescriber(array $types): ?PropertyDescriberInterface
{
foreach ($this->propertyDescribers as $propertyDescriber) {
Expand All @@ -49,8 +54,10 @@ private function getPropertyDescriber(array $types): ?PropertyDescriberInterface
}

// Prevent infinite recursion
if (in_array($propertyDescriber, $this->called, true)) {
continue;
if (key_exists($this->getHash($types), $this->called)) {
if (in_array($propertyDescriber, $this->called[$this->getHash($types)], true)) {
continue;
}
}

if ($propertyDescriber instanceof ModelRegistryAwareInterface) {
Expand Down
5 changes: 5 additions & 0 deletions Tests/Functional/Entity/CompoundEntity.php
Expand Up @@ -27,4 +27,9 @@ class CompoundEntity
* @var CompoundEntityNested[]|string|null
*/
public $complexNested;

/**
* @var array<CompoundEntityNested>|array<array<CompoundEntityNested>>
*/
public $arrayOfArrayComplex;
}
50 changes: 48 additions & 2 deletions Tests/Functional/FunctionalTest.php
Expand Up @@ -625,7 +625,7 @@ public function testCompoundEntityAction()
self::assertEquals([
'schema' => 'CompoundEntity',
'type' => 'object',
'required' => ['complex'],
'required' => ['complex', 'arrayOfArrayComplex'],
'properties' => [
'complex' => [
'oneOf' => [
Expand All @@ -645,6 +645,7 @@ public function testCompoundEntityAction()
'oneOf' => [
[
'type' => 'integer',
'nullable' => true,
],
[
'type' => 'array',
Expand All @@ -663,13 +664,33 @@ public function testCompoundEntityAction()
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
'nullable' => true,
],
[
'type' => 'string',
'nullable' => true, // For some reason, this only exists on PHP < 7.4, which should not be the case. Assuming this to be a bug in PHP.
],
],
],
'arrayOfArrayComplex' => [
'oneOf' => [
[
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
],
[
'type' => 'array',
'items' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
],
],
],
],
],
], json_decode($this->getModel('CompoundEntity')->toJson(), true));

Expand All @@ -696,6 +717,7 @@ public function testCompoundEntityAction()
'oneOf' => [
[
'type' => 'integer',
'nullable' => true,
],
[
'type' => 'array',
Expand All @@ -714,6 +736,7 @@ public function testCompoundEntityAction()
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
'nullable' => true,
],
[
'type' => 'string',
Expand All @@ -730,7 +753,7 @@ public function testCompoundEntityAction()
self::assertEquals([
'schema' => 'CompoundEntity',
'type' => 'object',
'required' => ['complex'],
'required' => ['complex', 'arrayOfArrayComplex'],
'properties' => [
'complex' => [
'oneOf' => [
Expand All @@ -750,6 +773,7 @@ public function testCompoundEntityAction()
'oneOf' => [
[
'type' => 'integer',
'nullable' => true,
],
[
'type' => 'array',
Expand All @@ -767,12 +791,32 @@ public function testCompoundEntityAction()
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
'nullable' => true,
],
[
'type' => 'string',
],
],
],
'arrayOfArrayComplex' => [
'oneOf' => [
[
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
],
[
'type' => 'array',
'items' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
],
],
],
],
],
], json_decode($this->getModel('CompoundEntity')->toJson(), true));

Expand All @@ -799,6 +843,7 @@ public function testCompoundEntityAction()
'oneOf' => [
[
'type' => 'integer',
'nullable' => true,
],
[
'type' => 'array',
Expand All @@ -816,6 +861,7 @@ public function testCompoundEntityAction()
'items' => [
'$ref' => '#/components/schemas/CompoundEntityNested',
],
'nullable' => true,
],
[
'type' => 'string',
Expand Down

0 comments on commit d7f9b80

Please sign in to comment.