Skip to content

Commit 8a8a1d1

Browse files
authored
Updated OpenApiDocs to use Cloud shared storage if available, #PG-4593 (#27)
* Moved API documentation from hard coded paths to a resolver service, if on Cloud, it will use CloudDistributedCachePath, else, it will use /tmp in the plugin * simplified code now, using generic file writing service * Adding better tests for path resolving * Added cloud pr suggestion, check if path exists and is writable * fix tests
1 parent 6ae5e76 commit 8a8a1d1

12 files changed

Lines changed: 438 additions & 30 deletions

API.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Piwik\Piwik;
1313
use Piwik\Plugin\Manager;
1414
use Piwik\Plugins\OpenApiDocs\Specs\SpecGenerator;
15+
use Piwik\Plugins\OpenApiDocs\Specs\PathResolver;
1516

1617
/**
1718
* API for plugin OpenApiDocs
@@ -67,9 +68,7 @@ public function getOpenApiSpec(string $pluginName, string $format = 'json'): arr
6768

6869
protected function getSpecFilePath(string $pluginName): string
6970
{
70-
$currentPluginDir = Manager::getInstance()::getPluginDirectory('OpenApiDocs');
71-
72-
return $currentPluginDir . OpenApiDocs::GENERATED_SPECS_PATH . $pluginName . '_openapi_spec_v' . OpenApiDocs::DEFAULT_SPEC_VERSION . '.json';
71+
return $this->getSpecPathResolver()->getSpecFilePath($pluginName);
7372
}
7473

7574
protected function isSpecFileReadable(string $filePath): bool
@@ -98,6 +97,11 @@ protected function validateJsonFormat(string $format): void
9897
}
9998
}
10099

100+
protected function getSpecPathResolver(): PathResolver
101+
{
102+
return new PathResolver();
103+
}
104+
101105
/**
102106
* Get the generated API documentation data for the specified plugin.
103107
*

Annotations/AnnotationGenerator.php

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
use Piwik\Http;
2424
use Piwik\Piwik;
2525
use Piwik\Plugin\Manager;
26+
use Piwik\Plugins\OpenApiDocs\Artifact\ArtifactWriter;
2627
use Piwik\Plugins\OpenApiDocs\OpenApiDocs;
28+
use Piwik\Plugins\OpenApiDocs\Specs\PathResolver;
2729
use Piwik\SettingsPiwik;
2830
use Piwik\Url;
2931
use Piwik\UrlHelper;
@@ -72,6 +74,16 @@ class AnnotationGenerator
7274
*/
7375
protected $generator;
7476

77+
/**
78+
* @var PathResolver
79+
*/
80+
protected $pathResolver;
81+
82+
/**
83+
* @var ArtifactWriter
84+
*/
85+
protected $artifactWriter;
86+
7587
/**
7688
* @var array[]
7789
*/
@@ -82,9 +94,14 @@ class AnnotationGenerator
8294
*/
8395
protected $missingImportantDataWarnings;
8496

