Support OpenAPI Polymorphism in ObjectModelDescriber

This is the default "symfony support" class, so seems like the right
place.
This commit is contained in:
Christopher Davis 2021-02-01 08:56:31 -06:00
parent d8626c2735
commit 9299c0e52e
6 changed files with 111 additions and 0 deletions

View File

@ -22,11 +22,13 @@ use Nelmio\ApiDocBundle\PropertyDescriber\PropertyDescriberInterface;
use OpenApi\Annotations as OA;
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwareInterface
{
use ModelRegistryAwareTrait;
use ApplyOpenApiDiscriminatorTrait;
/** @var PropertyInfoExtractorInterface */
private $propertyInfo;
@ -71,6 +73,17 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
$annotationsReader = new AnnotationsReader($this->doctrineReader, $this->modelRegistry, $this->mediaTypes);
$annotationsReader->updateDefinition($reflClass, $schema);
$discriminatorMap = $this->doctrineReader->getClassAnnotation($reflClass, DiscriminatorMap::class);
if ($discriminatorMap && $schema->discriminator === OA\UNDEFINED) {
$this->applyOpenApiDiscriminator(
$model,
$schema,
$this->modelRegistry,
$discriminatorMap->getTypeProperty(),
$discriminatorMap->getMapping()
);
}
$propertyInfoProperties = $this->propertyInfo->getProperties($class, $context);
if (null === $propertyInfoProperties) {

View File

@ -18,6 +18,7 @@ use Nelmio\ApiDocBundle\Annotation\Security;
use Nelmio\ApiDocBundle\Tests\Functional\Entity\Article;
use Nelmio\ApiDocBundle\Tests\Functional\Entity\CompoundEntity;
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyConstraints;
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyDiscriminator;
use Nelmio\ApiDocBundle\Tests\Functional\Entity\User;
use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyType;
use Nelmio\ApiDocBundle\Tests\Functional\Form\UserType;
@ -221,4 +222,13 @@ class ApiController
public function compoundEntityAction()
{
}
/**
* @Route("/discriminator-mapping", methods={"GET", "POST"})
*
* @OA\Response(response=200, description="Worked well!", @Model(type=SymfonyDiscriminator::class))
*/
public function discriminatorMappingAction()
{
}
}

View File

@ -0,0 +1,28 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/**
* @DiscriminatorMap(typeProperty="type", mapping={
* "one": SymfonyDiscriminatorOne::class,
* "two": SymfonyDiscriminatorTwo::class,
* })
*/
abstract class SymfonyDiscriminator
{
/**
* @var string
*/
public $type;
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
class SymfonyDiscriminatorOne extends SymfonyDiscriminator
{
/**
* @var string
*/
public $one;
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
class SymfonyDiscriminatorTwo extends SymfonyDiscriminator
{
/**
* @var string
*/
public $two;
}

View File

@ -498,4 +498,24 @@ class FunctionalTest extends WebTestCase
$this->assertNotHasProperty('protectedField', $model);
$this->assertNotHasProperty('protected', $model);
}
public function testModelsWithDiscriminatorMapAreLoadedWithOpenApiPolymorphism()
{
$model = $this->getModel('SymfonyDiscriminator');
$this->assertInstanceOf(OA\Discriminator::class, $model->discriminator);
$this->assertSame('type', $model->discriminator->propertyName);
$this->assertCount(2, $model->discriminator->mapping);
$this->assertArrayHasKey('one', $model->discriminator->mapping);
$this->assertArrayHasKey('two', $model->discriminator->mapping);
$this->assertNotSame(OA\UNDEFINED, $model->oneOf);
$this->assertCount(2, $model->oneOf);
}
public function testDiscriminatorMapLoadsChildrenModels()
{
// get model does its own assertions
$this->getModel('SymfonyDiscriminatorOne');
$this->getModel('SymfonyDiscriminatorTwo');
}
}