Passed
Push — master ( 77c76c...926ba1 )
by Fran
03:51
created

DocumentorService::setRequestHeaders()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 32
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 6
nop 2
dl 0
loc 32
ccs 0
cts 17
cp 0
crap 30
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace PSFS\services;
4
5
use Propel\Runtime\Map\ColumnMap;
6
use PSFS\base\config\Config;
7
use PSFS\base\Logger;
8
use PSFS\base\Request;
9
use PSFS\base\Router;
10
use PSFS\base\Service;
11
use PSFS\base\types\helpers\GeneratorHelper;
12
use PSFS\base\types\helpers\InjectorHelper;
13
use PSFS\base\types\helpers\RouterHelper;
14
use Symfony\Component\Finder\Finder;
15
16
/**
17
 * Class DocumentorService
18
 * @package PSFS\services
19
 */
20
class DocumentorService extends Service
21
{
22
    public static $nativeMethods = [
23
        'modelList', // Api list
24
        'get', // Api get
25
        'post', // Api post
26
        'put', // Api put
27
        'delete', // Api delete
28
    ];
29
30
    const DTO_INTERFACE = '\\PSFS\\base\\dto\\Dto';
31
    const MODEL_INTERFACE = '\\Propel\\Runtime\\ActiveRecord\\ActiveRecordInterface';
32
33
    /**
34
     * @Inyectable
35
     * @var \PSFS\base\Router route
36
     */
37
    protected $route;
38
39
    /**
40
     * Method that extract all modules
41
     * @param string $requestModule
42
     * @return array
43
     */
44
    public function getModules($requestModule)
45
    {
46
        $modules = [];
47
        $domains = $this->route->getDomains();
48
        if (count($domains)) {
49
            foreach ($domains as $module => $info) {
50
                try {
51
                    $module = preg_replace('/(@|\/)/', '', $module);
52
                    if (!preg_match('/^ROOT/i', $module) && $module == $requestModule) {
53
                        $modules = [
54
                            'name' => $module,
55
                            'path' => realpath($info['template'] . DIRECTORY_SEPARATOR . '..'),
56
                        ];
57
                    }
58
                } catch (\Exception $e) {
59
                    $modules[] = $e->getMessage();
60
                }
61
            }
62
        }
63
64
        return $modules;
65
    }
66
67
    /**
68
     * Method that extract all endpoints for each module
69
     *
70
     * @param array $module
71
     *
72
     * @return array
73
     */
74
    public function extractApiEndpoints(array $module)
75
    {
76
        $module_path = $module['path'] . DIRECTORY_SEPARATOR . 'Api';
77
        $module_name = $module['name'];
78
        $endpoints = [];
79
        if (file_exists($module_path)) {
80
            $finder = new Finder();
81
            $finder->files()->in($module_path)->depth(0)->name('*.php');
82
            if (count($finder)) {
83
                /** @var \SplFileInfo $file */
84
                foreach ($finder as $file) {
85
                    if(preg_match('/User\.php$/i', $file->getFilename())) {
86
                        $namespace = "\\{$module_name}\\Api\\" . str_replace('.php', '', $file->getFilename());
87
                        $info = $this->extractApiInfo($namespace, $module_name);
88
                        if (!empty($info)) {
89
                            $endpoints[$namespace] = $info;
90
                        }
91
                    }
92
                }
93
            }
94
        }
95
        return $endpoints;
96
    }
97
98
    /**
99
     * Method that extract all the endpoit information by reflection
100
     *
101
     * @param string $namespace
102
     *
103
     * @return array
104
     */
105
    public function extractApiInfo($namespace, $module)
106
    {
107
        $info = [];
108
        if (class_exists($namespace)) {
109
            $reflection = new \ReflectionClass($namespace);
110
            foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
111
                try {
112
                    if($method->getShortName() === 'checkLogin') {
113
                        $mInfo = $this->extractMethodInfo($namespace, $method, $reflection, $module);
114
                        if (NULL !== $mInfo) {
115
                            $info[] = $mInfo;
116
                        }
117
                    }
118
                } catch (\Exception $e) {
119
                    Logger::getInstance()->errorLog($e->getMessage());
120
                }
121
            }
122
        }
123
        return $info;
124
    }