85-
public function __construct(DocumentationGenerator $generator)
86-
{
97+
public function __construct(
98+
DocumentationGenerator $generator,
99+
?PathResolver $pathResolver = null,
100+
?ArtifactWriter $artifactWriter = null
101+
) {
87102
$this->generator = $generator;
103+
$this->pathResolver = $pathResolver ?? new PathResolver();
104+
$this->artifactWriter = $artifactWriter ?? new ArtifactWriter();
88105
$this->missingImportantDataWarnings = [];
89106
$this->currentPluginDir = Manager::getInstance()::getPluginDirectory('OpenApiDocs');
90107
}
@@ -115,8 +132,7 @@ public function generatePluginApiAnnotations(string $pluginName, bool $writeToFi
115132
}
116133

117134
$rules = require $this->currentPluginDir . '/Annotations/config.php';
118-
$pluginAnnotationDir = $this->currentPluginDir . OpenApiDocs::GENERATED_ANNOTATIONS_PATH;
119-
$pluginAnnotationPath = $pluginAnnotationDir . "/{$pluginName}GeneratedAnnotations.php";
135+
$pluginAnnotationPath = $this->pathResolver->getAnnotationFilePath($pluginName);
120136

121137
$className = Request::getClassNameAPI($pluginName);
122138

@@ -231,8 +247,7 @@ public function getContentForGeneratedAnnotationsFile(array $annotations, string
231247
*/
232248
protected function writeAnnotationsToFile(array $annotations, string $filePath, string $pluginName)
233249
{
234-
// Create or overwrite the annotations file
235-
return file_put_contents($filePath, $this->getContentForGeneratedAnnotationsFile($annotations, $pluginName));
250+
return $this->writeFile($filePath, $this->getContentForGeneratedAnnotationsFile($annotations, $pluginName));
236251
}
237252

238253
/**
@@ -903,11 +918,11 @@ protected function getExampleIfAvailable(string $url, bool $useLocalToken = fals
903918
}
904919
$method = $queryParams['method'];
905920
$format = strtolower($queryParams['format']);
906-
$exampleFilePath = $this->currentPluginDir . OpenApiDocs::EXAMPLE_RESPONSES_PATH . $method . '.' . $format;
921+
[$pluginName, $methodName] = explode('.', $method);
922+
$exampleFilePath = $this->pathResolver->getExampleResponseFilePath($pluginName, $methodName, $format);
907923
// If there's already a file, use that instead of making a new server call. Ignore the file when the flag is set.
908924
if (!$ignoreCached) {
909925
// If an example file is found, return its contents instead of making the server call.
910-
[$pluginName, $methodName] = explode('.', $method);
911926
$exampleContents = $this->getCachedExampleResponseFile($pluginName, $methodName, $format);
912927
if (!empty($exampleContents)) {
913928
return $exampleContents;
@@ -962,7 +977,7 @@ protected function getExampleIfAvailable(string $url, bool $useLocalToken = fals
962977
$body = $response['data'];
963978

964979
// Write the example response to file as a cache and reference.
965-
file_put_contents($exampleFilePath, $body);
980+
$this->writeFile($exampleFilePath, $body);
966981

967982
// Convert the XML responses into a JSON object and then encode it into a string. This is helpful for building schemas.
968983
if ($format === 'xml') {
@@ -994,7 +1009,7 @@ protected function getExampleIfAvailable(string $url, bool $useLocalToken = fals
9941009
*/
9951010
protected function getCachedExampleResponseFile(string $pluginName, string $methodName, string $format, bool $rawResult = false, bool $applyMaxLength = true): string
9961011
{
997-
$exampleFilePath = $this->currentPluginDir . OpenApiDocs::EXAMPLE_RESPONSES_PATH . $pluginName . '.' . $methodName . '.' . $format;
1012+
$exampleFilePath = $this->pathResolver->getExampleResponseFilePath($pluginName, $methodName, $format);
9981013
// Simply return an empty string if the file doesn't exist yet.
9991014
if (!file_exists($exampleFilePath)) {
10001015
return '';
@@ -1021,6 +1036,11 @@ protected function getCachedExampleResponseFile(string $pluginName, string $meth
10211036
return $exampleContents;
10221037
}
10231038

1039+
protected function writeFile(string $filePath, string $contents)
1040+
{
1041+
return $this->artifactWriter->writeFile($filePath, $contents);
1042+
}
1043+
10241044
/**
10251045
* Try to build an example URL for a specific API method using report metadata. This queries the demo server for
10261046
* report metadata to get examples of existing reports which can be used as example URLS. If no metadata matches the

Annotations/ApiMethodInfoExtractor.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,29 @@
1515
use Piwik\API\Proxy;
1616
use Piwik\API\Request;
1717
use Piwik\Plugin\Manager;
18-
use Piwik\Plugins\OpenApiDocs\OpenApiDocs;
18+
use Piwik\Plugins\OpenApiDocs\Artifact\ArtifactWriter;
19+
use Piwik\Plugins\OpenApiDocs\Specs\PathResolver;
1920
use Piwik\Validators\BaseValidator;
2021
use Piwik\Validators\NotEmpty;
2122

2223
class ApiMethodInfoExtractor
2324
{
25+
/**
26+
* @var PathResolver
27+
*/
28+
private $pathResolver;
29+
30+
/**
31+
* @var ArtifactWriter
32+
*/
33+
private $artifactWriter;
34+
35+
public function __construct(?PathResolver $pathResolver = null, ?ArtifactWriter $artifactWriter = null)
36+
{
37+
$this->pathResolver = $pathResolver ?? new PathResolver();
38+
$this->artifactWriter = $artifactWriter ?? new ArtifactWriter();
39+
}
40+
2441
/**
2542
* Look up the Matomo Reporting API methods for the specified plugin(s) and output the basic information for each.
2643
* This includes the comment block, parameter information, and things like that. This can then be fed to a secure
@@ -38,8 +55,6 @@ public function extractMethodInfo(string $pluginName, bool $writeToFile = false)
3855
$pluginNames = explode(',', $pluginName);
3956

4057
BaseValidator::check('pluginNames', $pluginNames, [new NotEmpty()]);
41-
$currentPluginDir = Manager::getInstance()::getPluginDirectory('OpenApiDocs');
42-
4358
$methodInfoArray = [];
4459
foreach ($pluginNames as $plugin) {
4560
BaseValidator::check('pluginName', $plugin, [new NotEmpty()]);
@@ -63,8 +78,8 @@ public function extractMethodInfo(string $pluginName, bool $writeToFile = false)
6378
}
6479

6580
if ($writeToFile) {
66-
$pluginSpecPath = $currentPluginDir . OpenApiDocs::GENERATED_ANNOTATIONS_PATH . $fileBaseName . '_api_method_info.json';
67-
file_put_contents($pluginSpecPath, $methodInfoString);
81+
$pluginSpecPath = $this->pathResolver->getApiMethodInfoFilePath($fileBaseName);
82+
$this->artifactWriter->writeFile($pluginSpecPath, $methodInfoString);
6883
}
6984

7085
return $methodInfoString;

Artifact/ArtifactWriter.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/**
4+
* Matomo - free/libre analytics platform
5+
*
6+
* @link https://matomo.org
7+
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace Piwik\Plugins\OpenApiDocs\Artifact;
13+
14+
use Piwik\Filesystem;
15+
16+
class ArtifactWriter
17+
{
18+
/**
19+
* @return false|int
20+
*/
21+
public function writeFile(string $filePath, string $contents)
22+
{
23+
Filesystem::mkdir(dirname($filePath));
24+
25+
return file_put_contents($filePath, $contents);
26+
}
27+
}

Commands/ExtractReportingApiMethodInfo.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Piwik\Plugins\OpenApiDocs\Commands;
1313

14+
use Piwik\Container\StaticContainer;
1415
use Piwik\Plugin\ConsoleCommand;
1516
use Piwik\Plugins\OpenApiDocs\Annotations\ApiMethodInfoExtractor;
17+
use Piwik\Plugins\OpenApiDocs\Specs\PathResolver;
1618

1719
/**
1820
* This class lets you define a new command. To read more about commands have a look at our Matomo Console guide on
@@ -86,7 +88,7 @@ protected function doExecute(): int
8688
$result = (new ApiMethodInfoExtractor())->extractMethodInfo($plugin, $notDryRun);
8789

8890
if ($notDryRun) {
89-
$output->writeln('<info>Results written to plugins/OpenApiDocs/tmp/annotations directory.</info>');
91+
$output->writeln('<info>Results written to ' . StaticContainer::get(PathResolver::class)->getAnnotationsDirectory() . '</info>');
9092

9193
return $result ? self::SUCCESS : self::FAILURE;
9294
}

Commands/GenerateAnnotations.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Piwik\Container\StaticContainer;
1313
use Piwik\Plugin\ConsoleCommand;
1414
use Piwik\Plugins\OpenApiDocs\Annotations\AnnotationGenerator;
15+
use Piwik\Plugins\OpenApiDocs\Specs\PathResolver;
1516

1617
/**
1718
* This class lets you define a new command. To read more about commands have a look at our Matomo Console guide on
@@ -83,7 +84,7 @@ protected function doExecute(): int
8384
$result = (StaticContainer::get(AnnotationGenerator::class))->generatePluginApiAnnotations($plugin, $notDryRun);
8485

8586
if ($notDryRun) {
86-
$output->writeln('<info>Results written to plugins/OpenApiDocs/tmp/annotations/ directory.</info>');
87+
$output->writeln('<info>Results written to ' . StaticContainer::get(PathResolver::class)->getAnnotationsDirectory() . '</info>');
8788

8889
return $result ? self::SUCCESS : self::FAILURE;
8990
}

Commands/GenerateSpecFile.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Piwik\Plugin\ConsoleCommand;
1414
use Piwik\Plugins\OpenApiDocs\Generation\SpecGenerationService;
1515
use Piwik\Plugins\OpenApiDocs\OpenApiDocs;
16+
use Piwik\Plugins\OpenApiDocs\Specs\PathResolver;
1617

1718
/**
1819
* This class lets you define a new command. To read more about commands have a look at our Matomo Console guide on
@@ -28,9 +29,15 @@ class GenerateSpecFile extends ConsoleCommand
2829
*/
2930
private $specGenerationService;
3031

31-
public function __construct(?SpecGenerationService $specGenerationService = null)
32+
/**
33+
* @var PathResolver
34+
*/
35+
private $specPathResolver;
36+
37+
public function __construct(?SpecGenerationService $specGenerationService = null, ?PathResolver $specPathResolver = null)
3238
{
3339
$this->specGenerationService = $specGenerationService ?: StaticContainer::get(SpecGenerationService::class);
40+
$this->specPathResolver = $specPathResolver ?: StaticContainer::get(PathResolver::class);
3441

3542
parent::__construct();
3643
}
@@ -116,12 +123,12 @@ protected function doExecute(): int
116123

117124
if ($addAnnotations) {
118125
foreach ($pluginNames as $pluginName) {
119-
$output->writeln('<info>Created Annotations for ' . $pluginName . ' and wrote results to plugins/OpenApiDocs/tmp/annotations.</info>');
126+
$output->writeln('<info>Created Annotations for ' . $pluginName . ' and wrote results to ' . $this->specPathResolver->getAnnotationsDirectory() . '</info>');
120127
}
121128
}
122129

123130
if ($notDryRun) {
124-
$output->writeln('<info>Results written to plugins/OpenApiDocs/tmp/specs/ directory.</info>');
131+
$output->writeln('<info>Results written to ' . $this->specPathResolver->getSpecDirectory() . '</info>');
125132
return self::SUCCESS;
126133
}
127134

0 commit comments

Comments
 (0)