GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Swagger   F
last analyzed

Complexity

Total Complexity 115

Size/Duplication

Total Lines 572
Duplicated Lines 7.34 %

Coupling/Cohesion

Components 1
Dependencies 24

Test Coverage

Coverage 87.21%

Importance

Changes 0
Metric Value
dl 42
loc 572
ccs 300
cts 344
cp 0.8721
rs 2
c 0
b 0
f 0
wmc 115
lcom 1
cbo 24

19 Methods

Rating   Name   Duplication   Size   Complexity  
A appendControllers() 0 6 2
A appendController() 0 31 5
A toJson() 0 5 1
A toArray() 0 4 1
A objectToArray() 0 18 6
B getExceptionsSchema() 0 51 9
B getReturnSchema() 3 34 7
A makeExample() 0 15 6
C makeTempSchema() 12 54 11
A getRefSchema() 0 12 2
F getParamsSchema() 27 102 24
A getAnySchema() 0 18 5
A getArraySchema() 0 22 4
A getObjectSchema() 0 30 5
A hasFileParam() 0 10 3
D mapValidation() 0 34 20
A mapType() 0 14 2
A getShortClassName() 0 6 1
A implode() 0 5 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Swagger often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Swagger, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace PhpBoot\Docgen\Swagger;
3
4
use PhpBoot\Application;
5
use PhpBoot\Controller\ControllerContainer;
6
use PhpBoot\Controller\ExceptionRenderer;
7
use PhpBoot\Controller\Route;
8
use PhpBoot\Docgen\Swagger\Schemas\ArraySchemaObject;
9
use PhpBoot\Docgen\Swagger\Schemas\BodyParameterObject;
10
use PhpBoot\Docgen\Swagger\Schemas\OperationObject;
11
use PhpBoot\Docgen\Swagger\Schemas\OtherParameterObject;
12
use PhpBoot\Docgen\Swagger\Schemas\PrimitiveSchemaObject;
13
use PhpBoot\Docgen\Swagger\Schemas\RefSchemaObject;
14
use PhpBoot\Docgen\Swagger\Schemas\ResponseObject;
15
use PhpBoot\Docgen\Swagger\Schemas\SimpleModelSchemaObject;
16
use PhpBoot\Docgen\Swagger\Schemas\SwaggerObject;
17
use PhpBoot\Docgen\Swagger\Schemas\TagObject;
18
use PhpBoot\Entity\ArrayContainer;
19
use PhpBoot\Entity\EntityContainer;
20
use PhpBoot\Entity\ScalarTypeContainer;
21
use PhpBoot\Entity\TypeContainerInterface;
22
use PhpBoot\Metas\ParamMeta;
23
use PhpBoot\Metas\ReturnMeta;
24
use PhpBoot\Utils\ArrayHelper;
25
use PhpBoot\Validator\Validator;
26
use Symfony\Component\HttpKernel\Exception\HttpException;
27
28
class Swagger extends SwaggerObject
29
{
30
31
    /**
32
     * @param Application $app
33
     * @param ControllerContainer[] $controllers
34
     */
35 1
    public function appendControllers(Application $app, $controllers)
36
    {
37 1
        foreach ($controllers as $controller) {
38 1
            $this->appendController($app, $controller);
39 1
        }
40 1
    }
41
42
    /**
43
     * @param Application $app
44
     * @param ControllerContainer $controller
45
     */
46 1
    public function appendController(Application $app, ControllerContainer $controller)
47
    {
48
        //tags
49 1
        $tag = new TagObject();
50 1
        $tag->name = $controller->getSummary();
51 1
        $tag->description = $controller->getDescription();
52 1
        $this->tags[] = $tag;
53
54 1
        foreach ($controller->getRoutes() as $action => $route) {
55 1
            $op = new OperationObject();
56 1
            $op->tags = [$controller->getSummary()];
57 1
            $op->summary = $route->getSummary();
58 1
            $op->description = $route->getDescription();
59
60 1
            $op->parameters = $this->getParamsSchema($app, $controller, $action, $route);
61 1
            if($this->hasFileParam($route)){
62 1
                $op->consumes = ['multipart/form-data'];
63 1
            }
64
65 1
            if ($returnSchema = $this->getReturnSchema($app, $controller, $action, $route)) {
66 1
                $op->responses['200'] = $returnSchema;
67 1
            }
68 1
            $op->responses += $this->getExceptionsSchema($app, $controller, $action, $route);
69 1
            $uri = $app->getFullUri($route->getUri());
70 1
            if (!isset($this->paths[$uri])) {
71 1
                $this->paths[$uri] = [];
72 1
            }
73 1
            $method = strtolower($route->getMethod());
74 1
            $this->paths[$uri][$method] = $op;
75 1
        }
76 1
    }
77
78
    /**
79
     * @return string
80
     */
81
    public function toJson()
82
    {
83
        $json = $this->toArray();
84
        return json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
85
    }
86
87
    /**
88
     * @return array
89
     */
90 1
    public function toArray()
91
    {
92 1
        return self::objectToArray($this);
93
    }
94
95
    /**
96
     * @param $object
97
     * @return array
98
     */
99 1
    static public function objectToArray($object)
100
    {
101 1
        if (is_object($object)) {
102 1
            $object = get_object_vars($object);
103 1
        }
104 1
        $res = [];
105 1
        foreach ($object as $k => $v) {
106 1
            if ($v === null) {
107 1
                continue;
108
            }
109 1
            if (is_array($v) || is_object($v)) {
110 1
                $res[$k] = self::objectToArray($v);
111 1
            } else {
112 1
                $res[$k] = $v;
113
            }
114 1
        }
115 1
        return $res;
116
    }
117
118
    /**
119
     * @param Application $app
120
     * @param ControllerContainer $controller
121
     * @param $action
122
     * @param Route $route
123
     * @return array
124
     */
125 1
    public function getExceptionsSchema(Application $app,
126
                                        ControllerContainer $controller,
0 ignored issues
show
Unused Code introduced by
The parameter $controller is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
127
                                        $action,
0 ignored issues
show
Unused Code introduced by
The parameter $action is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
128
                                        Route $route)
129
    {
130 1
        $handler = $route->getExceptionHandler();
131 1
        if (!$handler) {
132
            return [];
133
        }
134 1
        $schemas = [];
135 1
        foreach ($handler->getExceptions() as $exception) {
136 1
            list($name, $desc) = $exception;
137
138 1
            $ins = null;
139
            try{
140 1
                $ins = $app->make($name);
141 1
            }catch (\Exception $e){
142
                try{
143
                    $ins = new $name("");
144
                }catch (\Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
145
146
                }
147
            }
148
149
            //TODO status 重复怎么办
150 1
            if ($ins instanceof HttpException) {
151 1
                $status = $ins->getStatusCode();
152 1
            } else {
153
                $status = 500;
154
            }
155 1
            if (isset($schemas[$status])) {
156
                //$this->warnings[] = "status response $status has been used for $name, $desc";
157
                $res = $schemas[$status];
158
            } else {
159 1
                $res = new ResponseObject();
160
            }
161 1
            $shortName = self::getShortClassName($name);
162 1
            $desc = "$shortName: $desc";
163 1
            $res->description = self::implode("\n", [$res->description, $desc]);
164 1
            if($ins){
165 1
                $error = $app->get(ExceptionRenderer::class)->render($ins)->getContent();
166 1
                if($error){
167
                    $res->examples = [$shortName => $error];
168
                }
169 1
            }
170
            //$res->schema = new RefSchemaObject("#/definitions/$name");
171 1
            $schemas[$status] = $res;
172
173 1
        }
174 1
        return $schemas;
175
    }
176
177
    /**
178
     * @param Application $app
179
     * @param ControllerContainer $controller
180
     * @param $action
181
     * @param Route $route
182
     * @return null|ResponseObject
183
     */
184 1
    public function getReturnSchema(Application $app,
185
                                    ControllerContainer $controller,
186
                                    $action,
187
                                    Route $route)
188
    {
189 1
        $response = $route->getResponseHandler();
190 1
        if (!$response) {
191
            return null;
192
        }
193 1
        $mappings = $response->getMappings();
194 1
        $output = [];
195 1
        $schema = new ResponseObject();
196 1
        foreach ($mappings as $key => $map) {
197 1 View Code Duplication
            if (substr($key, 0, strlen('response.')) == 'response.') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
198 1
                $key = substr($key, strlen('response.'));
199 1
            }
200 1
            ArrayHelper::set($output, $key, $map);
201 1
        }
202
        //TODO 支持 header、status 等
203 1
        if (isset($output['content'])) {
204 1
            $content = $output['content'];
205 1
            if ($content instanceof ReturnMeta) {
206 1
                $schema->description = $content->description;
207 1
                $schema->schema = $this->getAnySchema($app, $controller, $action, $route, $content->container);
0 ignored issues
show
Bug introduced by
It seems like $content->container can be null; however, getAnySchema() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
208 1
            } elseif (is_array($content)) {
209 1
                $tmpSchema = $this->makeTempSchema($app, $controller, $action, $route, $content, 'Res');
210 1
                $schema->schema = $tmpSchema;
211
212 1
            }
213
            //$schema->examples = ['application/json'=>$this->makeExample($content)];
214 1
            return $schema;
215
        }
216
        return null;
217
    }