125
126
    /**
127
     * Extract route from doc comments
128
     *
129
     * @param string $comments
130
     *
131
     * @return string
132
     */
133
    protected function extractRoute($comments = '')
134
    {
135
        $route = '';
136
        preg_match('/@route\ (.*)\n/i', $comments, $route);
137
138
        return $route[1];
139
    }
140
141
    /**
142
     * Extract api from doc comments
143
     *
144
     * @param string $comments
145
     *
146
     * @return string
147
     */
148
    protected function extractApi($comments = '')
149
    {
150
        $api = '';
151
        preg_match('/@api\ (.*)\n/i', $comments, $api);
152
153
        return $api[1];
154
    }
155
156
    /**
157
     * Extract api from doc comments
158
     *
159
     * @param string $comments
160
     *
161
     * @return boolean
162
     */
163
    protected function checkDeprecated($comments = '')
164
    {
165
        return false != preg_match('/@deprecated\n/i', $comments);
166
    }
167
168
    /**
169
     * Extract visibility from doc comments
170
     *
171
     * @param string $comments
172
     *
173
     * @return boolean
174
     */
175
    protected function extractVisibility($comments = '')
176
    {
177
        $visible = TRUE;
178
        preg_match('/@visible\ (true|false)\n/i', $comments, $visibility);
179
        if (count($visibility)) {
180
            $visible = !('false' == $visibility[1]);
181
        }
182
183
        return $visible;
184
    }
185
186
    /**
187
     * Method that extract the description for the endpoint
188
     *
189
     * @param string $comments
190
     *
191
     * @return string
192
     */
193
    protected function extractDescription($comments = '')
194
    {
195
        $description = '';
196
        $docs = explode("\n", $comments);
197
        if (count($docs)) {
198
            foreach ($docs as &$doc) {
199 View Code Duplication
                if (!preg_match('/(\*\*|\@)/i', $doc) && preg_match('/\*\ /i', $doc)) {
200
                    $doc = explode('* ', $doc);
201
                    $description = $doc[1];
202
                }
203
            }
204
        }
205
206
        return $description;
207
    }
208
209
    /**
210
     * Method that extract the type of a variable
211
     *
212
     * @param string $comments
213
     *
214
     * @return string
215
     */
216
    public static function extractVarType($comments = '')
217
    {
218
        $type = 'string';
219
        preg_match('/@var\ (.*) (.*)\n/i', $comments, $varType);
220
        if (count($varType)) {
221
            $aux = trim($varType[1]);
222
            $type = str_replace(' ', '', strlen($aux) > 0 ? $varType[1] : $varType[2]);
223
        }
224
225
        return $type;
226
    }
227
228
    /**
229
     * Method that extract the payload for the endpoint
230
     *
231
     * @param string $model
232
     * @param string $comments
233
     *
234
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
235
     */
236
    protected function extractPayload($model, $comments = '')
237
    {
238
        $payload = [];
239
        preg_match('/@payload\ (.*)\n/i', $comments, $doc);
240
        if (count($doc)) {
241
            $namespace = str_replace('{__API__}', $model, $doc[1]);
242
            $payload = $this->extractModelFields($namespace);
243
            $reflector = new \ReflectionClass($namespace);
244
            $namespace = $reflector->getShortName();
245
        } else {
246
            $namespace = $model;
247
        }
248
249
        return [$namespace, $payload];
250
    }
251
252
    /**
253
     * Extract all the properties from Dto class
254
     *
255
     * @param string $class
256
     *
257
     * @return array
258
     */
259
    protected function extractDtoProperties($class)
260
    {
261
        $properties = [];
262
        $reflector = new \ReflectionClass($class);
263
        if ($reflector->isSubclassOf(self::DTO_INTERFACE)) {
264
            $properties = array_merge($properties, InjectorHelper::extractVariables($reflector));
265
        }
266
267
        return $properties;
268
    }
269
270
    /**
271
     * Extract return class for api endpoint
272
     *
273
     * @param string $model
274
     * @param string $comments
275
     *
276
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
277
     */
278
    protected function extractReturn($model, $comments = '')
