356 lines
14 KiB
PHP
356 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* ==================================================================
|
|
* 文 件 名: BootstrapApiDoc.php
|
|
* 概 要: BootstrapAPI文档生成
|
|
* 作 者: IT小强
|
|
* 创建时间: 2018/6/6 13:57
|
|
* 修改时间:
|
|
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
|
* ==================================================================
|
|
*/
|
|
|
|
namespace itxq\apidoc;
|
|
|
|
use itxq\apidoc\lib\Tools;
|
|
|
|
/**
|
|
* BootstrapAPI文档生成
|
|
* Class BootstrapApiDoc
|
|
* @package itxq\apidoc
|
|
*/
|
|
class BootstrapApiDoc extends ApiDoc
|
|
{
|
|
/**
|
|
* @var string - Bootstrap CSS文件路径
|
|
*/
|
|
private $bootstrapCss = __DIR__ . '/../assets/css/bootstrap.min.css';
|
|
|
|
/**
|
|
* @var string - Bootstrap JS文件路径
|
|
*/
|
|
private $bootstrapJs = __DIR__ . '/../assets/js/bootstrap.min.js';
|
|
|
|
/**
|
|
* @var string - jQuery Js文件路径
|
|
*/
|
|
private $jQueryJs = __DIR__ . '/../assets/js/jquery.min.js';
|
|
|
|
/**
|
|
* @var string - 自定义CSS
|
|
*/
|
|
private $customCss = '<style type="text/css">
|
|
::-webkit-scrollbar {width: 5px;}
|
|
.navbar-collapse.collapse.show::-webkit-scrollbar {width: 0; height: 0;background-color: rgba(255, 255, 255, 0);}
|
|
::-webkit-scrollbar-track {background-color: rgba(255, 255, 255, 0.2);-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;}
|
|
::-webkit-scrollbar-thumb {background-color: rgba(0, 0, 0, 0.8);-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;}
|
|
::-webkit-scrollbar-button {-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;height: 0;background-color: rgba(0, 0, 0, 0.9);}
|
|
::-webkit-scrollbar-corner {background-color: rgba(0, 0, 0, 0.9);}
|
|
#list-tab-left-nav{display: none;}
|
|
.doc-content{margin-top: 75px;}
|
|
.class-item .class-title {text-indent: 0.6em;border-left: 5px solid lightseagreen;font-size: 24px;margin: 15px 0;}
|
|
.action-item .action-title {text-indent: 0.6em;border-left: 3px solid #F0AD4E;font-size: 20px;margin: 8px 0;}
|
|
.table-item {background-color:#FFFFFF;padding-top: 10px;margin-bottom:10px;border: solid 1px #ccc;border-radius: 5px;}
|
|
.list-group-item-sub{padding: .5rem 1.25rem;}
|
|
</style>';
|
|
|
|
/**
|
|
* @var string - 自定义JS
|
|
*/
|
|
private $customJs = '<script type="text/javascript">
|
|
$(\'a[href*="#"]:not([href="#"])\').click(function() {
|
|
if (location.pathname.replace(/^\//, \'\') == this.pathname.replace(/^\//, \'\') && location.hostname == this.hostname) {
|
|
var target = $(this.hash);
|
|
target = target.length ? target : $("[name=\' + this.hash.slice(1) +\']");
|
|
if (target.length) {
|
|
var topOffset = target.offset().top - 60;
|
|
$("html, body").animate({
|
|
scrollTop: topOffset
|
|
}, 800);
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
</script>';
|
|
|
|
/**
|
|
* Bootstrap 构造函数.
|
|
* @param array $config - 配置信息
|
|
*/
|
|
public function __construct($config) {
|
|
parent::__construct($config);
|
|
// bootstrapJs文件路径
|
|
$this->bootstrapJs = Tools::getSubValue('bootstrap_js', $config, $this->bootstrapJs);
|
|
// jQueryJs文件路径
|
|
$this->jQueryJs = Tools::getSubValue('jquery_js', $config, $this->jQueryJs);
|
|
// 自定义js
|
|
$this->customJs .= Tools::getSubValue('custom_js', $config, '');
|
|
// bootstrapCSS文件路径
|
|
$this->bootstrapCss = Tools::getSubValue('bootstrap_css', $config, $this->bootstrapCss);
|
|
// 自定义CSS
|
|
$this->customCss .= Tools::getSubValue('custom_css', $config, '');
|
|
// 合并CSS
|
|
$this->_getCss();
|
|
// 合并JS
|
|
$this->_getJs();
|
|
}
|
|
|
|
/**
|
|
* 输出HTML
|
|
* @param int $type - 方法过滤,默认只获取 public类型 方法
|
|
* ReflectionMethod::IS_STATIC
|
|
* ReflectionMethod::IS_PUBLIC
|
|
* ReflectionMethod::IS_PROTECTED
|
|
* ReflectionMethod::IS_PRIVATE
|
|
* ReflectionMethod::IS_ABSTRACT
|
|
* ReflectionMethod::IS_FINAL
|
|
* @return string
|
|
*/
|
|
public function getHtml($type = \ReflectionMethod::IS_PUBLIC) {
|
|
$data = $this->getApiDoc($type);
|
|
$html = <<<EXT
|
|
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="renderer" content="webkit">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
|
<!-- 禁止浏览器初始缩放 -->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1, user-scalable=0">
|
|
<title>API文档 By Api-Doc-PHP</title>
|
|
{$this->customCss}
|
|
</head>
|
|
<body>
|
|
<div class="container-fluid">
|
|
<nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top">
|
|
<a class="navbar-brand" href="#">API文档</a>
|
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01" >
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navbarColor01">
|
|
{$this->_getTopNavList($data)}
|
|
</div>
|
|
</nav>
|
|
<div class="row">
|
|
<div class="col-lg-12">{$this->_getDocList($data)}</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-lg-12 text-center">
|
|
版权的撒打算
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{$this->customJs}
|
|
</body>
|
|
</html>
|
|
EXT;
|
|
|
|
if (isset($_GET['download']) && $_GET['download'] === 'api_doc_php') {
|
|
Tools::downloadFile($html);
|
|
return true;
|
|
}
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 解析return 并生成HTML
|
|
* @param array $data
|
|
* @return string
|
|
*/
|
|
private function _getReturnData($data = []) {
|
|
$html = '';
|
|
if (!is_array($data) || count($data) < 1) {
|
|
return $html;
|
|
}
|
|
$html .= '<div class="table-item col-md-12"><p class="table-title"><span class="btn btn-sm btn-success">返回参数</span></p>';
|
|
$html .= '<table class="table"><tr><td>参数</td><td>类型</td><td>描述</td></tr>';
|
|
foreach ($data as $v) {
|
|
$html .= '<tr>
|
|
<td>' . Tools::getSubValue('return_name', $v, '') . '</td>
|
|
<td>' . Tools::getSubValue('return_type', $v, '') . '</td>
|
|
<td>' . Tools::getSubValue('return_title', $v, '') . '</td>
|
|
</tr>';
|
|
}
|
|
$html .= '</table></div>';
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 解析param 并生成HTML
|
|
* @param array $data
|
|
* @return string
|
|
*/
|
|
private function _getParamData($data = []) {
|
|
$html = '';
|
|
if (!is_array($data) || count($data) < 1) {
|
|
return $html;
|
|
}
|
|
$html .= '<div class="table-item col-md-12"><p class="table-title"><span class="btn btn-sm btn-danger">请求参数</span></p>';
|
|
$html .= '<table class="table"><tr><td>参数</td><td>类型</td><td>描述</td><td>默认值</td><td>是否必须</td></tr>';
|
|
foreach ($data as $v) {
|
|
$html .= '<tr>
|
|
<td>' . Tools::getSubValue('param_name', $v, '') . '</td>
|
|
<td>' . Tools::getSubValue('param_type', $v, '') . '</td>
|
|
<td>' . Tools::getSubValue('param_title', $v, '') . '</td>
|
|
<td>' . Tools::getSubValue('param_default', $v, '无默认值') . '</td>
|
|
<td>' . Tools::getSubValue('param_require', $v, '非必须') . '</td>
|
|
</tr>';
|
|
}
|
|
$html .= '</table></div>';
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 解析code 并生成HTML
|
|
* @param array $data
|
|
* @return string
|
|
*/
|
|
private function _getCodeData($data = []) {
|
|
$html = '';
|
|
if (!is_array($data) || count($data) < 1) {
|
|
return $html;
|
|
}
|
|
$html .= '<div class="table-item col-md-12"><p class="table-title"><span class="btn btn-sm btn-warning">状态码说明</span></p>';
|
|
$html .= '<table class="table"><tr><td>状态码</td><td>描述</td></tr>';
|
|
foreach ($data as $v) {
|
|
$html .= '<tr>
|
|
<td>' . Tools::getSubValue('code', $v, '') . '</td>
|
|
<td>' . Tools::getSubValue('content', $v, '暂无说明') . '</td>
|
|
</tr>';
|
|
}
|
|
$html .= '</table></div>';
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 获取指定接口操作下的文档信息
|
|
* @param $className - 类名
|
|
* @param $actionName - 操作名
|
|
* @param $actionItem - 接口数据
|
|
* @return string
|
|
*/
|
|
private function _getActionItem($className, $actionName, $actionItem) {
|
|
$html = <<<EXT
|
|
<div class="list-group-item list-group-item-action action-item col-md-12" id="{$className}_{$actionName}">
|
|
<h4 class="action-title">API - {$actionItem['title']}</h4>
|
|
<p>请求方式:
|
|
<span class="btn btn-info btn-sm">{$actionItem['method']}</span>
|
|
</p>
|
|
<p>请求地址:<a href="{$actionItem['url']}">{$actionItem['url']}</a></p>
|
|
{$this->_getParamData(Tools::getSubValue('param', $actionItem, []))}
|
|
{$this->_getReturnData(Tools::getSubValue('return', $actionItem, []))}
|
|
{$this->_getCodeData(Tools::getSubValue('code', $actionItem, []))}
|
|
</div>
|
|
EXT;
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 获取指定API类的文档HTML
|
|
* @param $className - 类名称
|
|
* @param $classItem - 类数据
|
|
* @return string
|
|
*/
|
|
private function _getClassItem($className, $classItem) {
|
|
$title = Tools::getSubValue('title', $classItem, '未命名');
|
|
$actionHtml = '';
|
|
if (isset($classItem['action']) && is_array($classItem['action']) && count($classItem['action']) >= 1) {
|
|
foreach ($classItem['action'] as $actionName => $actionItem) {
|
|
$actionHtml .= $this->_getActionItem($className, $actionName, $actionItem);
|
|
}
|
|
}
|
|
$html = <<<EXT
|
|
<div class="class-item" id="{$className}">
|
|
<h2 class="class-title">{$title}</h2>
|
|
<div class="list-group">{$actionHtml}</div>
|
|
</div>
|
|
EXT;
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 获取API文档HTML
|
|
* @param array $data - 文档数据
|
|
* @return string
|
|
*/
|
|
private function _getDocList($data) {
|
|
$html = '';
|
|
if (count($data) < 1) {
|
|
return $html;
|
|
}
|
|
$html .= '<div class="doc-content">';
|
|
foreach ($data as $className => $classItem) {
|
|
$html .= $this->_getClassItem($className, $classItem);
|
|
}
|
|
$html .= '</div>';
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 获取顶部导航HTML
|
|
* @param $data -API文档数据
|
|
* @return string
|
|
*/
|
|
private function _getTopNavList($data) {
|
|
$html = '<ul class="navbar-nav" id="navbar-nav-top-nav">';
|
|
foreach ($data as $className => $classItem) {
|
|
$title = Tools::getSubValue('title', $classItem, '未命名');
|
|
$html .= '<li class="nav-item dropdown">';
|
|
$html .= '<a class="nav-link dropdown-toggle" href="#" id="' . $className . '-nav" data-toggle="dropdown">' . $title . '</a>';
|
|
$html .= '<div class="dropdown-menu" aria-labelledby="' . $className . '-nav">';
|
|
foreach ($classItem['action'] as $actionName => $actionItem) {
|
|
$title = Tools::getSubValue('title', $actionItem, '未命名');
|
|
$id = $className . '_' . $actionName;
|
|
$html .= '<a class="dropdown-item" href="#' . $id . '">' . $title . '</a>';
|
|
}
|
|
$html .= '</div></li>';
|
|
}
|
|
$html .= ' <li class="nav-item"><a class="nav-link" href="?download=api_doc_php">下载文档</a></li>';
|
|
$html .= '</ul>';
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 获取文档CSS
|
|
* @return string
|
|
*/
|
|
private function _getCss() {
|
|
$path = realpath($this->bootstrapCss);
|
|
if (!$path || !is_file($path)) {
|
|
return $this->customCss;
|
|
}
|
|
$bootstrapCss = file_get_contents($path);
|
|
if (empty($bootstrapCss)) {
|
|
return $this->customCss;
|
|
}
|
|
$this->customCss = '<style type="text/css">' . $bootstrapCss . '</style>' . $this->customCss;
|
|
// $this->customCss = ' <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">' . $this->customCss;
|
|
return $this->customCss;
|
|
}
|
|
|
|
/**
|
|
* 获取文档JS
|
|
* @return string
|
|
*/
|
|
private function _getJs() {
|
|
// $js = '<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>';
|
|
// $js .= '<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" type="text/javascript"></script>';
|
|
// $this->customJs = $js . $this->customJs;
|
|
// return $this->customJs;
|
|
$bootstrapJs = realpath($this->bootstrapJs);
|
|
$jQueryJs = realpath($this->jQueryJs);
|
|
if (!$bootstrapJs || !$jQueryJs || !is_file($bootstrapJs) || !is_file($jQueryJs)) {
|
|
$this->customJs = '';
|
|
return $this->customCss;
|
|
}
|
|
$bootstrapJs = file_get_contents($bootstrapJs);
|
|
$jQueryJs = file_get_contents($jQueryJs);
|
|
if (empty($bootstrapJs) || empty($jQueryJs)) {
|
|
$this->customJs = '';
|
|
return $this->customJs;
|
|
}
|
|
$js = '<script type="text/javascript">' . $jQueryJs . '</script>' . '<script type="text/javascript">' . $bootstrapJs . '</script>';
|
|
$this->customJs = $js . $this->customJs;
|
|
return $this->customJs;
|
|
}
|
|
} |