Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 21 additions & 26 deletions Annotations/AnnotationGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

namespace Piwik\Plugins\OpenApiDocs\Annotations;

use Matomo\Dependencies\OpenApiDocs\phpDocumentor\Reflection\DocBlock\Tags\Param;
use Matomo\Dependencies\OpenApiDocs\phpDocumentor\Reflection\DocBlock\Tags\TagWithType;
use Matomo\Dependencies\OpenApiDocs\phpDocumentor\Reflection\DocBlockFactory;
use Piwik\API\DocumentationGenerator;
use Piwik\API\NoDefaultValue;
use Piwik\API\Proxy;
Expand All @@ -24,11 +27,6 @@
use Piwik\UrlHelper;
use Piwik\Validators\BaseValidator;
use Piwik\Validators\NotEmpty;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;

class AnnotationGenerator
{
Expand Down Expand Up @@ -282,21 +280,21 @@ protected function buildAnnotationForMethod(array $rules, string $pluginName, \R
*/
public function getParamInfoFromDocBlock(string $docBlock): array
{
$lexer = new Lexer();
$tokens = $lexer->tokenize($docBlock);
$expressionParser = new ConstExprParser();
$parser = new PhpDocParser(new TypeParser($expressionParser), $expressionParser);
$node = $parser->parse(new TokenIterator($tokens));
$factory = DocBlockFactory::createInstance();
$docBlockObject = $factory->create($docBlock);

$params = [];
foreach ($node->getParamTagValues() as $param) {
$name = ltrim($param->parameterName, '$');
foreach ($docBlockObject->getTagsByName('param') as $param) {
if (!($param instanceof Param)) {
continue;
}
$name = ltrim($param->getVariableName(), '$');
$params[$name] = [
'type' => (string)$param->type,
'type' => (string) $param->getType(),
// Normalise the description. E.g. remove linebreaks and indentation
'description' => trim(preg_replace(['/^\h+/m', '/\R+/u',], ['', ' '], $param->description)),
'byRef' => $param->isReference,
'variadic' => $param->isVariadic,
'description' => trim(preg_replace(['/^\h+/m', '/\R+/u',], ['', ' '], (string) $param->getDescription())),
'byRef' => $param->isReference(),
'variadic' => $param->isVariadic(),
];
}
return $params;
Expand All @@ -313,27 +311,24 @@ public function getParamInfoFromDocBlock(string $docBlock): array
*/
public function getResponseInfoFromDocBlock(string $docBlock): array
{
$lexer = new Lexer();
$tokens = $lexer->tokenize($docBlock);
$expressionParser = new ConstExprParser();
$parser = new PhpDocParser(new TypeParser($expressionParser), $expressionParser);
$node = $parser->parse(new TokenIterator($tokens));
$factory = DocBlockFactory::createInstance();
$docBlockObject = $factory->create($docBlock);

$responseInfo = ['type' => null];
$returnTags = $node->getReturnTagValues();
if (empty($returnTags)) {
$returnTags = $docBlockObject->getTagsByName('return');
if (empty($returnTags) || !($returnTags[0] instanceof TagWithType)) {
return $responseInfo;
}

$returnTag = $returnTags[0];
$tagValue = strval($returnTag->type);
$tagValue = strval($returnTag->getType());
$responseInfo['type'] = $this->getOpenApiTypeFromPhpType($tagValue);
if ($responseInfo['type'] === 'string' && !empty($tagValue) && strtolower($tagValue) !== 'string') {
$responseInfo['type'] = '';
$responseInfo['description'] = 'Response of unknown type';
}
if (!empty($returnTag->description)) {
$responseInfo['description'] = $returnTag->description;
if (!empty($returnTag->getDescription())) {
$responseInfo['description'] = $returnTag->getDescription();
}

return $responseInfo;
Expand Down
5 changes: 0 additions & 5 deletions Commands/GenerateAnnotations.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ protected function doExecute(): int
$input = $this->getInput();
$output = $this->getOutput();

if (!class_exists('PHPStan\PhpDocParser\Parser\PhpDocParser')) {
$output->writeln("<error>This command requires phpstan/phpdoc-parser. It should be available while running Matomo in development mode.</error>");
return self::FAILURE;
}

$plugin = $input->getOption('plugin');
if (empty($plugin)) {
throw new \RuntimeException('Please specify a plugin name.');
Expand Down
4 changes: 4 additions & 0 deletions phpstan-bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php

// Include the scoped dependencies in the autoloader
require_once __DIR__ . '/vendor/autoload.php';
1 change: 1 addition & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ parameters:
- scoper.inc.php
- Specs/SpecGenerator.php
bootstrapFiles:
- phpstan-bootstrap.php
- ../../bootstrap-phpstan.php
universalObjectCratesClasses:
- Piwik\Config
Expand Down
4 changes: 3 additions & 1 deletion tests/Unit/AnnotationGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace Piwik\Plugins\OpenApiDocs\tests\Unit;

require_once PIWIK_INCLUDE_PATH . '/plugins/OpenApiDocs/vendor/autoload.php';
use PHPUnit\Framework\TestCase;
use Piwik\API\DocumentationGenerator;
use Piwik\API\NoDefaultValue;
Expand Down Expand Up @@ -153,7 +154,7 @@ class AnnotationGeneratorTest extends TestCase
* @param int[] $idDestinationSites Optional array of IDs identifying which site(s) the new custom report is to be
* assigned to. The default is [idSite] when nothing is provided.
*
* @return array
* @return array Some test description for the return annotation.
* @throws Exception
*/';

Expand Down Expand Up @@ -316,6 +317,7 @@ public function testGetResponseInfoFromDocBlock(): void
// TODO - Update to use resource file and/or dataprovider to test more than one comment block
$expected = [
'type' => 'array',
'description' => 'Some test description for the return annotation.',
];
$this->assertEquals($expected, $this->annotationGenerator->getResponseInfoFromDocBlock(self::EXAMPLE_API_METHOD_DOC_BLOCK1));
}
Expand Down