Skip to content

Commit

Permalink
parameters are now correctly located in path, query, or body
Browse files Browse the repository at this point in the history
  • Loading branch information
eceltov committed Oct 8, 2024
1 parent 174abc3 commit c4c88db
Showing 1 changed file with 58 additions and 31 deletions.
89 changes: 58 additions & 31 deletions app/commands/SwaggerAnnotator.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$route = $this->extractRoute($route);

$className = $namespacePrefix . $metadata['class'];
$annotationData = AnnotationHelper::extractAnnotationData($className, $metadata['method']);
$annotationData = AnnotationHelper::extractAnnotationData($className, $metadata['method'], $route);

$fileBuilder->addAnnotatedMethod($metadata['method'], $annotationData->toSwaggerAnnotations($route));
}
Expand Down Expand Up @@ -179,17 +179,18 @@ enum HttpMethods: string {
class AnnotationData {
public HttpMethods $httpMethod;

# $queryParams contain path and query params. This is because they are extracted from
# annotations directly, and the annotations do not contain this information.
public array $pathParams;
public array $queryParams;
public array $bodyParams;

public function __construct(
HttpMethods $httpMethod,
array $pathParams,
array $queryParams,
array $bodyParams
) {
$this->httpMethod = $httpMethod;
$this->pathParams = $pathParams;
$this->queryParams = $queryParams;
$this->bodyParams = $bodyParams;
}
Expand All @@ -200,12 +201,6 @@ private function getHttpMethodAnnotation(): string {
return "@OA\\" . $httpMethodString;
}

private function getRoutePathParamNames(string $route): array {
# sample: from '/users/{id}/{name}' generates ['id', 'name']
preg_match_all('/\{([A-Za-z0-9 ]+?)\}/', $route, $out);
return $out[1];
}

private function getBodyAnnotation(): string|null {
if (count($this->bodyParams) === 0) {
return null;
Expand All @@ -227,14 +222,11 @@ public function toSwaggerAnnotations(string $route) {
$body = new ParenthesesBuilder();
$body->addKeyValue("path", $route);

$pathParamNames = $this->getRoutePathParamNames($route);
foreach ($this->pathParams as $pathParam) {
$body->addValue($pathParam->toParameterAnnotation());
}
foreach ($this->queryParams as $queryParam) {
# find out where the parameter is located
$location = 'query';
if (in_array($queryParam->name, $pathParamNames))
$location = 'path';

$body->addValue($queryParam->toParameterAnnotation($location));
$body->addValue($queryParam->toParameterAnnotation());
}

$jsonProperties = $this->getBodyAnnotation();
Expand Down Expand Up @@ -281,6 +273,7 @@ class AnnotationParameterData {
public string|null $dataType;
public string $name;
public string|null $description;
public string $location;

private static $nullableSuffix = '|null';
private static $typeMap = [
Expand Down Expand Up @@ -310,11 +303,13 @@ class AnnotationParameterData {
public function __construct(
string|null $dataType,
string $name,
string|null $description
string|null $description,
string $location
) {
$this->dataType = $dataType;
$this->name = $name;
$this->description = $description;
$this->location = $location;
}

private function isDatatypeNullable(): bool {
Expand Down Expand Up @@ -360,12 +355,12 @@ private function generateSchemaAnnotation(): string {
* Converts the object to a @OA\Parameter(...) annotation string
* @param string $parameterLocation Where the parameter resides. Can be 'path', 'query', 'header' or 'cookie'.
*/
public function toParameterAnnotation(string $parameterLocation): string {
public function toParameterAnnotation(): string {

Check failure on line 358 in app/commands/SwaggerAnnotator.php

View workflow job for this annotation

GitHub Actions / phpstan (8.2)

PHPDoc tag @param references unknown parameter: $parameterLocation

Check failure on line 358 in app/commands/SwaggerAnnotator.php

View workflow job for this annotation

GitHub Actions / phpstan (8.3)

PHPDoc tag @param references unknown parameter: $parameterLocation
$head = "@OA\\Parameter";
$body = new ParenthesesBuilder();

$body->addKeyValue("name", $this->name);
$body->addKeyValue("in", $parameterLocation);
$body->addKeyValue("in", $this->location);
$body->addKeyValue("required", !$this->isDatatypeNullable());
if ($this->description !== null)
$body->addKeyValue("description", $this->description);
Expand Down Expand Up @@ -410,8 +405,10 @@ private static function extractAnnotationHttpMethod(array $annotations): HttpMet
return null;
}

private static function extractAnnotationQueryParams(array $annotations): array {
$queryParams = [];
private static function extractStandardAnnotationParams(array $annotations, string $route): array {
$routeParams = self::getRoutePathParamNames($route);

$params = [];
foreach ($annotations as $annotation) {
# assumed that all query parameters have a @param annotation
if (str_starts_with($annotation, "@param")) {
Expand All @@ -421,16 +418,22 @@ private static function extractAnnotationQueryParams(array $annotations): array
# assumed that all names start with $
$name = substr($tokens[2], 1);
$description = implode(" ", array_slice($tokens,3));
$descriptor = new AnnotationParameterData($type, $name, $description);
$queryParams[] = $descriptor;

# figure out where the parameter is located
$location = 'query';
if (in_array($name, $routeParams))
$location = 'path';

$descriptor = new AnnotationParameterData($type, $name, $description, $location);
$params[] = $descriptor;
}
}
return $queryParams;
return $params;
}

private static function extractBodyParams(array $expressions): array {
$dict = [];
#sample: [ name="uiData", validation="array|null" ]
#sample: [ 'name="uiData"', 'validation="array|null"' ]
foreach ($expressions as $expression) {
$tokens = explode('="', $expression);
$name = $tokens[0];
Expand All @@ -441,7 +444,7 @@ private static function extractBodyParams(array $expressions): array {
return $dict;
}

private static function extractAnnotationBodyParams(array $annotations): array {
private static function extractNetteAnnotationParams(array $annotations): array {
$bodyParams = [];
$prefix = "@Param";
foreach ($annotations as $annotation) {
Expand All @@ -453,7 +456,7 @@ private static function extractAnnotationBodyParams(array $annotations): array {
$tokens = explode(", ", $body);
$values = self::extractBodyParams($tokens);
$descriptor = new AnnotationParameterData($values["validation"],
$values["name"], $values["description"]);
$values["name"], $values["description"], $values["type"]);
$bodyParams[] = $descriptor;
}
}
Expand Down Expand Up @@ -496,13 +499,37 @@ private static function getMethodAnnotations(string $className, string $methodNa
return $merged;
}

public static function extractAnnotationData(string $className, string $methodName): AnnotationData {
private static function getRoutePathParamNames(string $route): array {
# sample: from '/users/{id}/{name}' generates ['id', 'name']
preg_match_all('/\{([A-Za-z0-9 ]+?)\}/', $route, $out);
return $out[1];
}

public static function extractAnnotationData(string $className, string $methodName, string $route): AnnotationData {
$methodAnnotations = self::getMethodAnnotations($className, $methodName);

$httpMethod = self::extractAnnotationHttpMethod($methodAnnotations);
$queryParams = self::extractAnnotationQueryParams($methodAnnotations);
$bodyParams = self::extractAnnotationBodyParams($methodAnnotations);
$data = new AnnotationData($httpMethod, $queryParams, $bodyParams);
$standardAnnotationParams = self::extractStandardAnnotationParams($methodAnnotations, $route);
$netteAnnotationParams = self::extractNetteAnnotationParams($methodAnnotations);
$params = array_merge($standardAnnotationParams, $netteAnnotationParams);

$pathParams = [];
$queryParams = [];
$bodyParams = [];

foreach ($params as $param) {
if ($param->location === 'path')
$pathParams[] = $param;
else if ($param->location === 'query')
$queryParams[] = $param;
else if ($param->location === 'post')
$bodyParams[] = $param;
else
throw new \Exception("Error in extractAnnotationData: Unknown param location: {$param->location}");
}


$data = new AnnotationData($httpMethod, $pathParams, $queryParams, $bodyParams);
return $data;
}
}

0 comments on commit c4c88db

Please sign in to comment.