Fix #1628 : annotations construction is context dependant (#1632)

* Fix #1628 : since annotations construction is context dependant, we cannot use the cached annotations reader

* CS

* Small improvement

* cs
This commit is contained in:
Guilhem Niot 2020-05-29 21:52:06 +02:00 committed by GitHub
parent 3f90ef6ce9
commit fb84e36fdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 26 deletions

View File

@ -87,7 +87,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
->setArguments([
new Reference(sprintf('nelmio_api_doc.routes.%s', $area)),
new Reference('nelmio_api_doc.controller_reflector'),
new Reference('annotation_reader'),
new Reference('annotations.reader'), // We cannot use the cached version of the annotation reader since the construction of the annotations is context dependant...
new Reference('logger'),
$config['media_types'],
])
@ -116,7 +116,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
(new Definition(FilteredRouteCollectionBuilder::class))
->setArguments(
[
new Reference('annotation_reader'),
new Reference('annotation_reader'), // Here we use the cached version as we don't deal with @OA annotations in this service
new Reference('nelmio_api_doc.controller_reflector'),
$area,
$areaConfig,
@ -165,7 +165,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
->setPublic(false)
->setArguments([
new Reference('jms_serializer.metadata_factory'),
new Reference('annotation_reader'),
new Reference('annotations.reader'),
$config['media_types'],
$jmsNamingStrategy,
])

View File

@ -18,6 +18,7 @@ use Nelmio\ApiDocBundle\OpenApiPhp\AddDefaults;
use Nelmio\ApiDocBundle\OpenApiPhp\ModelRegister;
use Nelmio\ApiDocBundle\OpenApiPhp\Util;
use Nelmio\ApiDocBundle\Util\ControllerReflector;
use OpenApi\Analyser;
use OpenApi\Analysis;
use OpenApi\Annotations as OA;
use Psr\Log\LoggerInterface;
@ -75,6 +76,15 @@ final class OpenApiPhpDescriber implements ModelRegistryAwareInterface
/** @var \ReflectionMethod $method */
foreach ($this->getMethodsToParse() as $method => list($path, $httpMethods)) {
$declaringClass = $method->getDeclaringClass();
$path = Util::getPath($api, $path);
Analyser::$context = Util::createContext(['nested' => $path], $path->_context);
Analyser::$context->namespace = $method->getNamespaceName();
Analyser::$context->class = $declaringClass->getShortName();
Analyser::$context->method = $method->name;
Analyser::$context->filename = $method->getFileName();
if (!array_key_exists($declaringClass->getName(), $classAnnotations)) {
$classAnnotations = array_filter($this->annotationReader->getClassAnnotations($declaringClass), function ($v) {
return $v instanceof OA\AbstractAnnotation;
@ -90,19 +100,10 @@ final class OpenApiPhpDescriber implements ModelRegistryAwareInterface
continue;
}
$path = Util::getPath($api, $path);
$path->_context->namespace = $method->getNamespaceName();
$path->_context->class = $declaringClass->getShortName();
$path->_context->method = $method->name;
$path->_context->filename = $method->getFileName();
$nestedContext = Util::createContext(['nested' => $path], $path->_context);
$implicitAnnotations = [];
$mergeProperties = new \stdClass();
foreach (array_merge($annotations, $classAnnotations[$declaringClass->getName()]) as $annotation) {
$annotation->_context = $nestedContext;
if ($annotation instanceof Operation) {
foreach ($httpMethods as $httpMethod) {
$operation = Util::getOperation($path, $httpMethod);
@ -142,13 +143,6 @@ final class OpenApiPhpDescriber implements ModelRegistryAwareInterface
throw new \LogicException(sprintf('Using the annotation "%s" as a root annotation in "%s::%s()" is not allowed.', get_class($annotation), $method->getDeclaringClass()->name, $method->name));
}
foreach ($annotation->_unmerged as $unmergedAnnotation) {
if (!$unmergedAnnotation instanceof OA\JsonContent && !$unmergedAnnotation instanceof OA\XmlContent) {
continue;
}
$unmergedAnnotation->_context->nested = $annotation;
}
$implicitAnnotations[] = $annotation;
}
@ -166,6 +160,9 @@ final class OpenApiPhpDescriber implements ModelRegistryAwareInterface
}
}
// Reset the Analyser after the parsing
Analyser::$context = null;
return $analysis;
}

View File

@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\ModelDescriber\Annotations;
use Doctrine\Common\Annotations\Reader;
use Nelmio\ApiDocBundle\Model\ModelRegistry;
use Nelmio\ApiDocBundle\OpenApiPhp\ModelRegister;
use OpenApi\Analyser;
use OpenApi\Analysis;
use OpenApi\Annotations as OA;
use OpenApi\Context;
@ -61,19 +62,20 @@ class OpenApiAnnotationsReader
public function updateProperty(\ReflectionProperty $reflectionProperty, OA\Property $property, array $serializationGroups = null): void
{
/** @var OA\Property $oaProperty */
if (!$oaProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, OA\Property::class)) {
return;
}
// In order to have nicer errors
$declaringClass = $reflectionProperty->getDeclaringClass();
$context = new Context([
Analyser::$context = new Context([
'namespace' => $declaringClass->getNamespaceName(),
'class' => $declaringClass->getShortName(),
'property' => $reflectionProperty->name,
'filename' => $declaringClass->getFileName(),
]);
$oaProperty->_context = $context;
/** @var OA\Property $oaProperty */
if (!$oaProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, OA\Property::class)) {
return;
}
Analyser::$context = null;
// Read @Model annotations
$this->modelRegister->__invoke(new Analysis([$oaProperty]), $serializationGroups);

View File

@ -36,6 +36,8 @@ class ApiController
* )
* @OA\Parameter(ref="#/components/parameters/test")
* @Route("/article/{id}", methods={"GET"})
* @OA\Parameter(name="Accept-Version", in="header", @OA\Schema(type="string"))
* @OA\Parameter(name="Application-Name", in="header", @OA\Schema(type="string"))
*/
public function fetchArticleAction()
{