218
219
    /**
220
     * @param $content
221
     */
222
    public function makeExample($content)
223
    {
224
        if ($content instanceof ReturnMeta || $content instanceof ParamMeta) {
225
            return $this->makeExample($content->container);
226
        }elseif ($content instanceof TypeContainerInterface){
227
            return $content->makeExample();
228
        }elseif(is_array($content)) {
229
            $res = [];
230
            foreach ($content as $k => $v) {
231
                $res[$k] = $this->makeExample($v);
232
            }
233
            return $res;
234
        }
235
        return null;
236
    }
237
    /**
238
     * @param Application $app
239
     * @param ControllerContainer $controller
240
     * @param $action
241
     * @param Route $route
242
     * @param array $arr
243
     * @param string $suffix
244
     * @return RefSchemaObject
245
     */
246 1
    public function makeTempSchema(Application $app,
247
                                   ControllerContainer $controller,
248
                                   $action,
249
                                   Route $route,
250
                                   array $arr, $suffix)
251
    {
252 1
        $className = self::getShortClassName($controller->getClassName());
253 1
        $name = $className . ucfirst($action) . $suffix;
254
255 1
        $schema = new SimpleModelSchemaObject();
256
257 1
        foreach ($arr as $k => $v) {
258 1
            if (is_array($v)) {
259 1
                $schema->properties[$k] = $this->makeTempSchema($app, $controller, $action, $route, $v, $suffix);
260 1
            } elseif ($v instanceof ReturnMeta) {
261 1
                $sub = $this->getAnySchema($app, $controller, $action, $route, $v->container);
0 ignored issues
show
Bug introduced by
It seems like $v->container can be null; however, getAnySchema() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
262 1
                if($sub){
263 1
                    $sub->description = $v->description;
264 1
                }
265 1
                $schema->properties[$k] = $sub;
266 1
            } elseif ($v instanceof ParamMeta) {
267 1 View Code Duplication
                if ($v->container instanceof ArrayContainer) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
268 1
                    $sub = $this->getArraySchema($app, $controller, $action, $route, $v->container);
269
                    //TODO array for validation
270 1
                } elseif ($v->container instanceof EntityContainer) {
271 1
                    $sub = $this->getRefSchema($app, $controller, $action, $route, $v->container);
272
                    //TODO array for validation
273 1
                } else {
274 1
                    $sub = new PrimitiveSchemaObject();
275 1
                    $sub->type = self::mapType($v->type);
276 1
                    self::mapValidation($v->validation, $sub);
277 1
                    unset($sub->required);
278
                }
279 1
                if($sub){
280 1
                    $sub->description = $v->description;
281 1
                    $sub->default = $v->default;
282 1
                }
283 1
                if (!$v->isOptional) {
284 1
                    $schema->required[] = $k;
285 1
                }
286 1
                $schema->properties[$k] = $sub;
287 1
            } else {
288
                //TODO how to do?
289
            }
290 1
        }