279
    {
280
        $modelDto = [];
281
        preg_match('/\@return\ (.*)\((.*)\)\n/i', $comments, $returnTypes);
282
        if (count($returnTypes)) {
283
            // Extract principal DTO information
284
            if (array_key_exists(1, $returnTypes)) {
285
                $modelDto = $this->extractDtoProperties($returnTypes[1]);
286
            }
287
            if (array_key_exists(2, $returnTypes)) {
288
                $subDtos = preg_split('/,?\ /', str_replace('{__API__}', $model, $returnTypes[2]));
289
                if (count($subDtos)) {
290
                    foreach ($subDtos as $subDto) {
291
                        $isArray = false;
292
                        list($field, $dtoName) = explode('=', $subDto);
293
                        if (false !== strpos($dtoName, '[') && false !== strpos($dtoName, ']')) {
294
                            $dtoName = str_replace(']', '', str_replace('[', '', $dtoName));
295
                            $isArray = true;
296
                        }
297
                        $dto = $this->extractModelFields($dtoName);
298
                        $modelDto[$field] = ($isArray) ? [$dto] : $dto;
299
                        $modelDto['objects'][$dtoName] = $dto;
300
                    }
301
                }
302
            }
303
        }
304
305
        return $modelDto;
306
    }
307
308
    /**
309
     * Extract all fields from a ActiveResource model
310
     *
311
     * @param string $namespace
312
     *
313
     * @return mixed
314
     */
315
    protected function extractModelFields($namespace)
316
    {
317
        $payload = [];
318
        try {
319
            $reflector = new \ReflectionClass($namespace);
320
            // Checks if reflector is a subclass of propel ActiveRecords
321
            if (NULL !== $reflector && $reflector->isSubclassOf(self::MODEL_INTERFACE)) {
322
                $tableMap = $namespace::TABLE_MAP;
323
                $tableMap = $tableMap::getTableMap();
324
                /** @var ColumnMap $field */
325
                foreach ($tableMap->getColumns() as $field) {
326
                    $info = [
327
                        "type" => $field->getType(),
328
                        "required" => $field->isNotNull(),
329
                    ];
330
                    $payload[$field->getPhpName()] = $info;
331
                }
332
            } elseif (null !== $reflector && $reflector->isSubclassOf(self::DTO_INTERFACE)) {
333
                $payload = $this->extractDtoProperties($namespace);
334
            }
335
        } catch (\Exception $e) {
336
            Logger::getInstance()->errorLog($e->getMessage());
337
        }
338
339
        return $payload;
340
    }
341
342
    /**
343
     * Method that extract all the needed info for each method in each API
344
     *
345
     * @param string $namespace
346
     * @param \ReflectionMethod $method
347
     * @param \ReflectionClass $reflection
348
     * @param string $module
349
     *
350
     * @return array
351
     */
352
    protected function extractMethodInfo($namespace, \ReflectionMethod $method, \ReflectionClass $reflection, $module)
353
    {
354
        $methodInfo = NULL;
355
        $docComments = $method->getDocComment();
356
        if (FALSE !== $docComments && preg_match('/\@route\ /i', $docComments)) {
357
            $api = self::extractApi($reflection->getDocComment());
358
            list($route, $info) = RouterHelper::extractRouteInfo($method, $api, $module);
359
            $route = explode('#|#', $route);
360
            $modelNamespace = str_replace('Api', 'Models', $namespace);
361
            if ($info['visible'] && !self::checkDeprecated($docComments)) {
362
                try {
363
                    $return = $this->extractReturn($modelNamespace, $docComments);
364
                    $url = array_pop($route);
365
                    $methodInfo = [
366
                        'url' => str_replace("/" . $module . "/api", '', $url),
367
                        'method' => $info['http'],
368
                        'description' => $info['label'],
369
                        'return' => $return,
370
                        'objects' => $return['objects'],
371
                        'class' => $reflection->getShortName(),
372
                    ];
373
                    unset($methodInfo['return']['objects']);
374
                    $this->setRequestParams($method, $methodInfo, $modelNamespace, $docComments);
375
                    $this->setQueryParams($method, $methodInfo);
376
                    $this->setRequestHeaders($reflection, $methodInfo);
377
                } catch (\Exception $e) {
378
                    jpre($e->getMessage());
379
                    Logger::getInstance()->errorLog($e->getMessage());
380
                }
381
            }
382
        }
383
384
        return $methodInfo;
385
    }
