2323use PHPStan \PhpDocParser \Parser \TypeParser ;
2424use PHPStan \PhpDocParser \Parser \ConstExprParser ;
2525use PHPStan \PhpDocParser \Parser \TokenIterator ;
26+ use function _PHPStan_3d4486d07 \RingCentral \Psr7 \str ;
2627
2728class AnnotationGenerator
2829{
@@ -42,19 +43,20 @@ public function __construct(DocumentationGenerator $generator)
4243 * - Uses config.php to set default values.
4344 * - Uses config.php from plugin to override default configs.
4445 */
45- public function generatePluginApiAnnotations (string $ pluginName )
46+ public function generatePluginApiAnnotations (string $ pluginName, bool $ writeToFile = false )
4647 {
4748 BaseValidator::check ('plugin ' , $ pluginName , [ new NotEmpty () ]);
4849 Manager::getInstance ()->checkIsPluginActivated ($ pluginName );
4950
5051 $ currentPluginDir = Manager::getInstance ()::getPluginDirectory ('OpenApiDocs ' );
5152 $ rules = require $ currentPluginDir . '/Annotations/config.php ' ;
5253 $ pluginDir = Manager::getInstance ()::getPluginDirectory ($ pluginName );
53- $ pluginConfigPath = $ pluginDir . '/OpenApi/Annotations/config.php ' ;
54- if (is_file ($ pluginConfigPath )) {
55- $ pluginRules = require $ pluginDir . '/OpenApi/Annotations/config.php ' ;
54+ $ pluginAnnotationDir = $ pluginDir . '/OpenApi/Annotations ' ;
55+ $ pluginAnnotationPath = $ pluginAnnotationDir . '/GeneratedAnnotations.php ' ;
56+ // If the directory doesn't exist yet, create it
57+ if ($ writeToFile && !is_dir ($ pluginAnnotationDir )) {
58+ mkdir ($ pluginAnnotationDir , 0777 , true );
5659 }
57- $ rules ['plugins ' ] = [ $ pluginName => $ pluginRules ?? [] ];
5860
5961 $ className = Request::getClassNameAPI ($ pluginName );
6062
@@ -81,13 +83,42 @@ public function generatePluginApiAnnotations(string $pluginName)
8183 $ annotations [] = $ methodAnnotations ;
8284 }
8385
84- if (empty ( $ annotations ) ) {
85- return false ;
86+ if ($ writeToFile ) {
87+ $ this -> writeAnnotationsToFile ( $ annotations , $ pluginAnnotationPath , $ pluginName ) ;
8688 }
8789
8890 return $ annotations ;
8991 }
9092
93+ protected function writeAnnotationsToFile (array $ annotations , string $ filePath , string $ pluginName ): void
94+ {
95+ $ output = '' ;
96+ $ lines = [
97+ '<?php ' ,
98+ '' ,
99+ 'namespace Piwik \\Plugins \\' . $ pluginName . '\\OpenApi \\Annotations; ' ,
100+ '' ,
101+ '/** ' ,
102+ ];
103+
104+ foreach ($ annotations as $ annotation ) {
105+ foreach ($ annotation as $ line ) {
106+ $ lines [] = ' * ' . $ line ;
107+ }
108+ }
109+
110+ $ lines = array_merge ($ lines , [
111+ ' */ ' ,
112+ 'class GeneratedAnnotations ' ,
113+ '{ ' ,
114+ '' ,
115+ '} ' ,
116+ ]);
117+
118+ // Create or overwrite the annotations file
119+ file_put_contents ($ filePath , implode (PHP_EOL , $ lines ));
120+ }
121+
91122 protected function buildAnnotationForMethod (array $ rules , string $ pluginName , \ReflectionMethod $ reflectionMethod ): array
92123 {
93124 $ existing = $ reflectionMethod ->getDocComment ();
@@ -270,6 +301,11 @@ protected function getApplicableDemoExampleUrls(string $pluginName, string $meth
270301
271302 protected function getExampleIfAvailable (string $ url ): array
272303 {
304+ // Simply return the URL for TSV
305+ if (stripos ($ url , 'format=tsv ' ) !== false ) {
306+ return ['externalValue ' => $ url ];
307+ }
308+
273309 $ ch = curl_init ($ url );
274310
275311 curl_setopt_array ($ ch , [
@@ -284,11 +320,22 @@ protected function getExampleIfAvailable(string $url): array
284320 curl_close ($ ch );
285321
286322 // If the example didn't load or is too big, simply include the URL instead of the string value
287- if ($ body === false || $ status !== 200 || strlen ($ body ) > 1000 ) {
323+ if ($ body === false || $ status !== 200 || strlen ($ body ) > 1000 || strpos ( $ body , ' Error: ' ) === 0 ) {
288324 return ['externalValue ' => $ url ];
289325 }
290326
291- return ['value ' => trim ($ body )];
327+ // Clean up XML formatting a bit
328+ $ body = trim ($ body );
329+ if (stripos ($ url , 'format=xml ' ) !== false ) {
330+ $ body = str_replace (['<?xml version="1.0" encoding="utf-8" ?> ' , "\n" , "\t" , '" ' ], ['' , '' , '' , '\" ' ], $ body );
331+ }
332+
333+ // The annotation expects an objects and not arrays
334+ if (stripos ($ url , 'format=json ' ) !== false && stripos ($ body , '[ ' ) === 0 ) {
335+ $ body = str_replace (['[ ' , '] ' ], ['{ ' , '} ' ], $ body );
336+ }
337+
338+ return ['value ' => $ body ];
292339 }
293340
294341 protected function determineResponses (array $ rules , string $ plugin , string $ method ): array
@@ -317,7 +364,13 @@ protected function determineResponses(array $rules, string $plugin, string $meth
317364 'summary="Example ' . $ type . '" ' ,
318365 ];
319366 $ exampleValue = $ this ->getExampleIfAvailable ($ url );
320- $ exampleProperties [] = array_key_first ($ exampleValue ) . '=" ' . array_pop ($ exampleValue ) . '" ' ;
367+ $ valueKey = array_key_first ($ exampleValue );
368+ $ value = '" ' . array_pop ($ exampleValue ) . '" ' ;
369+ // Remove the surrounding quotes for JSON values
370+ if ($ valueKey === 'value ' && $ type === 'json ' ) {
371+ $ value = substr ($ value , 1 , -1 );
372+ }
373+ $ exampleProperties [] = $ valueKey . '= ' . $ value ;
321374 $ mediaTypes [] = [
322375 'mediaType=" ' . $ contentType . '" ' ,
323376 '@OA\Examples ' => $ exampleProperties ,
@@ -391,6 +444,9 @@ protected function buildSchemaObjectArray(string $type, string $subType = '', st
391444 }
392445 if ($ type === 'array ' ) {
393446 $ schemaMap [] = '@OA\Items( ' . $ subTypeString . ') ' ;
447+ if ($ default === '[] ' ) {
448+ $ default = '{} ' ;
449+ }
394450 }
395451
396452 if ($ default !== '' ) {
0 commit comments