291 1
        $unused = $name;
292 1
        $tempId = 0;
293 1
        while (isset($this->definitions[$unused])) {
294 1
            $unused = $name . $tempId;
295 1
            $tempId++;
296 1
        }
297 1
        $this->definitions[$unused] = $schema;
298 1
        return new RefSchemaObject("#/definitions/$unused");
299
    }
300
301
    /**
302
     * @param Application $app
303
     * @param ControllerContainer $controller
304
     * @param $action
305
     * @param Route $route
306
     * @param EntityContainer $container
307
     * @return RefSchemaObject
308
     */
309 1
    public function getRefSchema(Application $app,
310
                                 ControllerContainer $controller,
311
                                 $action,
312
                                 Route $route,
313
                                 EntityContainer $container)
314
    {
315 1
        $name = $container->getClassName();
316 1
        if (!isset($this->definitions[$name])) {
317 1
            $this->definitions[$name] = $this->getObjectSchema($app, $controller, $action, $route, $container);
318 1
        }
319 1
        return new RefSchemaObject("#/definitions/$name");
320
    }
321
322 1
    public function getParamsSchema(Application $app,
323
                                    ControllerContainer $controller,
324
                                    $action,
325
                                    Route $route)
326
    {
327 1
        $params = $route->getRequestHandler()->getParamMetas();
328 1
        $parameters = [];
329 1
        $body = [];
330 1
        $in = 'query';
331
332 1
        $bodyType = 'body'; // 当有文件上传时, 必须是formData方式
333 1
        if($this->hasFileParam($route)){
334 1
            $bodyType = 'formData';
335 1
        }
336
337 1
        foreach ($params as $name => $param) {
338 1
            $isFile = false;
339 1
            if ($param->isPassedByReference) {
340 1
                continue;
341
            }
342 1
            if ($param->source == 'request.request') {
343
                $in = $bodyType;
344
                $name = '';
345 1 View Code Duplication
            } elseif (strpos($param->source, 'request.request.') === 0
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
346 1
                || $param->source == 'request.request'
347 1
            ) {
348 1
                $in = $bodyType;
349 1
                $name = substr($param->source, strlen('request.request.'));
350 1
            } elseif (strpos($param->source, 'request.query.') === 0) {
351 1
                $in = 'query';
352 1
                $name = substr($param->source, strlen('request.query.'));
353 1
            } elseif (strpos($param->source, 'request.cookies.') === 0) {
354 1
                $in = 'cookie';
355 1
                $name = substr($param->source, strlen('request.cookies.'));
356 1
            } elseif (strpos($param->source, 'request.headers.') === 0) {
357 1
                $in = 'header';
358 1
                $name = substr($param->source, strlen('request.headers.'));
359 1 View Code Duplication
            } elseif (strpos($param->source, 'request.files.') === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
360 1
                $isFile = true;
361 1
                $in = $bodyType;
362 1
                $name = substr($param->source, strlen('request.files.'));
363 1
            } elseif (strpos($param->source, 'request.') === 0) {
364 1
                $name = substr($param->source, strlen('request.'));
365 1
                if ($route->hasPathParam($param->name)) {
366 1
                    $in = 'path';
367 1
                } elseif ($route->getMethod() == 'POST'
368 1
                    || $route->getMethod() == 'PUT'
369 1
                    || $route->getMethod() == 'PATCH'
370 1
                ) {
371 1
                    $in = $bodyType;
372 1
                } else {
373 1
                    $in = 'query';
374
                }
375 1
            }
376 1
            if ($in != 'body') {
377 1 View Code Duplication
                if ($param->container instanceof ArrayContainer) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
378 1
                    $paramSchema = $this->getArraySchema($app, $controller, $action, $route, $param->container);
379
                    //TODO array for validation
380 1
                } elseif ($param->container instanceof EntityContainer) {
381 1
                    $paramSchema = $this->getRefSchema($app, $controller, $action, $route, $param->container);
382
                    //TODO array for validation
383 1
                } else {
384 1
                    $paramSchema = new PrimitiveSchemaObject();
385 1
                    if($isFile){
386 1
                        $paramSchema->type = 'file';
387 1
                    }else{
388 1
                        $paramSchema->type = self::mapType($param->type);
389 1
                        self::mapValidation($param->validation, $paramSchema);
390
                    }
391
392
                }
393 1
                $paramSchema->in = $in;
394 1
                $paramSchema->name = $name;
395 1
                $paramSchema->description = $param->description;
396 1
                $paramSchema->default = $param->default;
397 1
                $paramSchema->required = !$param->isOptional;
398 1
                $parameters[] = $paramSchema;
399 1
            } else {
400 1
                if (!$name) {
401
                    $body = $param;
402
                } else {
403 1
                    ArrayHelper::set($body, $name, $param);
0 ignored issues
show
Bug introduced by
It seems like $body defined by $param on line 401 can also be of type object<PhpBoot\Metas\ParamMeta>; however, PhpBoot\Utils\ArrayHelper::set() does only seem to accept array|object<ArrayAccess>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
404
                }
405
406
            }
407 1
        }