386
387
    /**
388
     * Translator from php types to swagger types
389
     * @param string $format
390
     *
391
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
392
     */
393 1
    public static function translateSwaggerFormats($format)
394
    {
395 1
        switch (strtolower($format)) {
396 1
            case 'bool':
397 1
            case 'boolean':
398
                $swaggerType = 'boolean';
399
                $swaggerFormat = '';
400
                break;
401
            default:
402 1
            case 'string':
403 1
            case 'varchar':
404 1
                $swaggerType = 'string';
405 1
                $swaggerFormat = '';
406 1
                break;
407 1
            case 'binary':
408 1
            case 'varbinary':
409
                $swaggerType = 'string';
410
                $swaggerFormat = 'binary';
411
                break;
412 1
            case 'int':
413 1
            case 'integer':
414 1
                $swaggerType = 'integer';
415 1
                $swaggerFormat = 'int32';
416 1
                break;
417
            case 'float':
418
            case 'double':
419
                $swaggerType = 'number';
420
                $swaggerFormat = strtolower($format);
421
                break;
422
            case 'date':
423
                $swaggerType = 'string';
424
                $swaggerFormat = 'date';
425
                break;
426
            case 'datetime':
427
                $swaggerType = 'string';
428
                $swaggerFormat = 'date-time';
429
                break;
430
431
        }
432 1
        return [$swaggerType, $swaggerFormat];
433
    }
434
435
    /**
436
     * Method that parse the definitions for the api's
437
     * @param string $name
438
     * @param array $fields
439
     *
440
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array<string,string|array>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
441
     */
442
    public static function extractSwaggerDefinition($name, array $fields)
443
    {
444
        $definition = [
445
            $name => [
446
                "type" => "object",
447
                "properties" => [],
448
            ],
449
        ];
450
        foreach ($fields as $field => $info) {
451
            list($type, $format) = self::translateSwaggerFormats($info['type']);
452
            $dto['properties'][$field] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$dto was never initialized. Although not strictly required by PHP, it is generally a good practice to add $dto = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
453
                "type" => $type,
454
                "required" => $info['required'],
455
            ];
456
            $definition[$name]['properties'][$field] = [
457
                "type" => $type,
458
                "required" => $info['required'],
459
            ];
460
            if (strlen($format)) {
461
                $definition[$name]['properties'][$field]['format'] = $format;
462
            }
463
        }
464
        return $definition;
465
    }
466
467
    /**
468
     * @return array
469
     */
470
    private static function swaggerResponses()
471
    {
472
        $codes = [200, 400, 404, 500];
473
        $responses = [];
474
        foreach ($codes as $code) {
475
            switch ($code) {
476
                default:
477
                case 200:
478
                    $message = _('Successful response');
479
                    break;
480
                case 400:
481
                    $message = _('Client error in request');
482
                    break;
483
                case 404:
484
                    $message = _('Service not found');
485
                    break;
486
                case 500:
487
                    $message = _('Server error');
488
                    break;
489
            }
490
            $responses[$code] = [
491
                'description' => $message,
492
                'schema' => [
493
                    'type' => 'object',
494
                    'properties' => [
495
                        'success' => [
496
                            'type' => 'boolean'
497
                        ],
498
                        'data' => [
499
                            'type' => 'boolean',
500
                        ],
501
                        'total' => [
502
                            'type' => 'integer',
503
                            'format' => 'int32',
504
                        ],
505
                        'pages' => [
506
                            'type' => 'integer',
507
                            'format' => 'int32',
508
                        ]
509
                    ]
510
                ]
511
            ];
512
        }
513
        return $responses;
514
    }
515
516
    /**
517
     * Method that export
518
     * @param array $module
519
     *
520
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
521
     */
522
    public static function swaggerFormatter(array $module)
