1111
1212namespace Piwik \Plugins \OpenApiDocs \Annotations ;
1313
14+ use Matomo \Dependencies \OpenApiDocs \phpDocumentor \Reflection \DocBlock \Description ;
1415use Matomo \Dependencies \OpenApiDocs \phpDocumentor \Reflection \DocBlock \Tags \Param ;
1516use Matomo \Dependencies \OpenApiDocs \phpDocumentor \Reflection \DocBlock \Tags \TagWithType ;
1617use Matomo \Dependencies \OpenApiDocs \phpDocumentor \Reflection \DocBlockFactory ;
@@ -121,15 +122,15 @@ public function generatePluginApiAnnotations(string $pluginName, bool $writeToFi
121122 $ pluginMetadata = Proxy::getInstance ()->getMetadata ()[$ className ] ?? [];
122123
123124 $ annotations = [[sprintf ('@OA\Tag(name="%s") ' , $ pluginName )]];
124- // I decided to not include the description in the tag annotation so that it automatically pulls the API class comment as the description.
125- // if (!empty($pluginMetadata['__documentation'])) {
126- // $tagLines = $this->buildLinesForAnnotationObject('@OA\Tag', [
127- // sprintf('name="%s"', $pluginName),
128- // sprintf('description="%s"', $this->normaliseDescriptionText($pluginMetadata['__documentation'])),
129- // ]);
130- // $this->removeTrailingCommaFromLastLine($tagLines);
131- // $annotations[] = $tagLines;
132- // }
125+
126+ if (!empty ($ pluginMetadata ['__documentation ' ])) {
127+ $ tagLines = $ this ->buildLinesForAnnotationObject ('@OA\Tag ' , [
128+ sprintf ('name="%s" ' , $ pluginName ),
129+ sprintf ('description="%s" ' , $ this ->normaliseDescriptionText ($ pluginMetadata ['__documentation ' ])),
130+ ]);
131+ $ this ->removeTrailingCommaFromLastLine ($ tagLines );
132+ $ annotations [] = $ tagLines ;
133+ }
133134
134135 foreach (array_keys ($ pluginMetadata ) as $ metadataMethod ) {
135136 if (!$ reflectionClass ->hasMethod ($ metadataMethod )) {
@@ -254,11 +255,12 @@ protected function buildAnnotationForMethod(array $rules, string $pluginName, \R
254255
255256 $ params = $ this ->determineParameters ($ rules , $ pluginName , $ methodName , $ reflectionMethod );
256257 $ responses = $ this ->determineResponses ($ rules , $ pluginName , $ methodName , $ reflectionMethod , $ params );
258+ $ description = $ this ->determineDescription ($ pluginName , $ methodName , $ reflectionMethod );
257259
258260 $ isPost = !empty ($ rules ['plugins ' ][$ pluginName ]['methodsRequiringPost ' ])
259261 && in_array ($ methodName , $ rules ['plugins ' ][$ pluginName ]['methodsRequiringPost ' ]);
260262
261- return $ this ->compileOperationLines ($ path , $ opId , $ pluginName , $ params , $ responses , $ isPost );
263+ return $ this ->compileOperationLines ($ path , $ opId , $ pluginName , $ params , $ responses , $ description , $ isPost );
262264 }
263265
264266 /**
@@ -354,6 +356,24 @@ public function getResponseInfoFromDocBlock(string $docBlock): array
354356 }
355357
356358 /**
359+ * Extract the description/summary from a given docblock
360+ *
361+ * @param string $docBlock The comment block from a method, which hopefully contains a description.
362+ *
363+ * @return string Description/summary extracted from the docblock
364+ */
365+ public function getDescriptionFromDocBlock (string $ docBlock ): string
366+ {
367+ $ factory = DocBlockFactory::createInstance ();
368+ $ docBlockObject = $ factory ->create ($ docBlock );
369+
370+ return $ docBlockObject ->getSummary ();
371+ }
372+
373+
374+
375+
376+ /**
357377 * This is a helper method for building the path used for an operation annotation. It takes a path template, like
358378 * the one from the config array and populates it with the plugin name and API method name.
359379 *
@@ -449,12 +469,17 @@ public function buildParameterAnnotationData(string $methodName, string $paramNa
449469 // Clean up the descriptions a little more like removing linebreaks and escaping double-quotes
450470 $ description = $ this ->normaliseDescriptionText ($ description );
451471
472+ $ default = $ paramMetadata ['default ' ] ?? null ;
473+ if (!is_string ($ default )) {
474+ $ default = json_encode ($ default );
475+ }
476+
452477 return [
453478 'name ' => $ paramName ,
454479 'types ' => $ typesMap ,
455480 'description ' => $ description ,
456481 'required ' => $ isRequired ? 'true ' : 'false ' ,
457- 'default ' => !$ isRequired ? json_encode ( $ paramMetadata [ ' default ' ]) : NoDefaultValue::class,
482+ 'default ' => !$ isRequired ? $ default : NoDefaultValue::class,
458483 'example ' => $ example ,
459484 ];
460485 }
@@ -578,6 +603,30 @@ protected function determineParameters(array $rules, string $plugin, string $met
578603 ];
579604 }
580605
606+
607+
608+
609+ /**
610+ * Get the description/summary of a given method
611+ *
612+ * @param string $plugin Name of the plugin. E.g. TagManager.
613+ * @param string $method The name of the method being annotated.
614+ * @param \ReflectionMethod $reflectionMethod The reflective representation of the method to provide metadata.
615+ *
616+ * @return string Description of the method
617+ */
618+ protected function determineDescription (string $ plugin , string $ method , \ReflectionMethod $ reflectionMethod ): string
619+ {
620+ $ description = '' ;
621+ $ docBlock = $ reflectionMethod ->getDocComment ();
622+ if (!empty ($ docBlock )) {
623+ $ description = $ this ->getDescriptionFromDocBlock ($ docBlock );
624+ }
625+
626+ return $ description ;
627+ }
628+
629+
581630 /**
582631 * Map the PHP type to the OpenAPI type. The currently available types for v3.1.1 are the following: “null”,
583632 * “boolean”, “object”, “array”, “number”, “string”, or “integer”.
@@ -614,6 +663,9 @@ public function getOpenApiTypeFromPhpType(string $type): string
614663 case 'double ' :
615664 $ type = 'number ' ;
616665 break ;
666+ case 'void ' :
667+ $ type = 'null ' ;
668+ break ;
617669 default :
618670 $ type = 'string ' ;
619671 }
@@ -1037,8 +1089,13 @@ protected function determineResponses(array $rules, string $plugin, string $meth
10371089 $ successArray ['ref ' ] = '#/components/responses/GenericSuccess ' ;
10381090 }
10391091
1092+ $ description = $ responseInfo ['description ' ] ?? null ;
1093+ if ($ description instanceof Description) {
1094+ $ description = $ description ->getBodyTemplate ();
1095+ }
1096+
10401097 // If it's a generic type and there's no custom description, use one of the global generic responses
1041- if (empty ($ successArray ['ref ' ]) && !empty ($ responseInfo ['type ' ]) && empty ($ responseInfo [ ' description ' ] )) {
1098+ if (empty ($ successArray ['ref ' ]) && !empty ($ responseInfo ['type ' ]) && empty ($ description )) {
10421099 $ ref = '' ;
10431100 switch ($ responseInfo ['type ' ]) {
10441101 case 'array ' :
@@ -1053,6 +1110,8 @@ protected function determineResponses(array $rules, string $plugin, string $meth
10531110 case 'string ' :
10541111 $ ref = '#/components/responses/GenericString ' ;
10551112 break ;
1113+ case 'null ' :
1114+ $ ref = '#/components/responses/GenericSuccess ' ;
10561115 }
10571116
10581117 if (!empty ($ ref )) {
@@ -1713,16 +1772,18 @@ public function buildSchemaObjectArrays(array $typesMap, string $default = '', s
17131772 * @param string $plugin The name of the plugin. E.g. CustomReports
17141773 * @param array $params The compiled list of method parameters and key information about them, like type.
17151774 * @param array $responses compiled list of method expected responses and key information about them, like type.
1775+ * @param string $description The method level description
17161776 * @param bool $isPost Indicates whether the operation is a POST. The default is false, meaning it's GET.
17171777 *
17181778 * @return string[] The array of all the lines of the operation annotation object.
17191779 */
1720- public function compileOperationLines (string $ path , string $ opId , string $ plugin , array $ params , array $ responses , bool $ isPost = false ): array
1780+ public function compileOperationLines (string $ path , string $ opId , string $ plugin , array $ params , array $ responses , string $ description , bool $ isPost = false ): array
17211781 {
17221782 $ operationValuesMap = [
17231783 'path=" ' . $ path . '" ' ,
17241784 'operationId=" ' . $ opId . '" ' ,
17251785 'tags={" ' . $ plugin . '"} ' ,
1786+ 'description=" ' . $ this ->normaliseDescriptionText ($ description ) . '" ' ,
17261787 ];
17271788 foreach ($ params ['refs ' ] ?? [] as $ ref ) {
17281789 $ operationValuesMap [] = '@OA\Parameter(ref=" ' . $ ref . '") ' ;
0 commit comments