408 1
        if ($body && $bodyType == 'body') {
409
410 1
            $paramSchema = new BodyParameterObject();
411 1
            $paramSchema->name = 'body';
412 1
            $paramSchema->in = 'body';
413 1
            if (is_array($body)) {
414 1
                $paramSchema->schema = $this->makeTempSchema($app, $controller, $action, $route, $body, 'Req');
415 1
            } else {
416
                $paramSchema->schema = $this->getAnySchema($app, $controller, $action, $route, $body->container);
417
            }
418
419 1
            $parameters[] = $paramSchema;
420 1
        }
421
422 1
        return $parameters;
423
    }
424
425
    /**
426
     * @param Application $app
427
     * @param ControllerContainer $controller
428
     * @param $action
429
     * @param Route $route
430
     * @param TypeContainerInterface $container
431
     * @return ArraySchemaObject|PrimitiveSchemaObject|RefSchemaObject
432
     */
433 1
    public function getAnySchema(Application $app, ControllerContainer $controller, $action, Route $route, $container)
434
    {
435 1
        if ($container instanceof EntityContainer) {
436 1
            $schema = $this->getRefSchema($app, $controller, $action, $route, $container);
437 1
        } elseif ($container instanceof ArrayContainer) {
438 1
            $schema = $this->getArraySchema($app, $controller, $action, $route, $container);
439 1
        } elseif ($container instanceof ScalarTypeContainer) {
440 1
            $schema = new PrimitiveSchemaObject();
441 1
            $schema->type = self::mapType($container->getType());
442 1
        } elseif($container == null){
443
            $schema = null ;//new PrimitiveSchemaObject();
444
            //$schema->type = null;
445
        }else {
446 1
            $schema = new PrimitiveSchemaObject();
447
            //$schema->type = 'mixed';
448
        }
449 1
        return $schema;
450
    }
