框架改版后的第二个版本定下来了,这两天也比较轻松,于是就折腾给项目建个好看的api文档。
各种折腾。先是折腾phpDocumentor2,用phpdoc开源工具来建立文档,好不容易安装成功,各个模板都使用了一遍,还是不满意。后来又发现了swagger文档生成工具,起初看起来还蛮直观的,但是一看注释块,又觉得太繁琐了。
索性,主管拍板,自己写一个api文档生成类,满足自己的需求:体现路由,方法和参数。
自写工具的优点是:高可定制化,满足自己的一切要求,实现自己想要的样式,没有冗余文件
下面是注释块样式:
/**
* @description 这里是描述
* @router http://www.test.com/api/demo/:id
* @method GET
* @param string $a
* @param string $b
* @return number
*/
下面是生成的效果 图:
实现代码如下:
/**
* 1.以输入的目录分目录,proxy,user,site
* 2.以@package分文件,site.html,vhost.html
*/
class apiDoc
{
static $round = 1;
static $testArr = array();
static $docPackage = '';
public static function targetApiDir($dir)
{
$apiDir = API_PATH.$dir."/";
self::$docPackage = API_DOC_DIR.$dir;
self::parseApiFile($apiDir);
}
public static function parseApiFile($dir)
{
$arr = scandir($dir);
foreach ($arr as $v) {
if ($v == "." || $v == "..") {
continue;
}
$file = $dir.$v;
$content = file_get_contents($file);
$preg = "/\/\*[\S\s]+?\*\//";
preg_match_all($preg,$content,$rows);
if (!!$rows) {
foreach ($rows[0] as $key=>$row) {
$arr = self::doWithBlocQuote($row);
self::$testArr[$arr['package']][$arr['router']."-".$arr['method']] = $arr;
}
}
}
if (self::unitDocDir(API_DOC_DIR)) {
self::createDocHtml();
}
echo "创建成功";
print_r(self::$testArr);
}
private static function doWithBlocQuote($row)
{
$router = "";
$param = array();
$method = '';
$package = '';
$return = '';
$description = '';
$preg_router = "/@router[\S\s]+?\\n/";
if (preg_match($preg_router, $row)) {
$arr= explode("\n", $row);
foreach ($arr as $a) {
$a = trim($a);
$a = trim($a,"*");
$a = trim($a,"\t");
$a = trim($a,"\n");
if ($a == "/" || !$a) {
continue;
}
$a = preg_replace('/\s(?=\s)/', '\\1', ltrim($a, " "));
$b = explode(" ", $a);
if ($b[0] == "@description" && count($b) >= 2) {
$b[1] = self::contactRemains($b, 2);
$description = $b[1];
}
if ($b[0] =="@package" && count($b) >= 2) {
$package = $b[1];
}
if ($b[0] == "@router") {
$router = $b[1];
}
if ($b[0] =="@method") {
$method = $b[1];
}
if ($b[0] =="@param" && count($b) >= 3) {
$b[3] = self::contactRemains($b, 4);
array_push($param, array("type"=>$b[1],"name"=>$b[2], "description"=>$b[3]));
}
if ($b[0] =="@return") {
$return = $b[1];
}
}
return array(
'description'=>$description,
'package' => $package,
'router' => $router,
'method' => $method,
'param' => $param,
'return' => $return
);
}
}
private static function headHtml($title, $content)
{
$tpl = '
%s
href="/asset/css/layui.css" rel="stylesheet"/>
href="/asset/css/common.css" rel="stylesheet"/>
%s
© 2013 %s, Inc. All rights reserved.
';
return sprintf($tpl,$title, $content, $title);
}
private static function createContentHtml($descript, $router, $method, $params)
{
$paramHtml = '';
if (count($params) > 0) {
foreach ($params as $param) {
$paramHtml.= sprintf('%s%s%s', $param['name'], $param['type'], $param['description']);
}
} else {
$paramHtml = '无';
}
$html = '
%s
%s
%s
参数 类型 参数说明
%s
';
return sprintf($html, $descript, $router, $method, $paramHtml);
}
private static function createDocHtml()
{
foreach (self::$testArr as $package=>&$list) {
ksort($list);
$html = '';
foreach ($list as $k=>$v) {
$html.= self::createContentHtml($v['description'], $v['router'], $v['method'], $v['param']);
}
$webname = sessionGet("web_name");
if (!$webname) {
$webname = SystemMod::webName();
}
self::createDocTempFile($package, self::headHtml($webname, $html));
}
}
private static function contactRemains($arr, $remains)
{
$str = '';
if (count($arr) >= $remains) {
$str = '';
for ($i = $remains - 1; $i < count($arr);$i++){
$str.= $arr[$i];
}
}
return $str;
}
private static function createDocTempFile($package, $content, $filename = null)
{
if (!is_dir(self::$docPackage)) {
mkdir(self::$docPackage, 775, true);
}
$newFile = self::$docPackage."/".$package.".html";
file_put_contents($newFile, $content.PHP_EOL, FILE_APPEND);
}
private static function unitDocDir($dir)
{
$arr = scandir($dir);
foreach ($arr as $v) {
if ($v == "." || $v == "..") {
continue;
}
$subDir = $dir."/".$v;
if (is_file($subDir)) {
unlink($subDir);
} else {
if (count(scandir($subDir)) > 2) {
self::unitDocDir($subDir);
}
rmdir($subDir);
}
}
return true;
}
}
以上是上线代码,通过给定api扫描目录生成文档目录,再以定义的package为文件名,生成文档文件。例如;如果文档目录是http://www.test.com/api/demo,则程序会自动扫描demo目录下的所有php文件,并根据注释块解析package, router, method, param,return等内容,如package为demo2,则会生成demo2.html文件,目录为http://www.test.com/doc/demo/demo2.html。