523
    {
524
        $formatted = [
525
            "swagger" => "2.0",
526
            "host" => preg_replace('/^(http|https)\:\/\/(.*)\/$/i', '$2', Router::getInstance()->getRoute('', true)),
527
            "basePath" => '/' . $module['name'] . '/api',
528
            "schemes" => [Request::getInstance()->getServer('HTTPS') == 'on' ? "https" : "http"],
529
            "info" => [
530
                "title" => _('Documentación API módulo ') . $module['name'],
531
                "version" => Config::getParam('api.version', '1.0'),
532
                "contact" => [
533
                    "name" => Config::getParam("author", "Fran López"),
534
                    "email" => Config::getParam("author_email", "[email protected]"),
535
                ]
536
            ]
537
        ];
538
        $dtos = $paths = [];
539
        $endpoints = DocumentorService::getInstance()->extractApiEndpoints($module);
540
        foreach ($endpoints as $model) {
541
            foreach ($model as $endpoint) {
542
                if (!preg_match('/^\/(admin|api)\//i', $endpoint['url']) && strlen($endpoint['url'])) {
543
                    $url = preg_replace('/\/' . $module['name'] . '\/api/i', '', $endpoint['url']);
544
                    $description = $endpoint['description'];
545
                    $method = strtolower($endpoint['method']);
546
                    $paths[$url][$method] = [
547
                        'summary' => $description,
548
                        'produces' => ['application/json'],
549
                        'consumes' => ['application/json'],
550
                        'responses' => self::swaggerResponses(),
551
                        'parameters' => [],
552
                    ];
553
                    if (array_key_exists('parameters', $endpoint)) {
554
                        foreach ($endpoint['parameters'] as $parameter => $type) {
555
                            list($type, $format) = self::translateSwaggerFormats($type);
556
                            $paths[$url][$method]['parameters'][] = [
557
                                'in' => 'path',
558
                                'required' => true,
559
                                'name' => $parameter,
560
                                'type' => $type,
561
                                'format' => $format,
562
                            ];
563
                        }
564
                    }
565 View Code Duplication
                    if (array_key_exists('query', $endpoint)) {
566
                        foreach ($endpoint['query'] as $query) {
567
                            $paths[$url][$method]['parameters'][] = $query;
568
                        }
569
                    }
570 View Code Duplication
                    if (array_key_exists('headers', $endpoint)) {
571
                        foreach ($endpoint['headers'] as $query) {
572
                            $paths[$url][$method]['parameters'][] = $query;
573
                        }
574
                    }
575
                    foreach ($endpoint['objects'] as $name => $object) {
576
                        if (class_exists($name)) {
577
                            $class = GeneratorHelper::extractClassFromNamespace($name);
578
                            if(array_key_exists('data', $endpoint['return']) && count(array_keys($object)) === count(array_keys($endpoint['return']['data']))) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 160 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
579
                                $classDefinition = [
580
                                    'type' => 'object',
581
                                    '$ref' => '#/definitions/' . $class,
582
                                ];
583
                            } else {
584
                                $classDefinition = [
585
                                    'type' => 'array',
586
                                    'items' => [
587
                                        '$ref' => '#/definitions/' . $class,
588
                                    ],
589
                                ];
590
                            }
591
592
                            $paths[$url][$method]['responses'][200]['schema']['properties']['data'] = $classDefinition;
593
                            $dtos += self::extractSwaggerDefinition($class, $object);
594
                            if (array_key_exists('payload', $endpoint)) {
595
                                $dtos[$endpoint['payload']['type']] = [
596
                                    'type' => 'object',
597
                                    'properties' => $endpoint['payload']['properties'],
598
                                ];
599
                                $paths[$url][$method]['parameters'][] = [
600
                                    'in' => 'body',
601
                                    'name' => $endpoint['payload']['type'],
602
                                    'required' => true,
603
                                    'schema' => [
604
                                        'type' => 'object',
605
                                        '$ref' => '#/definitions/' . $endpoint['payload']['type'],
606
                                    ],
607
                                ];
608
                            }
609
                        }
610
                        if (!isset($paths[$url][$method]['tags']) || !in_array($endpoint['class'], $paths[$url][$method]['tags'])) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 132 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
611
                            $paths[$url][$method]['tags'][] = $endpoint['class'];
612
                        }
613
                    }
614
                }
615
            }
616
        }
