Skip to content

Commit 01f0705

Browse files
committed
improved code comments
1 parent 5398ab7 commit 01f0705

File tree

1 file changed

+57
-17
lines changed

1 file changed

+57
-17
lines changed

app/commands/SwaggerAnnotator.php

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
class SwaggerAnnotator extends Command
1919
{
2020
protected static $defaultName = 'swagger:annotate';
21+
private static $presenterNamespace = 'App\V1Module\Presenters\\';
22+
private static $autogeneratedAnnotationFilePath = 'app/V1Module/presenters/annotations.php';
2123

2224
protected function configure(): void
2325
{
@@ -28,26 +30,33 @@ protected function configure(): void
2830

2931
protected function execute(InputInterface $input, OutputInterface $output): int
3032
{
31-
$namespacePrefix = 'App\V1Module\Presenters\\';
33+
# create a temporary file containing transpiled annotations usable by the external library (Swagger-PHP)
34+
$fileBuilder = new FileBuilder(self::$autogeneratedAnnotationFilePath);
35+
$fileBuilder->startClass('__Autogenerated_Annotation_Controller__', '1.0', 'ReCodEx API');
3236

33-
$fileBuilder = new FileBuilder("app/V1Module/presenters/annotations.php");
34-
$fileBuilder->startClass("AnnotationController");
37+
# get all routes of the api
3538
$routes = $this->getRoutes();
36-
foreach ($routes as $route) {
37-
$metadata = $this->extractMetadata($route);
38-
$route = $this->extractRoute($route);
39+
foreach ($routes as $routeObj) {
40+
# extract class and method names of the endpoint
41+
$metadata = $this->extractMetadata($routeObj);
42+
$route = $this->extractRoute($routeObj);
43+
$className = self::$presenterNamespace . $metadata['class'];
3944

40-
$className = $namespacePrefix . $metadata['class'];
45+
# extract data from the existing annotations
4146
$annotationData = AnnotationHelper::extractAnnotationData($className, $metadata['method'], $route);
4247

48+
# add an empty method to the file with the transpiled annotations
4349
$fileBuilder->addAnnotatedMethod($metadata['method'], $annotationData->toSwaggerAnnotations($route));
4450
}
4551
$fileBuilder->endClass();
4652

47-
4853
return Command::SUCCESS;
4954
}
5055

56+
/**
57+
* Finds all route objects of the API
58+
* @return array Returns an array of all found route objects.
59+
*/
5160
function getRoutes(): array {
5261
$router = \App\V1Module\RouterFactory::createRouter();
5362

@@ -77,14 +86,23 @@ function getRoutes(): array {
7786
return $routes;
7887
}
7988

80-
private function extractRoute($routeObj) {
89+
/**
90+
* Extracts the route string from a route object. Replaces '<..>' in the route with '{...}'.
91+
* @param mixed $routeObj
92+
*/
93+
private function extractRoute($routeObj): string {
8194
$mask = self::getPropertyValue($routeObj, "mask");
8295

8396
# sample: replaces '/users/<id>' with '/users/{id}'
8497
$mask = str_replace(["<", ">"], ["{", "}"], $mask);
8598
return "/" . $mask;
8699
}
87100

101+
/**
102+
* Extracts the class and method names of the endpoint handler.
103+
* @param mixed $routeObj The route object representing the endpoint.
104+
* @return string[] Returns a dictionary [ "class" => ..., "method" => ...]
105+
*/
88106
private function extractMetadata($routeObj) {
89107
$metadata = self::getPropertyValue($routeObj, "metadata");
90108
$presenter = $metadata["presenter"]["value"];
@@ -100,6 +118,13 @@ private function extractMetadata($routeObj) {
100118
];
101119
}
102120

121+
/**
122+
* Helper function that can extract a property value from an arbitrary object where
123+
* the property can be private.
124+
* @param mixed $object The object to extract from.
125+
* @param string $propertyName The name of the property.
126+
* @return mixed Returns the value of the property.
127+
*/
103128
private static function getPropertyValue($object, string $propertyName): mixed
104129
{
105130
$class = new \ReflectionClass($object);
@@ -118,6 +143,9 @@ private static function getPropertyValue($object, string $propertyName): mixed
118143
}
119144
}
120145

146+
/**
147+
* Builder class that handles .php file creation.
148+
*/
121149
class FileBuilder {
122150
private $file;
123151
private $methodEntries;
@@ -132,16 +160,16 @@ public function __construct(
132160
private function initFile(string $filename) {
133161
$this->file = fopen($filename, "w");
134162
fwrite($this->file, "<?php\n");
163+
fwrite($this->file, "/// THIS FILE WAS AUTOGENERATED\n");
135164
fwrite($this->file, "namespace App\V1Module\Presenters;\n");
136165
fwrite($this->file, "use OpenApi\Annotations as OA;\n");
137166
}
138167

139-
///TODO: hardcoded info
140-
private function createInfoAnnotation() {
168+
private function createInfoAnnotation(string $version, string $title) {
141169
$head = "@OA\\Info";
142170
$body = new ParenthesesBuilder();
143-
$body->addKeyValue("version", "1.0");
144-
$body->addKeyValue("title", "ReCodEx API");
171+
$body->addKeyValue("version", $version);
172+
$body->addKeyValue("title", $title);
145173
return $head . $body->toString();
146174
}
147175

@@ -151,9 +179,8 @@ private function writeAnnotationLineWithComments(string $annotationLine) {
151179
fwrite($this->file, "*/\n");
152180
}
153181

154-
public function startClass(string $className) {
155-
///TODO: hardcoded
156-
$this->writeAnnotationLineWithComments($this->createInfoAnnotation());
182+
public function startClass(string $className, string $version, string $title) {
183+
$this->writeAnnotationLineWithComments($this->createInfoAnnotation($version, $title));
157184
fwrite($this->file, "class {$className} {\n");
158185
}
159186

@@ -217,6 +244,11 @@ private function getBodyAnnotation(): string|null {
217244
return $head . $body->toString() . "))";
218245
}
219246

247+
/**
248+
* Converts the extracted annotation data to a string parsable by the Swagger-PHP library.
249+
* @param string $route The route of the handler this set of data represents.
250+
* @return string Returns the transpiled annotations on a single line.
251+
*/
220252
public function toSwaggerAnnotations(string $route) {
221253
$httpMethodAnnotation = $this->getHttpMethodAnnotation();
222254
$body = new ParenthesesBuilder();
@@ -239,6 +271,9 @@ public function toSwaggerAnnotations(string $route) {
239271
}
240272
}
241273

274+
/**
275+
* Builder class that can create strings of the schema: '(key1="value1", key2="value2", standalone1, standalone2, ...)'
276+
*/
242277
class ParenthesesBuilder {
243278
private array $tokens;
244279

@@ -269,6 +304,9 @@ public function toString(): string {
269304
}
270305
}
271306

307+
/**
308+
* Contains data of a single annotation parameter.
309+
*/
272310
class AnnotationParameterData {
273311
public string|null $dataType;
274312
public string $name;
@@ -353,7 +391,6 @@ private function generateSchemaAnnotation(): string {
353391

354392
/**
355393
* Converts the object to a @OA\Parameter(...) annotation string
356-
* @param string $parameterLocation Where the parameter resides. Can be 'path', 'query', 'header' or 'cookie'.
357394
*/
358395
public function toParameterAnnotation(): string {
359396
$head = "@OA\\Parameter";
@@ -381,6 +418,9 @@ public function toPropertyAnnotation(): string {
381418
}
382419
}
383420

421+
/**
422+
* Parser that can parse the annotations of existing recodex endpoints
423+
*/
384424
class AnnotationHelper {
385425
private static function getMethod(string $className, string $methodName): \ReflectionMethod {
386426
$class = new \ReflectionClass($className);

0 commit comments

Comments
 (0)