mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-09 02:59:27 +03:00
log name collisions (#1862)
This commit is contained in:
parent
6ebb9cc9b4
commit
985b43fb60
@ -20,9 +20,12 @@ use Nelmio\ApiDocBundle\OpenApiPhp\ModelRegister;
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Annotations\OpenApi;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
|
||||
final class ApiDocGenerator
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/** @var OpenApi */
|
||||
private $openApi;
|
||||
|
||||
@ -81,6 +84,9 @@ final class ApiDocGenerator
|
||||
|
||||
$this->openApi = new OpenApi([]);
|
||||
$modelRegistry = new ModelRegistry($this->modelDescribers, $this->openApi, $this->alternativeNames);
|
||||
if (null !== $this->logger) {
|
||||
$modelRegistry->setLogger($this->logger);
|
||||
}
|
||||
foreach ($this->describers as $describer) {
|
||||
if ($describer instanceof ModelRegistryAwareInterface) {
|
||||
$describer->setModelRegistry($modelRegistry);
|
||||
|
@ -66,11 +66,12 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
||||
$container->setParameter('nelmio_api_doc.media_types', $config['media_types']);
|
||||
foreach ($config['areas'] as $area => $areaConfig) {
|
||||
$nameAliases = $this->findNameAliases($config['models']['names'], $area);
|
||||
|
||||
$container->register(sprintf('nelmio_api_doc.generator.%s', $area), ApiDocGenerator::class)
|
||||
->setPublic(true)
|
||||
->addMethodCall('setAlternativeNames', [$nameAliases])
|
||||
->addMethodCall('setMediaTypes', [$config['media_types']])
|
||||
->addMethodCall('setLogger', [new Reference('logger')])
|
||||
->addTag('monolog.logger', ['channel' => 'nelmio_api_doc'])
|
||||
->setArguments([
|
||||
new TaggedIteratorArgument(sprintf('nelmio_api_doc.describer.%s', $area)),
|
||||
new TaggedIteratorArgument('nelmio_api_doc.model_describer'),
|
||||
|
@ -15,10 +15,16 @@ use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface;
|
||||
use Nelmio\ApiDocBundle\ModelDescriber\ModelDescriberInterface;
|
||||
use Nelmio\ApiDocBundle\OpenApiPhp\Util;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
|
||||
final class ModelRegistry
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
private $registeredModelNames = [];
|
||||
|
||||
private $alternativeNames = [];
|
||||
|
||||
private $unregistered = [];
|
||||
@ -40,10 +46,11 @@ final class ModelRegistry
|
||||
{
|
||||
$this->modelDescribers = $modelDescribers;
|
||||
$this->api = $api;
|
||||
|
||||
$this->logger = new NullLogger();
|
||||
foreach (array_reverse($alternativeNames) as $alternativeName => $criteria) {
|
||||
$this->alternativeNames[] = $model = new Model(new Type('object', false, $criteria['type']), $criteria['groups']);
|
||||
$this->names[$model->getHash()] = $alternativeName;
|
||||
$this->registeredModelNames[$alternativeName] = $model;
|
||||
Util::getSchema($this->api, $alternativeName);
|
||||
}
|
||||
}
|
||||
@ -57,6 +64,7 @@ final class ModelRegistry
|
||||
}
|
||||
if (!isset($this->names[$hash])) {
|
||||
$this->names[$hash] = $this->generateModelName($model);
|
||||
$this->registeredModelNames[$this->names[$hash]] = $model;
|
||||
}
|
||||
|
||||
// Reserve the name
|
||||
@ -115,6 +123,12 @@ final class ModelRegistry
|
||||
);
|
||||
$i = 1;
|
||||
while (\in_array($name, $names, true)) {
|
||||
if (isset($this->registeredModelNames[$name])) {
|
||||
$this->logger->info(sprintf('Can not assign a name for the model, the name "%s" has already been taken.', $name), [
|
||||
'model' => $this->modelToArray($model),
|
||||
'taken_by' => $this->modelToArray($this->registeredModelNames[$name]),
|
||||
]);
|
||||
}
|
||||
++$i;
|
||||
$name = $base.$i;
|
||||
}
|
||||
@ -122,6 +136,26 @@ final class ModelRegistry
|
||||
return $name;
|
||||
}
|
||||
|
||||
private function modelToArray(Model $model): array
|
||||
{
|
||||
$getType = function (Type $type) use (&$getType) {
|
||||
return [
|
||||
'class' => $type->getClassName(),
|
||||
'built_in_type' => $type->getBuiltinType(),
|
||||
'nullable' => $type->isNullable(),
|
||||
'collection' => $type->isCollection(),
|
||||
'collection_key_types' => $type->isCollection() ? array_map($getType, $type->getCollectionKeyTypes()) : null,
|
||||
'collection_value_types' => $type->isCollection() ? array_map($getType, $type->getCollectionValueTypes()) : null,
|
||||
];
|
||||
};
|
||||
|
||||
return [
|
||||
'type' => $getType($model->getType()),
|
||||
'options' => $model->getOptions(),
|
||||
'groups' => $model->getGroups(),
|
||||
];
|
||||
}
|
||||
|
||||
private function getTypeShortName(Type $type): string
|
||||
{
|
||||
if (null !== $type->getCollectionValueType()) {
|
||||
|
@ -15,6 +15,7 @@ use Nelmio\ApiDocBundle\Model\Model;
|
||||
use Nelmio\ApiDocBundle\Model\ModelRegistry;
|
||||
use OpenApi\Annotations as OA;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
|
||||
class ModelRegistryTest extends TestCase
|
||||
@ -33,6 +34,96 @@ class ModelRegistryTest extends TestCase
|
||||
$this->assertEquals('#/components/schemas/array', $registry->register(new Model($type, ['group1'])));
|
||||
}
|
||||
|
||||
public function testNameCollisionsAreLogged()
|
||||
{
|
||||
$logger = $this->createMock(LoggerInterface::class);
|
||||
$logger
|
||||
->expects(self::once())
|
||||
->method('info')
|
||||
->with(
|
||||
'Can not assign a name for the model, the name "ModelRegistryTest" has already been taken.', [
|
||||
'model' => [
|
||||
'type' => [
|
||||
'class' => 'Nelmio\\ApiDocBundle\\Tests\\Model\\ModelRegistryTest',
|
||||
'built_in_type' => 'object',
|
||||
'nullable' => false,
|
||||
'collection' => false,
|
||||
'collection_key_types' => null,
|
||||
'collection_value_types' => null,
|
||||
],
|
||||
'options' => null,
|
||||
'groups' => ['group2'],
|
||||
],
|
||||
'taken_by' => [
|
||||
'type' => [
|
||||
'class' => 'Nelmio\\ApiDocBundle\\Tests\\Model\\ModelRegistryTest',
|
||||
'built_in_type' => 'object',
|
||||
'nullable' => false,
|
||||
'collection' => false,
|
||||
'collection_key_types' => null,
|
||||
'collection_value_types' => null,
|
||||
],
|
||||
'options' => null,
|
||||
'groups' => ['group1'],
|
||||
],
|
||||
]);
|
||||
|
||||
$registry = new ModelRegistry([], new OA\OpenApi([]), []);
|
||||
$registry->setLogger($logger);
|
||||
|
||||
$type = new Type(Type::BUILTIN_TYPE_OBJECT, false, self::class);
|
||||
$registry->register(new Model($type, ['group1']));
|
||||
$registry->register(new Model($type, ['group2']));
|
||||
}
|
||||
|
||||
public function testNameCollisionsAreLoggedWithAlternativeNames()
|
||||
{
|
||||
$ref = new \ReflectionClass(self::class);
|
||||
$alternativeNames = [
|
||||
$ref->getShortName() => [
|
||||
'type' => $ref->getName(),
|
||||
'groups' => ['group1'],
|
||||
],
|
||||
];
|
||||
$logger = $this->createMock(LoggerInterface::class);
|
||||
$logger
|
||||
->expects(self::once())
|
||||
->method('info')
|
||||
->with(
|
||||
'Can not assign a name for the model, the name "ModelRegistryTest" has already been taken.', [
|
||||
'model' => [
|
||||
'type' => [
|
||||
'class' => 'Nelmio\\ApiDocBundle\\Tests\\Model\\ModelRegistryTest',
|
||||
'built_in_type' => 'object',
|
||||
'nullable' => false,
|
||||
'collection' => false,
|
||||
'collection_key_types' => null,
|
||||
'collection_value_types' => null,
|
||||
],
|
||||
'options' => null,
|
||||
'groups' => ['group2'],
|
||||
],
|
||||
'taken_by' => [
|
||||
'type' => [
|
||||
'class' => 'Nelmio\\ApiDocBundle\\Tests\\Model\\ModelRegistryTest',
|
||||
'built_in_type' => 'object',
|
||||
'nullable' => false,
|
||||
'collection' => false,
|
||||
'collection_key_types' => null,
|
||||
'collection_value_types' => null,
|
||||
],
|
||||
'options' => null,
|
||||
'groups' => ['group1'],
|
||||
],
|
||||
]);
|
||||
|
||||
$registry = new ModelRegistry([], new OA\OpenApi([]), $alternativeNames);
|
||||
$registry->setLogger($logger);
|
||||
|
||||
$type = new Type(Type::BUILTIN_TYPE_OBJECT, false, self::class);
|
||||
$registry->register(new Model($type, ['group2']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getNameAlternatives
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user