451
452
    /**
453
     * @param Application $app
454
     * @param ControllerContainer $controller
455
     * @param $action
456
     * @param Route $route
457
     * @param ArrayContainer $container
458
     * @return ArraySchemaObject
459
     */
460 1
    public function getArraySchema(Application $app,
461
                                   ControllerContainer $controller,
462
                                   $action,
463
                                   Route $route,
464
                                   ArrayContainer $container)
465
    {
466 1
        $schema = new ArraySchemaObject();
467 1
        $itemContainer = $container->getContainer();
468 1
        if ($itemContainer instanceof EntityContainer) {
469 1
            $itemSchema = $this->getRefSchema($app, $controller, $action, $route, $itemContainer);
470 1
        } elseif ($itemContainer instanceof ArrayContainer) {
471
            $itemSchema = $this->getArraySchema($app, $controller, $action, $route, $itemContainer);
472 1
        } elseif ($itemContainer instanceof ScalarTypeContainer) {
473 1
            $itemSchema = new PrimitiveSchemaObject();
474 1
            $itemSchema->type = self::mapType($itemContainer->getType());
475 1
        } else {
476
            $itemSchema = new PrimitiveSchemaObject();
477
            //$itemSchema->type = 'mixed';
478
        }
479 1
        $schema->items = $itemSchema;
480 1
        return $schema;
481
    }
482
483 1
    public function getObjectSchema(Application $app,
484
                                    ControllerContainer $controller,
485
                                    $action,
486
                                    Route $route,
487
                                    EntityContainer $container)