617
        $formatted['definitions'] = $dtos;
618
        $formatted['paths'] = $paths;
619
        return $formatted;
620
    }
621
622
    /**
623
     * Method that extract the Dto class for the api documentation
624
     * @param string $dto
625
     * @param boolean $isArray
626
     *
627
     * @return string
628
     */
629
    protected function extractDtoName($dto, $isArray = false)
630
    {
631
        $dto = explode('\\', $dto);
632
        $modelDto = array_pop($dto) . "Dto";
633
        if ($isArray) {
634
            $modelDto .= "List";
635
        }
636
637
        return $modelDto;
638
    }
639
640
    /**
641
     * @param \ReflectionMethod $method
642
     * @param $methodInfo
643
     */
644
    protected function setQueryParams(\ReflectionMethod $method, &$methodInfo)
645
    {
646
        if (in_array($methodInfo['method'], ['GET']) && in_array($method->getShortName(), self::$nativeMethods)) {
647
            $methodInfo['query'] = [];
648
            $methodInfo['query'][] = [
649
                "name" => "__limit",
650
                "in" => "query",
651
                "description" => _("Límite de registros a devolver, -1 para devolver todos los registros"),
652
                "required" => false,
653
                "type" => "integer",
654
            ];
655
            $methodInfo['query'][] = [
656
                "name" => "__page",
657
                "in" => "query",
658
                "description" => _("Página a devolver"),
659
                "required" => false,
660
                "type" => "integer",
661
            ];
662
            $methodInfo['query'][] = [
663
                "name" => "__fields",
664
                "in" => "query",
665
                "description" => _("Campos a devolver"),
666
                "required" => false,
667
                "type" => "array",
668
                "items" => [
669
                    "type" => "string",
670
                ]
671
            ];
672
        }
673
    }
674
    /**
675
     * @param \ReflectionClass $reflection
676
     * @param $methodInfo
677
     */
678
    protected function setRequestHeaders(\ReflectionClass $reflection, &$methodInfo)
679
    {
680
681
        $methodInfo['headers'] = [];
682
        foreach($reflection->getProperties() as $property) {
683
            $doc = $property->getDocComment();
684
            preg_match('/@header\ (.*)\n/i', $doc, $headers);
685
            if(count($headers)) {
686
                $header = [
687
                    "name" => $headers[1],
688
                    "in" => "header",
689
                    "required" => true,
690
                ];
691
692
                // Extract var type
693
                $header['type'] = $this->extractVarType($doc);
694
695
                // Extract description
696
                preg_match('/@label\ (.*)\n/i', $doc, $label);
697
                if(count($label)) {
698
                    $header['description'] = _($label[1]);
699
                }
700
701
                // Extract default value
702
                preg_match('/@default\ (.*)\n/i', $doc, $default);
703
                if(count($default)) {
704
                    $header['default'] = $default[1];
705
                }
706
                $methodInfo['headers'][] = $header;
707
            }
708
        }
709
    }
710
711
    /**
712
     * @param \ReflectionMethod $method
713
     * @param array $methodInfo
714
     * @param string $modelNamespace
715
     * @param string $docComments
716
     */
717
    protected function setRequestParams(\ReflectionMethod $method, &$methodInfo, $modelNamespace, $docComments)
718
    {
719
        if (in_array($methodInfo['method'], ['POST', 'PUT'])) {
720
            list($payloadNamespace, $payloadDto) = $this->extractPayload($modelNamespace, $docComments);
721
            if (count($payloadDto)) {
722
                $methodInfo['payload'] = [
723
                    'type' => $payloadNamespace,
724
                    'properties' => $payloadDto,
725
                ];
726
            }
727
        }
728
        if ($method->getNumberOfParameters() > 0) {
729
            $methodInfo['parameters'] = [];
730
            foreach ($method->getParameters() as $parameter) {
731
                $parameterName = $parameter->getName();
732
                $types = [];
733
                preg_match_all('/\@param\ (.*)\ \$' . $parameterName . '$/im', $docComments, $types);
734
                if (count($types) > 1) {
735
                    $methodInfo['parameters'][$parameterName] = $types[1][0];
736
                }
737
            }
738
        }
739
    }
740
}
741