mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-03-12 02:26:09 +03:00
* Fix #1628 : since annotations construction is context dependant, we cannot use the cached annotations reader * CS * Small improvement * cs
This commit is contained in:
parent
3f90ef6ce9
commit
fb84e36fdf
@ -87,7 +87,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
|||||||
->setArguments([
|
->setArguments([
|
||||||
new Reference(sprintf('nelmio_api_doc.routes.%s', $area)),
|
new Reference(sprintf('nelmio_api_doc.routes.%s', $area)),
|
||||||
new Reference('nelmio_api_doc.controller_reflector'),
|
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'),
|
new Reference('logger'),
|
||||||
$config['media_types'],
|
$config['media_types'],
|
||||||
])
|
])
|
||||||
@ -116,7 +116,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
|||||||
(new Definition(FilteredRouteCollectionBuilder::class))
|
(new Definition(FilteredRouteCollectionBuilder::class))
|
||||||
->setArguments(
|
->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'),
|
new Reference('nelmio_api_doc.controller_reflector'),
|
||||||
$area,
|
$area,
|
||||||
$areaConfig,
|
$areaConfig,
|
||||||
@ -165,7 +165,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
|||||||
->setPublic(false)
|
->setPublic(false)
|
||||||
->setArguments([
|
->setArguments([
|
||||||
new Reference('jms_serializer.metadata_factory'),
|
new Reference('jms_serializer.metadata_factory'),
|
||||||
new Reference('annotation_reader'),
|
new Reference('annotations.reader'),
|
||||||
$config['media_types'],
|
$config['media_types'],
|
||||||
$jmsNamingStrategy,
|
$jmsNamingStrategy,
|
||||||
])
|
])
|
||||||
|
@ -18,6 +18,7 @@ use Nelmio\ApiDocBundle\OpenApiPhp\AddDefaults;
|
|||||||
use Nelmio\ApiDocBundle\OpenApiPhp\ModelRegister;
|
use Nelmio\ApiDocBundle\OpenApiPhp\ModelRegister;
|
||||||
use Nelmio\ApiDocBundle\OpenApiPhp\Util;
|
use Nelmio\ApiDocBundle\OpenApiPhp\Util;
|
||||||
use Nelmio\ApiDocBundle\Util\ControllerReflector;
|
use Nelmio\ApiDocBundle\Util\ControllerReflector;
|
||||||
|
use OpenApi\Analyser;
|
||||||
use OpenApi\Analysis;
|
use OpenApi\Analysis;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
@ -75,6 +76,15 @@ final class OpenApiPhpDescriber implements ModelRegistryAwareInterface
|
|||||||
/** @var \ReflectionMethod $method */
|
/** @var \ReflectionMethod $method */
|
||||||
foreach ($this->getMethodsToParse() as $method => list($path, $httpMethods)) {
|
foreach ($this->getMethodsToParse() as $method => list($path, $httpMethods)) {
|
||||||
$declaringClass = $method->getDeclaringClass();
|
$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)) {
|
if (!array_key_exists($declaringClass->getName(), $classAnnotations)) {
|
||||||
$classAnnotations = array_filter($this->annotationReader->getClassAnnotations($declaringClass), function ($v) {
|
$classAnnotations = array_filter($this->annotationReader->getClassAnnotations($declaringClass), function ($v) {
|
||||||
return $v instanceof OA\AbstractAnnotation;
|
return $v instanceof OA\AbstractAnnotation;
|
||||||
@ -90,19 +100,10 @@ final class OpenApiPhpDescriber implements ModelRegistryAwareInterface
|
|||||||
continue;
|
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 = [];
|
$implicitAnnotations = [];
|
||||||
$mergeProperties = new \stdClass();
|
$mergeProperties = new \stdClass();
|
||||||
|
|
||||||
foreach (array_merge($annotations, $classAnnotations[$declaringClass->getName()]) as $annotation) {
|
foreach (array_merge($annotations, $classAnnotations[$declaringClass->getName()]) as $annotation) {
|
||||||
$annotation->_context = $nestedContext;
|
|
||||||
|
|
||||||
if ($annotation instanceof Operation) {
|
if ($annotation instanceof Operation) {
|
||||||
foreach ($httpMethods as $httpMethod) {
|
foreach ($httpMethods as $httpMethod) {
|
||||||
$operation = Util::getOperation($path, $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));
|
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;
|
$implicitAnnotations[] = $annotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +160,9 @@ final class OpenApiPhpDescriber implements ModelRegistryAwareInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the Analyser after the parsing
|
||||||
|
Analyser::$context = null;
|
||||||
|
|
||||||
return $analysis;
|
return $analysis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\ModelDescriber\Annotations;
|
|||||||
use Doctrine\Common\Annotations\Reader;
|
use Doctrine\Common\Annotations\Reader;
|
||||||
use Nelmio\ApiDocBundle\Model\ModelRegistry;
|
use Nelmio\ApiDocBundle\Model\ModelRegistry;
|
||||||
use Nelmio\ApiDocBundle\OpenApiPhp\ModelRegister;
|
use Nelmio\ApiDocBundle\OpenApiPhp\ModelRegister;
|
||||||
|
use OpenApi\Analyser;
|
||||||
use OpenApi\Analysis;
|
use OpenApi\Analysis;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
use OpenApi\Context;
|
use OpenApi\Context;
|
||||||
@ -61,19 +62,20 @@ class OpenApiAnnotationsReader
|
|||||||
|
|
||||||
public function updateProperty(\ReflectionProperty $reflectionProperty, OA\Property $property, array $serializationGroups = null): void
|
public function updateProperty(\ReflectionProperty $reflectionProperty, OA\Property $property, array $serializationGroups = null): void
|
||||||
{
|
{
|
||||||
/** @var OA\Property $oaProperty */
|
// In order to have nicer errors
|
||||||
if (!$oaProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, OA\Property::class)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$declaringClass = $reflectionProperty->getDeclaringClass();
|
$declaringClass = $reflectionProperty->getDeclaringClass();
|
||||||
$context = new Context([
|
Analyser::$context = new Context([
|
||||||
'namespace' => $declaringClass->getNamespaceName(),
|
'namespace' => $declaringClass->getNamespaceName(),
|
||||||
'class' => $declaringClass->getShortName(),
|
'class' => $declaringClass->getShortName(),
|
||||||
'property' => $reflectionProperty->name,
|
'property' => $reflectionProperty->name,
|
||||||
'filename' => $declaringClass->getFileName(),
|
'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
|
// Read @Model annotations
|
||||||
$this->modelRegister->__invoke(new Analysis([$oaProperty]), $serializationGroups);
|
$this->modelRegister->__invoke(new Analysis([$oaProperty]), $serializationGroups);
|
||||||
|
@ -36,6 +36,8 @@ class ApiController
|
|||||||
* )
|
* )
|
||||||
* @OA\Parameter(ref="#/components/parameters/test")
|
* @OA\Parameter(ref="#/components/parameters/test")
|
||||||
* @Route("/article/{id}", methods={"GET"})
|
* @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()
|
public function fetchArticleAction()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user