diff --git a/src/Contract/Service/DocBlockParserInterface.php b/src/Contract/Service/DocBlockParserInterface.php index 0ab8ff6..2b4a879 100644 --- a/src/Contract/Service/DocBlockParserInterface.php +++ b/src/Contract/Service/DocBlockParserInterface.php @@ -11,7 +11,7 @@ interface DocBlockParserInterface /** * @return array */ - public function parseDocBlock(string $docBlock): array; + public function parseDocBlock(string $docBlock, ?string $parameterName = null): array; /** * @return string[] diff --git a/src/Model/Doc/Request/RequestDoc.php b/src/Model/Doc/Request/RequestDoc.php index ea64be5..1103576 100644 --- a/src/Model/Doc/Request/RequestDoc.php +++ b/src/Model/Doc/Request/RequestDoc.php @@ -8,7 +8,8 @@ class RequestDoc { - private ?ComponentSchemaDoc $componentSchemaDoc = null; + /** @var ComponentSchemaDoc[] */ + private array $componentSchemaDocs = []; /** @var ParameterDoc[] */ private array $parameters = []; @@ -16,14 +17,19 @@ class RequestDoc /** @var mixed[] */ private array $requestBody = []; - public function getComponentSchemaDoc(): ?ComponentSchemaDoc + /** + * @return ComponentSchemaDoc[] + */ + public function getComponentSchemaDocs(): array { - return $this->componentSchemaDoc; + return $this->componentSchemaDocs; } - public function setComponentSchemaDoc(?ComponentSchemaDoc $componentSchemaDoc): self + public function addComponentSchemaDoc(?ComponentSchemaDoc $componentSchemaDoc): self { - $this->componentSchemaDoc = $componentSchemaDoc; + if ($componentSchemaDoc !== null) { + $this->componentSchemaDocs[$componentSchemaDoc->getName()] = $componentSchemaDoc; + } return $this; } diff --git a/src/Service/ControllerMethodParser.php b/src/Service/ControllerMethodParser.php index 49a3380..368717e 100644 --- a/src/Service/ControllerMethodParser.php +++ b/src/Service/ControllerMethodParser.php @@ -10,6 +10,7 @@ use Symfony\Component\Routing\Annotation\Route as RouteAnnotation; use Symfony\Component\Routing\Attribute\Route as RouteAttribute; use Symfony\Component\Routing\RouterInterface; +use Valantic\PimcoreApiDocumentationBundle\Contract\Model\Component\Property\ComponentSchemaPropertyInterface; use Valantic\PimcoreApiDocumentationBundle\Contract\Service\ControllerMethodParserInterface; use Valantic\PimcoreApiDocumentationBundle\Contract\Service\DataTypeParserInterface; use Valantic\PimcoreApiDocumentationBundle\Contract\Service\SchemaGeneratorInterface; @@ -160,11 +161,11 @@ private function parseRequest(\ReflectionMethod $method): ?RequestDoc if (!is_subclass_of($requestClass, ApiRequestInterface::class)) { return null; } + $requestDoc = new RequestDoc(); foreach ($requestParameter->getAttributes() as $attribute) { if ($attribute->getName() === MapQueryString::class) { - // TODO: parse nested $requestReflection = new \ReflectionClass($requestClass); $requestProperties = $requestReflection->getProperties(\ReflectionProperty::IS_PUBLIC); @@ -174,6 +175,12 @@ private function parseRequest(\ReflectionMethod $method): ?RequestDoc $propertyDoc = $this->getDataTypeParser($property)->parse($property); + if ($propertyDoc instanceof ComponentSchemaPropertyInterface) { + foreach ($propertyDoc->getSchemas() as $schema) { + $requestDoc->addComponentSchemaDoc($schema); + } + } + $parameterDoc ->setName($property->getName()) ->setIn(ParameterDoc::IN_QUERY) @@ -187,7 +194,7 @@ private function parseRequest(\ReflectionMethod $method): ?RequestDoc } if (($attribute->getName() === MapRequestPayload::class) && is_subclass_of($requestClass, HasJsonPayload::class)) { - $requestDoc->setComponentSchemaDoc($this->schemaGenerator->generateForRequest($requestClass)); + $requestDoc->addComponentSchemaDoc($this->schemaGenerator->generateForRequest($requestClass)); $requestDoc->setRequestBody([ 'content' => [ 'application/json' => [ diff --git a/src/Service/DataTypeParser/ArrayParser.php b/src/Service/DataTypeParser/ArrayParser.php index e690c30..5627593 100644 --- a/src/Service/DataTypeParser/ArrayParser.php +++ b/src/Service/DataTypeParser/ArrayParser.php @@ -26,7 +26,6 @@ public function __construct( public function parse(\ReflectionProperty $reflectionProperty): AbstractPropertyDoc { $typeHints = $this->determineTypeHints($reflectionProperty); - $arrayItems = []; foreach ($typeHints as $typeHint) { @@ -79,9 +78,11 @@ private function determineTypeHints(\ReflectionProperty $reflectionProperty): ar $docBlocksTypeHints = []; $docBlock = null; + $parameterName = null; if ($reflectionProperty->getDocComment()) { $docBlock = $reflectionProperty->getDocComment(); + $parameterName = $propertyName; } elseif ( $declaringClassReflection->hasMethod('__construct') && $declaringClassReflection->getMethod('__construct')->getDocComment() !== false @@ -90,7 +91,7 @@ private function determineTypeHints(\ReflectionProperty $reflectionProperty): ar } if ($docBlock !== null) { - $docBlocksTypeHints = $this->docBlockParser->parseDocBlock($docBlock); + $docBlocksTypeHints = $this->docBlockParser->parseDocBlock($docBlock, $parameterName); } $typeHints = []; diff --git a/src/Service/DocBlockParser.php b/src/Service/DocBlockParser.php index a363695..0e31404 100644 --- a/src/Service/DocBlockParser.php +++ b/src/Service/DocBlockParser.php @@ -33,23 +33,25 @@ public function __construct() $this->phpDocParser = new PhpDocParser($typeParser, $constExprParser); } - public function parseDocBlock(string $docBlock): array + public function parseDocBlock(string $docBlock, ?string $parameterName = null): array { $docBlockData = []; $tokens = new TokenIterator($this->lexer->tokenize($docBlock)); $parsedDocBlock = $this->phpDocParser->parse($tokens); foreach ($parsedDocBlock->children as $docBlockItem) { + $docBlockParamName = $parameterName; + if ($docBlockItem->value instanceof ParamTagValueNode) { - $parameterName = ltrim($docBlockItem->value->parameterName, '$'); + $docBlockParamName = ltrim($docBlockItem->value->parameterName, '$'); } if ($docBlockItem->value instanceof VarTagValueNode) { - $parameterName = ltrim($docBlockItem->value->variableName, '$'); + $docBlockParamName = ltrim($docBlockItem->value->variableName, '$'); } - if (isset($parameterName)) { - $docBlockData[$parameterName] = $docBlockItem; + if (isset($docBlockParamName) && $docBlockParamName !== '') { + $docBlockData[$docBlockParamName] = $docBlockItem; } } diff --git a/src/Service/DocsGenerator.php b/src/Service/DocsGenerator.php index 9f0bb64..63c2d02 100644 --- a/src/Service/DocsGenerator.php +++ b/src/Service/DocsGenerator.php @@ -44,10 +44,7 @@ public function generate(string $docsPath): void foreach ($controllerDoc->getMethodsDocs() as $methodDoc) { $paths[$methodDoc->getRouteDoc()->getPath()][$methodDoc->getRouteDoc()->getMethod()] = $methodDoc; - if ($methodDoc->getRequestDoc()?->getComponentSchemaDoc() !== null) { - $requestSchema = $methodDoc->getRequestDoc()->getComponentSchemaDoc(); - $schemas[$requestSchema->getName()] = $requestSchema; - } + $schemas = array_merge($schemas, $methodDoc->getRequestDoc()?->getComponentSchemaDocs() ?: []); foreach ($methodDoc->getResponsesDoc() as $responseDoc) { $schemas = array_merge($schemas, $responseDoc->getComponentSchemas());