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 | /** |
||
3 | * ApiModel class file. |
||
4 | * |
||
5 | * @author Qiang Xue <[email protected]> |
||
6 | * @link http://www.yiiframework.com/ |
||
7 | * @copyright 2008-2013 Yii Software LLC |
||
8 | * @license http://www.yiiframework.com/license/ |
||
9 | */ |
||
10 | |||
11 | /** |
||
12 | * ApiModel represents the documentation for the Yii framework. |
||
13 | * @author Qiang Xue <[email protected]> |
||
14 | * @package system.build |
||
15 | * @since 1.0 |
||
16 | */ |
||
17 | class ApiModel |
||
18 | { |
||
19 | public $classes=array(); |
||
20 | public $packages; |
||
21 | |||
22 | private $_currentClass; |
||
23 | |||
24 | public function build($sourceFiles) |
||
25 | { |
||
26 | $this->findClasses($sourceFiles); |
||
27 | $this->processClasses(); |
||
28 | } |
||
29 | |||
30 | /* |
||
31 | * Calls checkSource for every file in $sourceFiles |
||
32 | * @param array $sourceFiles array of source file path that we need to check |
||
33 | */ |
||
34 | public function check($sourceFiles) |
||
35 | { |
||
36 | echo "Checking PHPDoc @param in source files ...\n"; |
||
37 | foreach($sourceFiles as $no=>$sourceFile) |
||
38 | { |
||
39 | $this->checkSource($sourceFile); |
||
40 | } |
||
41 | echo "Done.\n\n"; |
||
42 | } |
||
43 | |||
44 | public function checkPackages($sourceFiles) |
||
45 | { |
||
46 | echo "Checking PHPDoc @package in source files ...\n"; |
||
47 | foreach($sourceFiles as $sourceFile) |
||
48 | { |
||
49 | $fileContent = file($sourceFile); |
||
50 | |||
51 | foreach($fileContent as $no=>$line) |
||
52 | { |
||
53 | if( preg_match('/^\s*\*\s*@package\s*([\w\.]+)/', $line, $matches, PREG_OFFSET_CAPTURE) ) |
||
54 | { |
||
55 | if( Yii::getPathOfAlias($matches[1][0]) == dirname($sourceFile)) |
||
56 | continue; |
||
57 | |||
58 | $docLine = $no + 1; |
||
59 | $docName = $matches[1][0]; |
||
60 | |||
61 | echo "ERROR.............: Package path not valid!\n"; |
||
62 | echo "Source file.......: ".$sourceFile."\n"; |
||
63 | echo "Parameter line....: ".$docLine."\n"; |
||
64 | echo "Parameter value....: ".$docName."\n\n"; |
||
65 | } |
||
66 | } |
||
67 | } |
||
68 | echo "Done.\n\n"; |
||
69 | } |
||
70 | |||
71 | protected function findClasses($sourceFiles) |
||
72 | { |
||
73 | $this->classes=array(); |
||
74 | |||
75 | foreach($sourceFiles as $file) |
||
76 | require_once($file); |
||
77 | |||
78 | $classes=array_merge(get_declared_classes(),get_declared_interfaces()); |
||
79 | foreach($classes as $class) |
||
80 | { |
||
81 | $r=new ReflectionClass($class); |
||
82 | if(in_array($r->getFileName(),$sourceFiles)) |
||
83 | $this->classes[$class]=true; |
||
84 | } |
||
85 | ksort($this->classes); |
||
86 | } |
||
87 | |||
88 | protected function processClasses() |
||
89 | { |
||
90 | $this->packages=array(); |
||
91 | foreach($this->classes as $class=>$value) |
||
92 | { |
||
93 | $doc=$this->processClass(new ReflectionClass($class)); |
||
94 | $this->classes[$class]=$doc; |
||
95 | $this->packages[$doc->package][]=$class; |
||
96 | } |
||
97 | ksort($this->packages); |
||
98 | |||
99 | // find out child classes for each class or interface |
||
100 | foreach($this->classes as $class) |
||
101 | { |
||
102 | if(isset($class->parentClasses[0])) |
||
103 | { |
||
104 | $parent=$class->parentClasses[0]; |
||
105 | if(isset($this->classes[$parent])) |
||
106 | $this->classes[$parent]->subclasses[]=$class->name; |
||
107 | } |
||
108 | foreach($class->interfaces as $interface) |
||
109 | { |
||
110 | if(isset($this->classes[$interface])) |
||
111 | $this->classes[$interface]->subclasses[]=$class->name; |
||
112 | } |
||
113 | } |
||
114 | } |
||
115 | |||
116 | protected function processClass($class) |
||
117 | { |
||
118 | $doc=new ClassDoc; |
||
119 | $doc->name=$class->getName(); |
||
120 | $doc->loadSource($class); |
||
121 | $this->_currentClass=$doc->name; |
||
122 | for($parent=$class;$parent=$parent->getParentClass();) |
||
123 | $doc->parentClasses[]=$parent->getName(); |
||
124 | foreach($class->getInterfaces() as $interface) |
||
125 | $doc->interfaces[]=$interface->getName(); |
||
126 | $doc->isInterface=$class->isInterface(); |
||
127 | $doc->isAbstract=$class->isAbstract(); |
||
128 | $doc->isFinal=$class->isFinal(); |
||
129 | $doc->methods=$this->processMethods($class); |
||
130 | $doc->properties=$this->processProperties($class); |
||
131 | $doc->signature=($doc->isInterface?'interface ':'class ').$doc->name; |
||
132 | if($doc->isFinal) |
||
133 | $doc->signature='final '.$doc->signature; |
||
134 | if($doc->isAbstract && !$doc->isInterface) |
||
135 | $doc->signature='abstract '.$doc->signature; |
||
136 | if(in_array('CComponent',$doc->parentClasses)) |
||
137 | { |
||
138 | $doc->properties=array_merge($doc->properties,$this->processComponentProperties($class)); |
||
139 | $doc->events=$this->processComponentEvents($class); |
||
140 | } |
||
141 | ksort($doc->properties); |
||
142 | |||
143 | foreach($doc->properties as $property) |
||
144 | { |
||
145 | if($property->isProtected) |
||
146 | $doc->protectedPropertyCount++; |
||
147 | else |
||
148 | $doc->publicPropertyCount++; |
||
149 | if(!$property->isInherited) |
||
150 | $doc->nativePropertyCount++; |
||
151 | } |
||
152 | foreach($doc->methods as $method) |
||
153 | { |
||
154 | if($method->isProtected) |
||
155 | $doc->protectedMethodCount++; |
||
156 | else |
||
157 | $doc->publicMethodCount++; |
||
158 | if(!$method->isInherited) |
||
159 | $doc->nativeMethodCount++; |
||
160 | } |
||
161 | foreach($doc->events as $event) |
||
162 | { |
||
163 | if(!$event->isInherited) |
||
164 | $doc->nativeEventCount++; |
||
165 | } |
||
166 | $this->processComment($doc,$class->getDocComment()); |
||
167 | |||
168 | return $doc; |
||
169 | } |
||
170 | |||
171 | protected function processComment($doc,$comment) |
||
172 | { |
||
173 | $comment = strtr(trim(preg_replace('/^\s*\**( |\t)?/m','',trim($comment,'/'))),"\r",''); |
||
174 | |||
175 | if( preg_match_all('/^\s*@(author|link|copyright|license|package).*/m',$comment ,$matches) ) |
||
176 | { |
||
177 | $comment = strtr(trim(preg_replace('/^\s*@(author|link|copyright|license|package).*$/m', '', $comment)),"\r",''); |
||
178 | $comment .= "\n"; |
||
179 | foreach($matches[0] as $meta) |
||
180 | $comment .= $meta."\n"; |
||
181 | } |
||
182 | |||
183 | if(preg_match('/^\s*@\w+/m',$comment,$matches,PREG_OFFSET_CAPTURE)) |
||
184 | { |
||
185 | $meta=substr($comment,$matches[0][1]); |
||
186 | $comment=trim(substr($comment,0,$matches[0][1])); |
||
187 | } |
||
188 | else |
||
189 | $meta=''; |
||
190 | if(($pos=strpos($comment,"\n"))!==false) |
||
191 | $doc->introduction=$this->processDescription(substr($comment,0,$pos)); |
||
192 | else |
||
193 | $doc->introduction=$this->processDescription($comment); |
||
194 | |||
195 | $doc->description=$this->processDescription($comment); |
||
196 | |||
197 | $this->processTags($doc,$meta); |
||
198 | } |
||
199 | |||
200 | protected function processDescription($text) |
||
201 | { |
||
202 | if(($text=trim($text))==='') |
||
203 | return ''; |
||
204 | $text=preg_replace_callback('/\{@include\s+([^\s\}]+)\s*\}/s',array($this,'processInclude'),$text); |
||
205 | $text=preg_replace('/^(\r| |\t)*$/m',"<br/><br/>",$text); |
||
206 | $text=preg_replace_callback('/<pre>(.*?)<\/pre>/is',array($this,'processCode'),$text); |
||
207 | $text=preg_replace_callback('/\{@link\s+([^\s\}]+)(.*?)\}/s',array($this,'processLink'),$text); |
||
208 | return $text; |
||
209 | } |
||
210 | |||
211 | protected function processCode($matches) |
||
212 | { |
||
213 | $match=preg_replace('/<br\/><br\/>/','',$matches[1]); |
||
214 | return "<pre>".htmlspecialchars($match)."</pre>"; |
||
215 | } |
||
216 | |||
217 | protected function resolveInternalUrl($url) |
||
218 | { |
||
219 | $url=rtrim($url,'()'); |
||
220 | if(($pos=strpos($url,'::'))!==false) |
||
221 | { |
||
222 | $class=substr($url,0,$pos); |
||
223 | $method=substr($url,$pos+2); |
||
224 | } |
||
225 | else if(isset($this->classes[$url])) |
||
226 | return $url; |
||
227 | else |
||
228 | { |
||
229 | $class=$this->_currentClass; |
||
230 | $method=$url; |
||
231 | } |
||
232 | return $this->getMethodUrl($class,$method); |
||
233 | } |
||
234 | |||
235 | protected function getMethodUrl($class,$method) |
||
236 | { |
||
237 | if(!isset($this->classes[$class])) |
||
238 | return ''; |
||
239 | View Code Duplication | if(method_exists($class,$method) || property_exists($class,$method)) |
|
0 ignored issues
–
show
|
|||
240 | return $class.'::'.$method; |
||
241 | View Code Duplication | if(method_exists($class,'get'.$method) || method_exists($class,'set'.$method)) |
|
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. ![]() |
|||
242 | return $class.'::'.$method; |
||
243 | if(($parent=get_parent_class($class))!==false) |
||
244 | return $this->getMethodUrl($parent,$method); |
||
245 | else |
||
246 | return ''; |
||
247 | } |
||
248 | |||
249 | protected function processLink($matches) |
||
250 | { |
||
251 | $url=$matches[1]; |
||
252 | if(($text=trim($matches[2]))==='') |
||
253 | $text=$url; |
||
254 | |||
255 | if(preg_match('/^(http|ftp):\/\//i',$url)) // an external URL |
||
256 | return "<a href=\"$url\">$text</a>"; |
||
257 | $url=$this->resolveInternalUrl($url); |
||
258 | return $url===''?$text:'{{'.$url.'|'.$text.'}}'; |
||
259 | } |
||
260 | |||
261 | protected function processInclude($matches) |
||
262 | { |
||
263 | $class=new ReflectionClass($this->_currentClass); |
||
264 | $fileName=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$matches[1]; |
||
265 | if(is_file($fileName)) |
||
266 | return file_get_contents($fileName); |
||
267 | else |
||
268 | return $matches[0]; |
||
269 | } |
||
270 | |||
271 | protected function processTags($object,$comment) |
||
272 | { |
||
273 | $tags=preg_split('/^\s*@/m',$comment,-1,PREG_SPLIT_NO_EMPTY); |
||
274 | foreach($tags as $tag) |
||
275 | { |
||
276 | $segs=preg_split('/\s+/',trim($tag),2); |
||
277 | $tagName=$segs[0]; |
||
278 | $param=isset($segs[1])?trim($segs[1]):''; |
||
279 | $tagMethod='tag'.ucfirst($tagName); |
||
280 | if(method_exists($this,$tagMethod)) |
||
281 | $this->$tagMethod($object,$param); |
||
282 | else if(property_exists($object,$tagName)) |
||
283 | $object->$tagName=$param; |
||
284 | } |
||
285 | } |
||
286 | |||
287 | protected function processMethods($class) |
||
288 | { |
||
289 | $methods=array(); |
||
290 | foreach($class->getMethods() as $method) |
||
291 | { |
||
292 | if($method->isPublic() || $method->isProtected()) |
||
293 | { |
||
294 | $doc=$this->processMethod($class,$method); |
||
295 | $methods[$doc->name]=$doc; |
||
296 | } |
||
297 | } |
||
298 | ksort($methods); |
||
299 | return $methods; |
||
300 | } |
||
301 | |||
302 | protected function processMethod($class,$method) |
||
303 | { |
||
304 | $doc=new MethodDoc; |
||
305 | $doc->name=$method->getName(); |
||
306 | $doc->loadSource($method); |
||
307 | $doc->definedBy=$method->getDeclaringClass()->getName(); |
||
308 | $doc->isAbstract=$method->isAbstract(); |
||
309 | $doc->isFinal=$method->isFinal(); |
||
310 | $doc->isProtected=$method->isProtected(); |
||
311 | $doc->isStatic=$method->isStatic(); |
||
312 | $doc->isInherited=$doc->definedBy!==$class->getName(); |
||
313 | |||
314 | $doc->input=array(); |
||
315 | foreach($method->getParameters() as $param) |
||
316 | { |
||
317 | $p=new ParamDoc; |
||
318 | $p->name=$param->getName(); |
||
319 | $p->isOptional=$param->isOptional(); |
||
320 | if($param->isDefaultValueAvailable()) |
||
321 | $p->defaultValue=$param->getDefaultValue(); |
||
322 | $p->isPassedByReference=$param->isPassedByReference(); |
||
323 | $doc->input[]=$p; |
||
324 | } |
||
325 | reset($doc->input); |
||
326 | |||
327 | $this->processComment($doc,$method->getDocComment()); |
||
328 | |||
329 | $params=array(); |
||
330 | foreach($doc->input as $param) |
||
331 | { |
||
332 | $type=empty($param->type)?'':$this->getTypeUrl($param->type).' '; |
||
333 | if($param->isOptional) |
||
334 | $params[]=$type.($param->isPassedByReference?'&':'').'$'.$param->name.'='.str_replace("\r",'',var_export($param->defaultValue,true)); |
||
335 | else |
||
336 | $params[]=$type.($param->isPassedByReference?'&':'').'$'.$param->name; |
||
337 | } |
||
338 | $doc->signature='{{'.$class->name.'::'.$doc->name.'|<b>'.$doc->name.'</b>}}('.implode(', ',$params).')'; |
||
339 | if($doc->output!==null) |
||
340 | $doc->signature=$this->getTypeUrl($doc->output->type).' '.$doc->signature; |
||
341 | else |
||
342 | $doc->signature='void '.$doc->signature; |
||
343 | View Code Duplication | if(($modifier=implode(' ',Reflection::getModifierNames($method->getModifiers())))!=='') |
|
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. ![]() |
|||
344 | $doc->signature=$modifier.' '.$doc->signature; |
||
345 | |||
346 | return $doc; |
||
347 | } |
||
348 | |||
349 | View Code Duplication | protected function getTypeUrl($type) |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
350 | { |
||
351 | if(isset($this->classes[$type]) && $type!==$this->_currentClass) |
||
352 | return '{{'.$type.'|'.$type.'}}'; |
||
353 | else |
||
354 | return $type; |
||
355 | } |
||
356 | |||
357 | protected function processProperties($class) |
||
358 | { |
||
359 | $properties=array(); |
||
360 | foreach($class->getProperties() as $property) |
||
361 | { |
||
362 | if($property->isPublic() || $property->isProtected()) |
||
363 | { |
||
364 | $p=$this->processProperty($class,$property); |
||
365 | $properties[$p->name]=$p; |
||
366 | } |
||
367 | } |
||
368 | return $properties; |
||
369 | } |
||
370 | |||
371 | protected function processProperty($class,$property) |
||
372 | { |
||
373 | $doc=new PropertyDoc; |
||
374 | $doc->name=$property->getName(); |
||
375 | $doc->definedBy=$property->getDeclaringClass()->getName(); |
||
376 | $doc->readOnly=false; |
||
377 | $doc->isStatic=$property->isStatic(); |
||
378 | $doc->isProtected=$property->isProtected(); |
||
379 | $doc->isInherited=$doc->definedBy!==$class->getName(); |
||
380 | |||
381 | $this->processComment($doc,$property->getDocComment()); |
||
382 | |||
383 | $doc->signature='<b>$'.$doc->name.'</b>;'; |
||
384 | if($doc->type!==null) |
||
385 | $doc->signature=$this->getTypeUrl($doc->type) . ' ' . $doc->signature; |
||
386 | View Code Duplication | if(($modifier=implode(' ',Reflection::getModifierNames($property->getModifiers())))!=='') |
|
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. ![]() |
|||
387 | $doc->signature=$modifier.' '.$doc->signature; |
||
388 | |||
389 | return $doc; |
||
390 | } |
||
391 | |||
392 | View Code Duplication | protected function processComponentProperties($class) |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
393 | { |
||
394 | $properties=array(); |
||
395 | foreach($class->getMethods() as $method) |
||
396 | { |
||
397 | if($this->isPropertyMethod($method) && ($method->isPublic() || $method->isProtected())) |
||
398 | { |
||
399 | $p=$this->processComponentProperty($class,$method); |
||
400 | $properties[$p->name]=$p; |
||
401 | } |
||
402 | } |
||
403 | return $properties; |
||
404 | } |
||
405 | |||
406 | protected function processComponentProperty($class,$method) |
||
407 | { |
||
408 | $doc=new PropertyDoc; |
||
409 | $name=$method->getName(); |
||
410 | $doc->name=strtolower($name[3]).substr($name,4); |
||
411 | $doc->isProtected=$method->isProtected(); |
||
412 | $doc->isStatic=false; |
||
413 | $doc->readOnly=!$class->hasMethod('set'.substr($name,3)); |
||
414 | $doc->definedBy=$method->getDeclaringClass()->getName(); |
||
415 | $doc->isInherited=$doc->definedBy!==$class->getName(); |
||
416 | $doc->getter=$this->processMethod($class,$method); |
||
417 | if(!$doc->readOnly) |
||
418 | $doc->setter=$this->processMethod($class,$class->getMethod('set'.substr($name,3))); |
||
419 | |||
420 | $this->processComment($doc,$method->getDocComment()); |
||
421 | |||
422 | return $doc; |
||
423 | } |
||
424 | |||
425 | View Code Duplication | protected function processComponentEvents($class) |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
426 | { |
||
427 | $events=array(); |
||
428 | foreach($class->getMethods() as $method) |
||
429 | { |
||
430 | if($this->isEventMethod($method) && ($method->isPublic() || $method->isProtected())) |
||
431 | { |
||
432 | $e=$this->processComponentEvent($class,$method); |
||
433 | $events[$e->name]=$e; |
||
434 | } |
||
435 | } |
||
436 | return $events; |
||
437 | } |
||
438 | |||
439 | protected function processComponentEvent($class,$method) |
||
440 | { |
||
441 | $doc=new EventDoc; |
||
442 | $doc->name=$method->getName(); |
||
443 | $doc->definedBy=$method->getDeclaringClass()->getName(); |
||
444 | $doc->isInherited=$doc->definedBy!==$class->getName(); |
||
445 | $doc->trigger=$this->processMethod($class,$method); |
||
446 | |||
447 | $this->processComment($doc,$method->getDocComment()); |
||
448 | |||
449 | return $doc; |
||
450 | } |
||
451 | |||
452 | protected function tagParam($object,$comment) |
||
453 | { |
||
454 | if($object instanceof FunctionDoc) |
||
455 | { |
||
456 | $param=current($object->input); |
||
457 | if($param!==false) |
||
458 | { |
||
459 | $segs=preg_split('/\s+/',$comment,2); |
||
460 | $param->type=$segs[0]; |
||
461 | if(preg_match('/\[\s*\]/',$param->type)) |
||
462 | $param->type='array'; |
||
463 | if(isset($segs[1])) |
||
464 | { |
||
465 | /* |
||
466 | * remove $variablename from description |
||
467 | */ |
||
468 | $segs[1]=trim(preg_replace('/^\$\w+/','',$segs[1])); |
||
469 | $param->description=$this->processDescription($segs[1]); |
||
470 | View Code Duplication | if(empty($object->introduction)) |
|
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. ![]() |
|||
471 | { |
||
472 | if(substr($object->name,0,3)=='set') |
||
473 | $object->introduction='Sets '.$param->description; |
||
474 | } |
||
475 | } |
||
476 | next($object->input); |
||
477 | } |
||
478 | } |
||
479 | } |
||
480 | |||
481 | protected function tagReturn($object,$comment) |
||
482 | { |
||
483 | $segs=preg_split('/\s+/',$comment,2); |
||
484 | if($object instanceof FunctionDoc) |
||
485 | { |
||
486 | $object->output=new ParamDoc; |
||
487 | $object->output->type=$segs[0]; |
||
488 | if(isset($segs[1])) |
||
489 | { |
||
490 | $object->output->description=$this->processDescription($segs[1]); |
||
491 | if(empty($object->introduction)) |
||
492 | { |
||
493 | /* |
||
494 | * If no custom introduction, add automatically |
||
495 | * with this getters introduction displayed in public methods table is resolved |
||
496 | */ |
||
497 | if(substr($object->name,0,5)=='getIs') |
||
498 | $object->introduction='Checks '.$object->output->description; |
||
499 | View Code Duplication | elseif(substr($object->name,0,3)=='get') |
|
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. ![]() |
|||
500 | $object->introduction='Returns '.$object->output->description; |
||
501 | View Code Duplication | elseif(substr($object->name,0,3)=='has') |
|
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. ![]() |
|||
502 | $object->introduction='Determines '.$object->output->description; |
||
503 | } |
||
504 | } |
||
505 | } |
||
506 | else if($object instanceof PropertyDoc) |
||
507 | { |
||
508 | $object->type=$segs[0]; |
||
509 | View Code Duplication | if(isset($segs[1]) && empty($object->description)) |
|
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. ![]() |
|||
510 | { |
||
511 | if(($pos=strpos($segs[1],'.'))!==false) |
||
512 | $object->introduction=$this->processDescription(substr($segs[1],0,$pos+1)); |
||
513 | else |
||
514 | $object->introduction=$this->processDescription($segs[1]); |
||
515 | $object->description=$this->processDescription($segs[1]); |
||
516 | } |
||
517 | } |
||
518 | } |
||
519 | |||
520 | protected function tagVar($object,$comment) |
||
521 | { |
||
522 | if($object instanceof PropertyDoc) |
||
523 | { |
||
524 | $segs=preg_split('/\s+/',$comment,2); |
||
525 | $object->type=$segs[0]; |
||
526 | View Code Duplication | if(isset($segs[1]) && empty($object->description)) |
|
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. ![]() |
|||
527 | { |
||
528 | if(($pos=strpos($segs[1],'.'))!==false) |
||
529 | $object->introduction=$this->processDescription(substr($segs[1],0,$pos+1)); |
||
530 | else |
||
531 | $object->introduction=$this->processDescription($segs[1]); |
||
532 | $object->description=$this->processDescription($segs[1]); |
||
533 | } |
||
534 | } |
||
535 | } |
||
536 | |||
537 | protected function tagSee($object,$comment) |
||
538 | { |
||
539 | $segs=preg_split('/\s+/',trim($comment),2); |
||
540 | $matches[1]=$segs[0]; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$matches was never initialized. Although not strictly required by PHP, it is generally a good practice to add $matches = 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 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. ![]() |
|||
541 | $matches[2]=isset($segs[1])?$segs[1]:''; |
||
542 | $object->see[]=$this->processLink($matches); |
||
543 | } |
||
544 | |||
545 | View Code Duplication | protected function isPropertyMethod($method) |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
546 | { |
||
547 | $methodName=$method->getName(); |
||
548 | return $method->getNumberOfRequiredParameters()===0 |
||
549 | && !$method->isStatic() |
||
550 | && strncasecmp($methodName,'get',3)===0 |
||
551 | && isset($methodName[3]); |
||
552 | } |
||
553 | |||
554 | View Code Duplication | protected function isEventMethod($method) |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
555 | { |
||
556 | $methodName=$method->getName(); |
||
557 | return strncasecmp($methodName,'on',2)===0 |
||
558 | && !$method->isStatic() |
||
559 | && isset($methodName[2]); |
||
560 | } |
||
561 | |||
562 | protected function getClassFiles($basePath) |
||
563 | { |
||
564 | $files=array(); |
||
565 | $folder=opendir($basePath); |
||
566 | while($file=readdir($folder)) |
||
567 | { |
||
568 | if($file==='.' || $file==='..') |
||
569 | continue; |
||
570 | $fullPath=realpath($basePath.DIRECTORY_SEPARATOR.$file); |
||
571 | if($this->isValidPath($fullPath)) |
||
572 | { |
||
573 | if(is_file($fullPath)) |
||
574 | $files[]=$fullPath; |
||
575 | else |
||
576 | $files=array_merge($files,$this->getClassFiles($fullPath)); |
||
577 | } |
||
578 | } |
||
579 | closedir($folder); |
||
580 | return $files; |
||
581 | } |
||
582 | |||
583 | protected function isValidPath($path) |
||
584 | { |
||
585 | if(is_file($path) && substr($path,-4)!=='.php') |
||
586 | return false; |
||
587 | $path=strtr($path,'\\','/'); |
||
588 | foreach($this->_excludes as $exclude) |
||
0 ignored issues
–
show
The property
_excludes does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
589 | { |
||
590 | if(($exclude[0]==='/' && $this->_sourcePath.$exclude===$path) || ($exclude[0]!=='/' && basename($path)===$exclude)) |
||
0 ignored issues
–
show
The property
_sourcePath does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
591 | return false; |
||
592 | } |
||
593 | return true; |
||
594 | } |
||
595 | |||
596 | protected function findTargets() |
||
597 | { |
||
598 | $oldClasses=get_declared_classes(); |
||
599 | $oldInterfaces=get_declared_interfaces(); |
||
600 | $oldFunctions=get_defined_functions(); |
||
601 | $oldConstants=get_defined_constants(true); |
||
0 ignored issues
–
show
$oldConstants is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
602 | |||
603 | $classFiles=$this->getClassFiles($this->_sourcePath); |
||
604 | require_once($this->_sourcePath.'/yii.php'); |
||
605 | foreach($classFiles as $classFile) |
||
606 | require_once($classFile); |
||
607 | |||
608 | $classes=array_values(array_diff(get_declared_classes(),$oldClasses)); |
||
609 | $interfaces=array_values(array_diff(get_declared_interfaces(),$oldInterfaces)); |
||
610 | $classes=array_merge($classes,$interfaces); |
||
611 | |||
612 | $n=count($classes); |
||
613 | for($i=0;$i<$n;++$i) |
||
614 | { |
||
615 | $class=new ReflectionClass($classes[$i]); |
||
616 | $fileName=strtr($class->getFileName(),'\\','/'); |
||
617 | foreach($this->_excludes as $exclude) |
||
618 | { |
||
619 | if(($exclude[0]==='/' && strpos($fileName,$this->_sourcePath.$exclude)===0)) |
||
620 | { |
||
621 | unset($classes[$i]); |
||
622 | break; |
||
623 | } |
||
624 | } |
||
625 | } |
||
626 | |||
627 | sort($classes); |
||
628 | $newFunctions=get_defined_functions(); |
||
629 | $newConstants=get_defined_constants(true); |
||
630 | $functions=array_values(array_diff($newFunctions['user'],$oldFunctions['user'])); |
||
631 | $constants=$newConstants['user']; |
||
632 | |||
633 | return array($classes,$functions,$constants); |
||
634 | } |
||
635 | |||
636 | /* |
||
637 | * Checks @param directives in a source file |
||
638 | * Detects: |
||
639 | * missing @param directive (there is no @param directive for a function parameter) |
||
640 | * missing function parameter (@param directive exists but that parameter is not in a function declaration) |
||
641 | * missmatch parameters (if @param directive has different parameter name than a function - possible spelling error or wrong order of @param directives) |
||
642 | */ |
||
643 | protected function checkSource($sourceFile) |
||
644 | { |
||
645 | $fileContent=file($sourceFile); |
||
646 | |||
647 | $docParam=array(); |
||
648 | foreach($fileContent as $no=>$line) |
||
649 | { |
||
650 | /* |
||
651 | * Get lines with @param, and parameter name |
||
652 | */ |
||
653 | if(preg_match('/^\s*\*\s*@param\s[A-Za-z0-9_\|\[\]]+\s(\$\w+)\s./',$line,$matches,PREG_OFFSET_CAPTURE)) |
||
654 | { |
||
655 | $docParam[]=array( |
||
656 | 'docLine'=>$no+1, |
||
657 | 'docName'=>$matches[1][0], |
||
658 | ); |
||
659 | continue; |
||
660 | } |
||
661 | /* |
||
662 | * If function without parameters, there should be no parameters in $docParam |
||
663 | */ |
||
664 | if(preg_match('/^\s*\w+[\s\w]*\sfunction\s\w+\(\s*\)/',$line,$matches,PREG_OFFSET_CAPTURE)) |
||
665 | { |
||
666 | if(isset($docParam[0])) { |
||
667 | $value=$docParam[0]; |
||
668 | echo "ERROR.............: Parameter name not found!\n"; |
||
669 | echo "Source file.......: ".$sourceFile."\n"; |
||
670 | echo "PHPDoc line.......: ".$value['docLine']."\n"; |
||
671 | echo "PHPDoc parameter..: ".$value['docName']."\n\n"; |
||
672 | $docParam=array(); |
||
673 | } |
||
674 | continue; |
||
675 | } |
||
676 | /* |
||
677 | * Get function variables in $matches[1][0] |
||
678 | */ |
||
679 | if(preg_match('/^\s*\w+[\s\w]*\sfunction\s\w+\((.+)\)/',$line,$matches,PREG_OFFSET_CAPTURE)) |
||
680 | { |
||
681 | $params=explode(",",$matches[1][0]); |
||
682 | foreach($params as $br=>$param) |
||
683 | { |
||
684 | /* |
||
685 | * Strip anything that does not begin with $ (class types) eg. CHttpRequest $request |
||
686 | */ |
||
687 | $param=preg_replace('/^\w+/','',trim($param)); |
||
688 | /* |
||
689 | * Strip default value if exists ex. data=array() (with spaces) |
||
690 | */ |
||
691 | $param=preg_replace('/\s*=.+/','',trim($param)); |
||
692 | /* |
||
693 | * Strip & if pass by reference |
||
694 | */ |
||
695 | if($param[0]=='&') |
||
696 | $param=substr($param,1); |
||
697 | /* |
||
698 | * add parameter info to the docParam array |
||
699 | */ |
||
700 | $docParam[$br]['parameterName']=$param; |
||
701 | $docParam[$br]['parameterLine']=$no+1; |
||
702 | } |
||
703 | |||
704 | /* |
||
705 | * All info gathered, let's make some checking |
||
706 | */ |
||
707 | foreach($docParam as $value) |
||
708 | { |
||
709 | View Code Duplication | if(!isset($value['docLine']) || !isset($value['docName']) && isset($value['parameterName'])) |
|
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. ![]() |
|||
710 | { |
||
711 | echo "ERROR.............: Documentation not found!\n"; |
||
712 | echo "Source file.......: ".$sourceFile."\n"; |
||
713 | echo "Parameter line....: ".$value['parameterLine']."\n"; |
||
714 | echo "Parameter name....: ".$value['parameterName']."\n\n"; |
||
715 | } |
||
716 | View Code Duplication | if(!isset($value['parameterName']) || !isset($value['parameterLine'])) |
|
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. ![]() |
|||
717 | { |
||
718 | echo "ERROR.............: Parameter name not found!\n"; |
||
719 | echo "Source file.......: ".$sourceFile."\n"; |
||
720 | echo "PHPDoc line.......: ".$value['docLine']."\n"; |
||
721 | echo "PHPDoc parameter..: ".$value['docName']."\n\n"; |
||
722 | } |
||
723 | if( isset($value['docName']) && isset($value['parameterName']) && $value['docName']!==$value['parameterName']) |
||
724 | { |
||
725 | echo "ERROR.............: Wrong parameter order!\n"; |
||
726 | echo "Source file.......: ".$sourceFile."\n"; |
||
727 | echo "PHPDoc line.......: ".$value['docLine']."\n"; |
||
728 | echo "PHPDoc parameter..: ".$value['docName']."\n"; |
||
729 | echo "Parameter line....: ".$value['parameterLine']."\n"; |
||
730 | echo "Parameter name....: ".$value['parameterName']."\n\n"; |
||
731 | } |
||
732 | } |
||
733 | /* |
||
734 | * reset $docParam |
||
735 | */ |
||
736 | $docParam=array(); |
||
737 | } |
||
738 | } |
||
739 | } |
||
740 | } |
||
741 | |||
742 | class BaseDoc |
||
743 | { |
||
744 | public $name; |
||
745 | public $since; |
||
746 | public $see; |
||
747 | public $introduction; |
||
748 | public $description; |
||
749 | |||
750 | public $sourcePath; |
||
751 | public $startLine; |
||
752 | public $endLine; |
||
753 | |||
754 | public function loadSource($reflection) |
||
755 | { |
||
756 | $this->sourcePath=str_replace('\\','/',str_replace(Yii::getPathOfAlias('basePath').DIRECTORY_SEPARATOR,'',$reflection->getFileName())); |
||
757 | $this->startLine=$reflection->getStartLine(); |
||
758 | $this->endLine=$reflection->getEndLine(); |
||
759 | } |
||
760 | |||
761 | public function getSourceUrl($baseUrl,$line=null) |
||
762 | { |
||
763 | if($line===null) |
||
764 | return $baseUrl.$this->sourcePath; |
||
765 | else |
||
766 | return $baseUrl.$this->sourcePath.'#'.$line; |
||
767 | } |
||
768 | |||
769 | public function getSourceCode() |
||
770 | { |
||
771 | $lines=file($this->sourcePath); |
||
772 | return implode("",array_slice($lines,$this->startLine-1,$this->endLine-$this->startLine+1)); |
||
773 | } |
||
774 | } |
||
775 | |||
776 | class ClassDoc extends BaseDoc |
||
777 | { |
||
778 | public $parentClasses=array(); |
||
779 | public $subclasses=array(); |
||
780 | public $interfaces=array(); |
||
781 | public $isInterface; |
||
782 | public $isAbstract; |
||
783 | public $isFinal; |
||
784 | |||
785 | public $signature; |
||
786 | |||
787 | public $properties=array(); |
||
788 | public $methods=array(); |
||
789 | public $events=array(); |
||
790 | public $constants=array(); |
||
791 | |||
792 | public $protectedPropertyCount=0; |
||
793 | public $publicPropertyCount=0; |
||
794 | public $protectedMethodCount=0; |
||
795 | public $publicMethodCount=0; |
||
796 | |||
797 | public $nativePropertyCount=0; |
||
798 | public $nativeMethodCount=0; |
||
799 | public $nativeEventCount=0; |
||
800 | |||
801 | public $package; |
||
802 | public $version; |
||
803 | } |
||
804 | |||
805 | class PropertyDoc extends BaseDoc |
||
806 | { |
||
807 | public $isProtected; |
||
808 | public $isStatic; |
||
809 | public $readOnly; |
||
810 | public $isInherited; |
||
811 | public $definedBy; |
||
812 | |||
813 | public $type; |
||
814 | public $signature; |
||
815 | |||
816 | public $getter; |
||
817 | public $setter; |
||
818 | } |
||
819 | |||
820 | class FunctionDoc extends BaseDoc |
||
821 | { |
||
822 | public $signature; |
||
823 | public $input=array(); |
||
824 | public $output; |
||
825 | } |
||
826 | |||
827 | class MethodDoc extends FunctionDoc |
||
828 | { |
||
829 | public $isAbstract; |
||
830 | public $isFinal; |
||
831 | public $isProtected; |
||
832 | public $isStatic; |
||
833 | public $isInherited; |
||
834 | public $definedBy; |
||
835 | } |
||
836 | |||
837 | class EventDoc extends BaseDoc |
||
838 | { |
||
839 | public $isInherited; |
||
840 | public $definedBy; |
||
841 | public $trigger; |
||
842 | } |
||
843 | |||
844 | class ParamDoc |
||
845 | { |
||
846 | public $name; |
||
847 | public $description; |
||
848 | public $type; |
||
849 | public $isOptional; |
||
850 | public $defaultValue; |
||
851 | public $isPassedByReference; |
||
852 | } |
||
853 |
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.