Carsten Brandt
11 years ago
1 changed files with 149 additions and 0 deletions
@ -0,0 +1,149 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\build\controllers; |
||||
|
||||
use yii\console\Controller; |
||||
use yii\helpers\Console; |
||||
|
||||
/** |
||||
* PhpDocController is there to help maintaining PHPDoc annotation in class files |
||||
* @author Carsten Brandt <mail@cebe.cc> |
||||
* @author Alexander Makarov <sam@rmcreative.ru> |
||||
* @since 2.0 |
||||
*/ |
||||
class PhpDocController extends Controller |
||||
{ |
||||
/** |
||||
* Generates @property annotations in class files from getters and setters |
||||
* |
||||
* @param string $directory the directory to parse files from |
||||
* @param boolean $updateFiles whether to update class docs directly |
||||
*/ |
||||
public function actionProperty($directory=null, $updateFiles=false) |
||||
{ |
||||
if ($directory === null) { |
||||
$directory = dirname(dirname(__DIR__)) . '/framework/yii'; |
||||
} |
||||
|
||||
$nFilesTotal = 0; |
||||
$files = new \RegexIterator( |
||||
new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory)), |
||||
'#^.+\.php$#i', |
||||
\RecursiveRegexIterator::GET_MATCH |
||||
); |
||||
foreach ($files as $file) { |
||||
list($className, $phpdoc) = $this->generateClassPropertyDocs($file[0]); |
||||
if ($phpdoc !== false) { |
||||
if ($updateFiles) { |
||||
$this->updateClassPropertyDocs($file[0], $className, $phpdoc); |
||||
} else { |
||||
$this->stdout("\n[ " . $file[0] . " ]\n\n", Console::BOLD); |
||||
$this->stdout($phpdoc . "\n"); |
||||
} |
||||
} |
||||
$nFilesTotal++; |
||||
} |
||||
|
||||
$this->stdout("\n\nParsed $nFilesTotal files.\n"); |
||||
} |
||||
|
||||
protected function updateClassPropertyDocs($file, $className, $phpDoc) |
||||
{ |
||||
// TODO implement |
||||
} |
||||
|
||||
protected function generateClassPropertyDocs($fileName) |
||||
{ |
||||
$phpdoc = ""; |
||||
$file = str_replace("\r", "", str_replace("\t", " ", file_get_contents($fileName, true))); |
||||
$ns = $this->match('#\nnamespace (?<name>[\w\\\\]+);\n#', $file); |
||||
$namespace = reset($ns); |
||||
$namespace = $namespace['name']; |
||||
$classes = $this->match('#\n(?:abstract )?class (?<name>\w+) extends .+\{(?<content>.+)\n\}(\n|$)#', $file); |
||||
|
||||
if (count($classes) > 1) { |
||||
$this->stderr("[ERR] There should be only one class in a file: $fileName\n", Console::FG_RED); |
||||
return false; |
||||
} |
||||
if (count($classes) < 1) { |
||||
$this->stderr("[ERR] No class in file: $fileName\n", Console::FG_RED); |
||||
return false; |
||||
} |
||||
|
||||
$className = null; |
||||
foreach ($classes as &$class) { |
||||
|
||||
$className = $namespace . '\\' . $class['name']; |
||||
|
||||
$gets = $this->match( |
||||
'#\* @return (?<type>\w+)(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' . |
||||
'[\s\n]{2,}public function (?<kind>get)(?<name>\w+)\((?:,? ?\$\w+ ?= ?[^,]+)*\)#', |
||||
$class['content']); |
||||
$sets = $this->match( |
||||
'#\* @param (?<type>\w+) \$\w+(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' . |
||||
'[\s\n]{2,}public function (?<kind>set)(?<name>\w+)\(\$\w+(?:, ?\$\w+ ?= ?[^,]+)*\)#', |
||||
$class['content']); |
||||
$acrs = array_merge($gets, $sets); |
||||
//print_r($acrs); continue; |
||||
|
||||
$props = array(); |
||||
foreach ($acrs as &$acr) { |
||||
$acr['name'] = lcfirst($acr['name']); |
||||
$acr['comment'] = trim(preg_replace('#(^|\n)\s+\*\s?#', '$1 * ', $acr['comment'])); |
||||
$props[$acr['name']][$acr['kind']] = array( |
||||
'type' => $acr['type'], |
||||
'comment' => $this->fixSentence($acr['comment']), |
||||
); |
||||
} |
||||
|
||||
// foreach ($props as $propName => &$prop) // I don't like write-only props... |
||||
// if (!isset($prop['get'])) |
||||
// unset($props[$propName]); |
||||
|
||||
if (count($props) > 0) { |
||||
$phpdoc .= " *\n"; |
||||
foreach ($props as $propName => &$prop) { |
||||
$phpdoc .= ' * @'; |
||||
// if (isset($prop['get']) && isset($prop['set'])) // Few IDEs support complex syntax |
||||
$phpdoc .= 'property'; |
||||
// elseif (isset($prop['get'])) |
||||
// $phpdoc .= 'property-read'; |
||||
// elseif (isset($prop['set'])) |
||||
// $phpdoc .= 'property-write'; |
||||
$phpdoc .= ' ' . $this->getPropParam($prop, 'type') . " $$propName " . $this->getPropParam($prop, 'comment') . "\n"; |
||||
} |
||||
$phpdoc .= " *\n"; |
||||
} |
||||
} |
||||
return array($className, $phpdoc); |
||||
} |
||||
|
||||
protected function match($pattern, $subject) |
||||
{ |
||||
$sets = array(); |
||||
preg_match_all($pattern . 'suU', $subject, $sets, PREG_SET_ORDER); |
||||
foreach ($sets as &$set) |
||||
foreach ($set as $i => $match) |
||||
if (is_numeric($i) /*&& $i != 0*/) |
||||
unset($set[$i]); |
||||
return $sets; |
||||
} |
||||
|
||||
protected function fixSentence($str) |
||||
{ |
||||
// TODO fix word wrap |
||||
if ($str == '') |
||||
return ''; |
||||
return strtoupper(substr($str, 0, 1)) . substr($str, 1) . ($str[strlen($str) - 1] != '.' ? '.' : ''); |
||||
} |
||||
|
||||
protected function getPropParam($prop, $param) |
||||
{ |
||||
return isset($prop['get']) ? $prop['get'][$param] : $prop['set'][$param]; |
||||
} |
||||
} |
Loading…
Reference in new issue