488
    {
489 1
        $schema = new SimpleModelSchemaObject();
490 1
        $schema->description = self::implode("\n", [$container->getSummary(), $container->getDescription()]);
491
492 1
        foreach ($container->getProperties() as $property) {
493
494 1
            if (!$property->isOptional) {
495 1
                $schema->required[] = $property->name;
496 1
            }
497 1
            if ($property->container instanceof EntityContainer) {
498 1
                $propertySchema = $this->getRefSchema($app, $controller, $action, $route, $property->container);
499 1
            } elseif ($property->container instanceof ArrayContainer) {
500 1
                $propertySchema = $this->getArraySchema($app, $controller, $action, $route, $property->container);
501 1
            } else {
502 1
                $propertySchema = new PrimitiveSchemaObject();
503 1
                $propertySchema->type = self::mapType($property->type);
504 1
                $propertySchema->description = self::implode("\n", [$property->summary, $property->description]);
505 1
                self::mapValidation($property->validation, $propertySchema);
0 ignored issues
show
Bug introduced by
It seems like $property->validation can also be of type array; however, PhpBoot\Docgen\Swagger\Swagger::mapValidation() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
506 1
                unset($propertySchema->required);
507
            }
508 1
            $schema->properties[$property->name] = $propertySchema;
509 1
        }
510
511 1
        return $schema;
512
    }
513
514 1
    public function hasFileParam(Route $route)
515
    {
516 1
        $params = $route->getRequestHandler()->getParamMetas();
517 1
        foreach ($params as $name => $param) {
518 1
            if(strpos($param->source, 'request.files.')===0){
519 1
                return true;
520
            }
521 1
        }
522 1
        return false;
523
    }
524
    /**
525
     * @param string $v
526
     * @param PrimitiveSchemaObject $schemaObject
527
     * @return PrimitiveSchemaObject
528
     */
529 1
    static public function mapValidation($v, PrimitiveSchemaObject $schemaObject)
530
    {
531 1
        if(!$v){
532 1
            return $schemaObject;
533
        }
534 1
        $rules = explode('|', $v);
535 1
        foreach ($rules as $r) {
536 1
            $params = explode(':', trim($r));
537 1
            $rule = $params[0];
538 1
            $params = isset($params[1]) ? explode(',', $params[1]) : [];
539
540 1
            if ($rule == 'required') {
541
                $schemaObject->required = true;
542 1
            } elseif ($rule == 'in') {
543
                $schemaObject->enum = $params;
544 1
            } elseif ($rule == 'lengthBetween' && isset($params[0]) && isset($params[1])) {
545
                $schemaObject->minLength = intval($params[0]);
546
                $schemaObject->maxLength = intval($params[1]);
547 1
            } elseif ($rule == 'lengthMin'&& isset($params[0])) {
548
                $schemaObject->minLength = intval($params[0]);
549 1
            } elseif ($rule == 'lengthMax'&& isset($params[0])) {
550
                $schemaObject->maxLength = intval($params[0]);
551 1
            } elseif ($rule == 'min'&& isset($params[0])) {
552 1
                $schemaObject->minimum = floatval($params[0]);
0 ignored issues
show
Documentation Bug introduced by
The property $minimum was declared of type integer, but floatval($params[0]) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
553 1
            } elseif ($rule == 'max'&& isset($params[0])) {
554 1
                $schemaObject->maximum = floatval($params[0]);
0 ignored issues
show
Documentation Bug introduced by
The property $maximum was declared of type integer, but floatval($params[0]) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
555 1
            } elseif ($rule == 'regex'&& isset($params[0])) {
556
                $schemaObject->pattern = $params[0];
557
            } elseif ($rule == 'optional') {
558
                $schemaObject->required = false;
559
            }
560 1
        }
561 1
        return $schemaObject;
562
    }
563
564
    /**
565
     * @param string $type
566
     * @return string
567
     */
568 1
    static public function mapType($type)
569
    {
570
        //TODO 如何处理 file、mixed 类型
571
        $map = [
572 1
            'int' => 'integer',
573 1
            'bool' => 'boolean',
574 1
            'float' => 'number',
575 1
            'mixed' => null,
576 1
        ];
577 1
        if (array_key_exists($type, $map)) {
578 1
            return $map[$type];
579
        }
580 1
        return $type;
581
    }
582
583
    /**
584
     * @param $className
585
     * @return string
586
     */
587 1
    static public function getShortClassName($className)
588
    {
589 1
        $className = explode('\\', $className);
590 1
        $className = $className[count($className) - 1];
591 1
        return $className;
592
    }
593
594
    static public function implode($glue , array $pieces )
595
    {
596
        $pieces = array_filter($pieces, function($i){return trim($i) !== '';});
597 1
        return implode($glue, $pieces);
598
    }
599
}