mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-13 13:09:25 +03:00
Read discriminator mapping from file configuration (#2034)
* Read discriminator mapping from file configuration * Use more realistic test data
This commit is contained in:
parent
18425863b7
commit
f808eafbe4
@ -144,7 +144,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
|||||||
));
|
));
|
||||||
|
|
||||||
$container->getDefinition('nelmio_api_doc.model_describers.object')
|
$container->getDefinition('nelmio_api_doc.model_describers.object')
|
||||||
->setArgument(3, $config['media_types']);
|
->setArgument(4, $config['media_types']);
|
||||||
|
|
||||||
// Add autoconfiguration for model describer
|
// Add autoconfiguration for model describer
|
||||||
$container->registerForAutoconfiguration(ModelDescriberInterface::class)
|
$container->registerForAutoconfiguration(ModelDescriberInterface::class)
|
||||||
|
@ -23,7 +23,7 @@ use OpenApi\Annotations as OA;
|
|||||||
use OpenApi\Generator;
|
use OpenApi\Generator;
|
||||||
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
|
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
|
||||||
use Symfony\Component\PropertyInfo\Type;
|
use Symfony\Component\PropertyInfo\Type;
|
||||||
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||||
|
|
||||||
class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwareInterface
|
class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwareInterface
|
||||||
@ -33,6 +33,8 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
|
|||||||
|
|
||||||
/** @var PropertyInfoExtractorInterface */
|
/** @var PropertyInfoExtractorInterface */
|
||||||
private $propertyInfo;
|
private $propertyInfo;
|
||||||
|
/** @var ClassMetadataFactoryInterface */
|
||||||
|
private $classMetadataFactory;
|
||||||
/** @var Reader */
|
/** @var Reader */
|
||||||
private $doctrineReader;
|
private $doctrineReader;
|
||||||
/** @var PropertyDescriberInterface[] */
|
/** @var PropertyDescriberInterface[] */
|
||||||
@ -46,6 +48,7 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
PropertyInfoExtractorInterface $propertyInfo,
|
PropertyInfoExtractorInterface $propertyInfo,
|
||||||
|
ClassMetadataFactoryInterface $classMetadataFactory,
|
||||||
Reader $reader,
|
Reader $reader,
|
||||||
iterable $propertyDescribers,
|
iterable $propertyDescribers,
|
||||||
array $mediaTypes,
|
array $mediaTypes,
|
||||||
@ -53,6 +56,7 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
|
|||||||
bool $useValidationGroups = false
|
bool $useValidationGroups = false
|
||||||
) {
|
) {
|
||||||
$this->propertyInfo = $propertyInfo;
|
$this->propertyInfo = $propertyInfo;
|
||||||
|
$this->classMetadataFactory = $classMetadataFactory;
|
||||||
$this->doctrineReader = $reader;
|
$this->doctrineReader = $reader;
|
||||||
$this->propertyDescribers = $propertyDescribers;
|
$this->propertyDescribers = $propertyDescribers;
|
||||||
$this->mediaTypes = $mediaTypes;
|
$this->mediaTypes = $mediaTypes;
|
||||||
@ -85,14 +89,17 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
|
|||||||
|
|
||||||
$schema->type = 'object';
|
$schema->type = 'object';
|
||||||
|
|
||||||
$discriminatorMap = $this->getAnnotation($reflClass, DiscriminatorMap::class);
|
$mapping = $this->classMetadataFactory
|
||||||
if ($discriminatorMap && Generator::UNDEFINED === $schema->discriminator) {
|
->getMetadataFor($class)
|
||||||
|
->getClassDiscriminatorMapping();
|
||||||
|
|
||||||
|
if ($mapping && Generator::UNDEFINED === $schema->discriminator) {
|
||||||
$this->applyOpenApiDiscriminator(
|
$this->applyOpenApiDiscriminator(
|
||||||
$model,
|
$model,
|
||||||
$schema,
|
$schema,
|
||||||
$this->modelRegistry,
|
$this->modelRegistry,
|
||||||
$discriminatorMap->getTypeProperty(),
|
$mapping->getTypeProperty(),
|
||||||
$discriminatorMap->getMapping()
|
$mapping->getTypesMapping()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,23 +203,6 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
|
|||||||
throw new \Exception(sprintf('Type "%s" is not supported in %s::$%s. You may use the `@OA\Property(type="")` annotation to specify it manually.', $types[0]->getBuiltinType(), $model->getType()->getClassName(), $propertyName));
|
throw new \Exception(sprintf('Type "%s" is not supported in %s::$%s. You may use the `@OA\Property(type="")` annotation to specify it manually.', $types[0]->getBuiltinType(), $model->getType()->getClassName(), $propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function getAnnotation(\ReflectionClass $reflection, string $className)
|
|
||||||
{
|
|
||||||
if (false === class_exists($className)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (\PHP_VERSION_ID >= 80000) {
|
|
||||||
if (null !== $attribute = $reflection->getAttributes($className, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
|
|
||||||
return $attribute->newInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->doctrineReader->getClassAnnotation($reflection, $className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function supports(Model $model): bool
|
public function supports(Model $model): bool
|
||||||
{
|
{
|
||||||
return Type::BUILTIN_TYPE_OBJECT === $model->getType()->getBuiltinType()
|
return Type::BUILTIN_TYPE_OBJECT === $model->getType()->getBuiltinType()
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
<!-- Model Describers -->
|
<!-- Model Describers -->
|
||||||
<service id="nelmio_api_doc.model_describers.object" class="Nelmio\ApiDocBundle\ModelDescriber\ObjectModelDescriber" public="false">
|
<service id="nelmio_api_doc.model_describers.object" class="Nelmio\ApiDocBundle\ModelDescriber\ObjectModelDescriber" public="false">
|
||||||
<argument type="service" id="property_info" />
|
<argument type="service" id="property_info" />
|
||||||
|
<argument type="service" id="serializer.mapping.class_metadata_factory" />
|
||||||
<argument type="service" id="annotations.reader" />
|
<argument type="service" id="annotations.reader" />
|
||||||
<argument type="tagged" tag="nelmio_api_doc.object_model.property_describer" />
|
<argument type="tagged" tag="nelmio_api_doc.object_model.property_describer" />
|
||||||
<argument />
|
<argument />
|
||||||
|
@ -24,6 +24,7 @@ use Nelmio\ApiDocBundle\Tests\Functional\Entity\EntityWithRef;
|
|||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyConstraints;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyConstraints;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyConstraintsWithValidationGroups;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyConstraintsWithValidationGroups;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyDiscriminator;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyDiscriminator;
|
||||||
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyDiscriminatorFileMapping;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\User;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\User;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyType;
|
use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyType;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Form\FormWithAlternateSchemaType;
|
use Nelmio\ApiDocBundle\Tests\Functional\Form\FormWithAlternateSchemaType;
|
||||||
@ -277,6 +278,15 @@ class ApiController80
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/discriminator-mapping-configured-with-file", methods={"GET", "POST"})
|
||||||
|
*
|
||||||
|
* @OA\Response(response=200, description="Worked well!", @Model(type=SymfonyDiscriminatorFileMapping::class))
|
||||||
|
*/
|
||||||
|
public function discriminatorMappingConfiguredWithFileAction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/named_route-operation-id", name="named_route_operation_id", methods={"GET", "POST"})
|
* @Route("/named_route-operation-id", name="named_route_operation_id", methods={"GET", "POST"})
|
||||||
*
|
*
|
||||||
|
16
Tests/Functional/Entity/SymfonyDiscriminatorFileMapping.php
Normal file
16
Tests/Functional/Entity/SymfonyDiscriminatorFileMapping.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
interface SymfonyDiscriminatorFileMapping
|
||||||
|
{
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
|
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
|
||||||
|
|
||||||
class SymfonyDiscriminatorOne extends SymfonyDiscriminator
|
class SymfonyDiscriminatorOne extends SymfonyDiscriminator implements SymfonyDiscriminatorFileMapping
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
|
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
|
||||||
|
|
||||||
class SymfonyDiscriminatorTwo extends SymfonyDiscriminator
|
class SymfonyDiscriminatorTwo extends SymfonyDiscriminator implements SymfonyDiscriminatorFileMapping
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
|
@ -622,6 +622,19 @@ class FunctionalTest extends WebTestCase
|
|||||||
$this->assertCount(2, $model->oneOf);
|
$this->assertCount(2, $model->oneOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testModelsWithDiscriminatorMapAreLoadedWithOpenApiPolymorphismWhenUsingFileConfiguration()
|
||||||
|
{
|
||||||
|
$model = $this->getModel('SymfonyDiscriminatorFileMapping');
|
||||||
|
|
||||||
|
$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(Generator::UNDEFINED, $model->oneOf);
|
||||||
|
$this->assertCount(2, $model->oneOf);
|
||||||
|
}
|
||||||
|
|
||||||
public function testDiscriminatorMapLoadsChildrenModels()
|
public function testDiscriminatorMapLoadsChildrenModels()
|
||||||
{
|
{
|
||||||
// get model does its own assertions
|
// get model does its own assertions
|
||||||
|
6
Tests/Functional/Resources/serializer/discriminator.yaml
Normal file
6
Tests/Functional/Resources/serializer/discriminator.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyDiscriminatorFileMapping:
|
||||||
|
discriminator_map:
|
||||||
|
type_property: type
|
||||||
|
mapping:
|
||||||
|
one: Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyDiscriminatorOne
|
||||||
|
two: Nelmio\ApiDocBundle\Tests\Functional\Entity\SymfonyDiscriminatorTwo
|
@ -131,7 +131,12 @@ class TestKernel extends Kernel
|
|||||||
'test' => null,
|
'test' => null,
|
||||||
'validation' => null,
|
'validation' => null,
|
||||||
'form' => null,
|
'form' => null,
|
||||||
'serializer' => ['enable_annotations' => true],
|
'serializer' => [
|
||||||
|
'enable_annotations' => true,
|
||||||
|
'mapping' => [
|
||||||
|
'paths' => [__DIR__.'/Resources/serializer/'],
|
||||||
|
],
|
||||||
|
],
|
||||||
'property_access' => true,
|
'property_access' => true,
|
||||||
];
|
];
|
||||||
// Support symfony/framework-bundle < 5.4
|
// Support symfony/framework-bundle < 5.4
|
||||||
|
Loading…
x
Reference in New Issue
Block a user