diff --git a/DependencyInjection/NelmioApiDocExtension.php b/DependencyInjection/NelmioApiDocExtension.php index 8db40fa..7a1193f 100644 --- a/DependencyInjection/NelmioApiDocExtension.php +++ b/DependencyInjection/NelmioApiDocExtension.php @@ -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, ]) diff --git a/Describer/OpenApiPhpDescriber.php b/Describer/OpenApiPhpDescriber.php index f9d27b5..cf02b7e 100644 --- a/Describer/OpenApiPhpDescriber.php +++ b/Describer/OpenApiPhpDescriber.php @@ -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; } diff --git a/ModelDescriber/Annotations/OpenApiAnnotationsReader.php b/ModelDescriber/Annotations/OpenApiAnnotationsReader.php index 7f09f0e..cac9937 100644 --- a/ModelDescriber/Annotations/OpenApiAnnotationsReader.php +++ b/ModelDescriber/Annotations/OpenApiAnnotationsReader.php @@ -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); diff --git a/Tests/Functional/Controller/ApiController.php b/Tests/Functional/Controller/ApiController.php index 059d7cb..289ca09 100644 --- a/Tests/Functional/Controller/ApiController.php +++ b/Tests/Functional/Controller/ApiController.php @@ -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() {