PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/build/commands/api/ApiModel.php

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