This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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
|
|||
127 | $action, |
||
0 ignored issues
–
show
|
|||
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
|
|||
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
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. ![]() |
|||
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
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);
}
}
![]() |
|||
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
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);
}
}
![]() |
|||
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
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. ![]() |
|||
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
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. ![]() |
|||
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
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. ![]() |
|||
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
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. ![]() |
|||
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
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. ![]() |
|||
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
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. ![]() |
|||
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
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;
![]() |
|||
553 | 1 | } elseif ($rule == 'max'&& isset($params[0])) { |
|
554 | 1 | $schemaObject->maximum = floatval($params[0]); |
|
0 ignored issues
–
show
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;
![]() |
|||
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 | } |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.