diff --git a/application/admin/command/Api.php b/application/admin/command/Api.php
index ab449127..2c719842 100644
--- a/application/admin/command/Api.php
+++ b/application/admin/command/Api.php
@@ -23,9 +23,10 @@ class Api extends Command
->addOption('template', 'e', Option::VALUE_OPTIONAL, '', 'index.html')
->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override general file', false)
->addOption('title', 't', Option::VALUE_OPTIONAL, 'document title', $site['name'])
- ->addOption('author', 'a', Option::VALUE_OPTIONAL, 'document author', $site['name'])
->addOption('class', 'c', Option::VALUE_OPTIONAL | Option::VALUE_IS_ARRAY, 'extend class', null)
->addOption('language', 'l', Option::VALUE_OPTIONAL, 'language', 'zh-cn')
+ ->addOption('addon', 'a', Option::VALUE_OPTIONAL, 'addon name', null)
+ ->addOption('controller', 'r', Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY, 'controller name', null)
->setDescription('Build Api document from controller');
}
@@ -58,12 +59,21 @@ class Api extends Command
$classes = $input->getOption('class');
// 标题
$title = $input->getOption('title');
- // 作者
- $author = $input->getOption('author');
// 模块
$module = $input->getOption('module');
+ // 插件
+ $addon = $input->getOption('addon');
- $moduleDir = APP_PATH . $module . DS;
+ $moduleDir = $addonDir = '';
+ if ($addon) {
+ $addonInfo = get_addon_info($addon);
+ if (!$addonInfo) {
+ throw new Exception('addon not found');
+ }
+ $moduleDir = ADDON_PATH . $addon . DS;
+ } else {
+ $moduleDir = APP_PATH . $module . DS;
+ }
if (!is_dir($moduleDir)) {
throw new Exception('module not found');
}
@@ -81,31 +91,44 @@ class Api extends Command
}
}
- $controllerDir = $moduleDir . Config::get('url_controller_layer') . DS;
- $files = new \RecursiveIteratorIterator(
- new \RecursiveDirectoryIterator($controllerDir),
- \RecursiveIteratorIterator::LEAVES_ONLY
- );
+ //控制器名
+ $controller = $input->getOption('controller') ?: [];
+ if (!$controller) {
+ $controllerDir = $moduleDir . Config::get('url_controller_layer') . DS;
+ $files = new \RecursiveIteratorIterator(
+ new \RecursiveDirectoryIterator($controllerDir),
+ \RecursiveIteratorIterator::LEAVES_ONLY
+ );
- foreach ($files as $name => $file) {
- if (!$file->isDir() && $file->getExtension() == 'php') {
- $filePath = $file->getRealPath();
+ foreach ($files as $name => $file) {
+ if (!$file->isDir() && $file->getExtension() == 'php') {
+ $filePath = $file->getRealPath();
+ $classes[] = $this->get_class_from_file($filePath);
+ }
+ }
+ } else {
+ foreach ($controller as $index => $item) {
+ $filePath = $moduleDir . Config::get('url_controller_layer') . DS . $item . '.php';
$classes[] = $this->get_class_from_file($filePath);
}
}
+
$classes = array_unique(array_filter($classes));
$config = [
'sitename' => config('site.name'),
'title' => $title,
- 'author' => $author,
+ 'author' => config('site.name'),
'description' => '',
'apiurl' => $url,
'language' => $language,
];
- $builder = new Builder($classes);
- $content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]);
-
+ try {
+ $builder = new Builder($classes);
+ $content = $builder->render($template_file, ['config' => $config, 'lang' => $lang]);
+ } catch (\Exception $e) {
+ print_r($e);
+ }
if (!file_put_contents($output_file, $content)) {
throw new Exception('Cannot save the content to ' . $output_file);
}
diff --git a/application/admin/command/Api/lang/zh-cn.php b/application/admin/command/Api/lang/zh-cn.php
index 2154aa4d..7f0ecc76 100644
--- a/application/admin/command/Api/lang/zh-cn.php
+++ b/application/admin/command/Api/lang/zh-cn.php
@@ -16,6 +16,9 @@ return [
'Tokentips' => 'Token在会员注册或登录后都会返回,WEB端同时存在于Cookie中',
'Apiurltips' => 'API接口URL',
'Savetips' => '点击保存后Token和Api url都将保存在本地Localstorage中',
+ 'Authorization' => '权限',
+ 'NeedLogin' => '登录',
+ 'NeedRight' => '鉴权',
'ReturnHeaders' => '响应头',
'ReturnParameters' => '返回参数',
'Response' => '响应输出',
diff --git a/application/admin/command/Api/library/Builder.php b/application/admin/command/Api/library/Builder.php
index ff9b08e5..169930ab 100755
--- a/application/admin/command/Api/library/Builder.php
+++ b/application/admin/command/Api/library/Builder.php
@@ -43,9 +43,11 @@ class Builder
continue;
}
Extractor::getClassMethodAnnotations($class);
+ //Extractor::getClassPropertyValues($class);
}
$allClassAnnotation = Extractor::getAllClassAnnotations();
$allClassMethodAnnotation = Extractor::getAllClassMethodAnnotations();
+ //$allClassPropertyValue = Extractor::getAllClassPropertyValues();
// foreach ($allClassMethodAnnotation as $className => &$methods) {
// foreach ($methods as &$method) {
@@ -162,10 +164,12 @@ class Builder
list($allClassAnnotations, $allClassMethodAnnotations) = $this->extractAnnotations();
$sectorArr = [];
- foreach ($allClassAnnotations as $index => $allClassAnnotation) {
+ foreach ($allClassAnnotations as $index => &$allClassAnnotation) {
$sector = isset($allClassAnnotation['ApiSector']) ? $allClassAnnotation['ApiSector'][0] : $allClassAnnotation['ApiTitle'][0];
$sectorArr[$sector] = isset($allClassAnnotation['ApiWeigh']) ? $allClassAnnotation['ApiWeigh'][0] : 0;
}
+ unset($allClassAnnotation);
+
arsort($sectorArr);
$routes = include_once CONF_PATH . 'route.php';
$subdomain = false;
@@ -175,7 +179,7 @@ class Builder
$counter = 0;
$section = null;
$weigh = 0;
- $docslist = [];
+ $docsList = [];
foreach ($allClassMethodAnnotations as $class => $methods) {
foreach ($methods as $name => $docs) {
if (isset($docs['ApiSector'][0])) {
@@ -190,28 +194,30 @@ class Builder
if ($subdomain) {
$route = substr($route, 4);
}
- $docslist[$section][$class . $name] = [
- 'id' => $counter,
- 'method' => is_array($docs['ApiMethod'][0]) ? $docs['ApiMethod'][0]['data'] : $docs['ApiMethod'][0],
- 'method_label' => $this->generateBadgeForMethod($docs),
- 'section' => $section,
- 'route' => $route,
- 'title' => is_array($docs['ApiTitle'][0]) ? $docs['ApiTitle'][0]['data'] : $docs['ApiTitle'][0],
- 'summary' => is_array($docs['ApiSummary'][0]) ? $docs['ApiSummary'][0]['data'] : $docs['ApiSummary'][0],
- 'body' => isset($docs['ApiBody'][0]) ? is_array($docs['ApiBody'][0]) ? $docs['ApiBody'][0]['data'] : $docs['ApiBody'][0] : '',
- 'headerslist' => $this->generateHeadersTemplate($docs),
- 'paramslist' => $this->generateParamsTemplate($docs),
- 'returnheaderslist' => $this->generateReturnHeadersTemplate($docs),
- 'returnparamslist' => $this->generateReturnParamsTemplate($docs),
- 'weigh' => is_array($docs['ApiWeigh'][0]) ? $docs['ApiWeigh'][0]['data'] : $docs['ApiWeigh'][0],
- 'return' => isset($docs['ApiReturn']) ? is_array($docs['ApiReturn'][0]) ? $docs['ApiReturn'][0]['data'] : $docs['ApiReturn'][0] : '',
+ $docsList[$section][$name] = [
+ 'id' => $counter,
+ 'method' => is_array($docs['ApiMethod'][0]) ? $docs['ApiMethod'][0]['data'] : $docs['ApiMethod'][0],
+ 'methodLabel' => $this->generateBadgeForMethod($docs),
+ 'section' => $section,
+ 'route' => $route,
+ 'title' => is_array($docs['ApiTitle'][0]) ? $docs['ApiTitle'][0]['data'] : $docs['ApiTitle'][0],
+ 'summary' => is_array($docs['ApiSummary'][0]) ? $docs['ApiSummary'][0]['data'] : $docs['ApiSummary'][0],
+ 'body' => isset($docs['ApiBody'][0]) ? is_array($docs['ApiBody'][0]) ? $docs['ApiBody'][0]['data'] : $docs['ApiBody'][0] : '',
+ 'headersList' => $this->generateHeadersTemplate($docs),
+ 'paramsList' => $this->generateParamsTemplate($docs),
+ 'returnHeadersList' => $this->generateReturnHeadersTemplate($docs),
+ 'returnParamsList' => $this->generateReturnParamsTemplate($docs),
+ 'weigh' => is_array($docs['ApiWeigh'][0]) ? $docs['ApiWeigh'][0]['data'] : $docs['ApiWeigh'][0],
+ 'return' => isset($docs['ApiReturn']) ? is_array($docs['ApiReturn'][0]) ? $docs['ApiReturn'][0]['data'] : $docs['ApiReturn'][0] : '',
+ 'needLogin' => $docs['ApiPermissionLogin'][0],
+ 'needRight' => $docs['ApiPermissionRight'][0],
];
$counter++;
}
}
//重建排序
- foreach ($docslist as $index => &$methods) {
+ foreach ($docsList as $index => &$methods) {
$methodSectorArr = [];
foreach ($methods as $name => $method) {
$methodSectorArr[$name] = isset($method['weigh']) ? $method['weigh'] : 0;
@@ -219,9 +225,8 @@ class Builder
arsort($methodSectorArr);
$methods = array_merge(array_flip(array_keys($methodSectorArr)), $methods);
}
- $docslist = array_merge(array_flip(array_keys($sectorArr)), $docslist);
- $docslist = array_filter($docslist , function($v) {return is_array($v) ; }) ;
- return $docslist;
+ $docsList = array_merge(array_flip(array_keys($sectorArr)), $docsList);
+ return $docsList;
}
public function getView()
@@ -237,8 +242,8 @@ class Builder
*/
public function render($template, $vars = [])
{
- $docslist = $this->parse();
+ $docsList = $this->parse();
- return $this->view->display(file_get_contents($template), array_merge($vars, ['docslist' => $docslist]));
+ return $this->view->display(file_get_contents($template), array_merge($vars, ['docsList' => $docsList]));
}
}
diff --git a/application/admin/command/Api/library/Extractor.php b/application/admin/command/Api/library/Extractor.php
index 5591921b..40115365 100644
--- a/application/admin/command/Api/library/Extractor.php
+++ b/application/admin/command/Api/library/Extractor.php
@@ -24,6 +24,8 @@ class Extractor
private static $classMethodAnnotationCache;
+ private static $classPropertyValueCache;
+
/**
* Indicates that annotations should has strict behavior, 'false' by default
* @var boolean
@@ -66,14 +68,16 @@ class Extractor
/**
* Gets all anotations with pattern @SomeAnnotation() from a given class
*
- * @param string $className class name to get annotations
+ * @param string $className class name to get annotations
* @return array self::$classAnnotationCache all annotated elements
*/
public static function getClassAnnotations($className)
{
if (!isset(self::$classAnnotationCache[$className])) {
$class = new \ReflectionClass($className);
- self::$classAnnotationCache[$className] = self::parseAnnotations($class->getDocComment());
+ $annotationArr = self::parseAnnotations($class->getDocComment());
+ $annotationArr['ApiTitle'] = !isset($annotationArr['ApiTitle'][0]) || !trim($annotationArr['ApiTitle'][0]) ? [$class->getShortName()] : $annotationArr['ApiTitle'];
+ self::$classAnnotationCache[$className] = $annotationArr;
}
return self::$classAnnotationCache[$className];
@@ -96,6 +100,17 @@ class Extractor
return self::$classMethodAnnotationCache[$className];
}
+ public static function getClassPropertyValues($className)
+ {
+ $class = new \ReflectionClass($className);
+
+ foreach ($class->getProperties() as $object) {
+ self::$classPropertyValueCache[$className][$object->name] = self::getClassPropertyValue($className, $object->name);
+ }
+
+ return self::$classMethodAnnotationCache[$className];
+ }
+
public static function getAllClassAnnotations()
{
return self::$classAnnotationCache;
@@ -106,11 +121,25 @@ class Extractor
return self::$classMethodAnnotationCache;
}
+ public static function getAllClassPropertyValues()
+ {
+ return self::$classPropertyValueCache;
+ }
+
+ public static function getClassPropertyValue($className, $property)
+ {
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $reflectionClass = new \ReflectionClass($className);
+ $reflectionProperty = $reflectionClass->getProperty($property);
+ $reflectionProperty->setAccessible(true);
+ return $reflectionProperty->getValue($reflectionClass->newInstanceWithoutConstructor());
+ }
+
/**
* Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
*
- * @param string $className class name
- * @param string $methodName method name to get annotations
+ * @param string $className class name
+ * @param string $methodName method name to get annotations
* @return array self::$annotationCache all annotated elements of a method given
*/
public static function getMethodAnnotations($className, $methodName)
@@ -138,8 +167,8 @@ class Extractor
* Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
* and instance its abcAnnotation class
*
- * @param string $className class name
- * @param string $methodName method name to get annotations
+ * @param string $className class name
+ * @param string $methodName method name to get annotations
* @return array self::$annotationCache all annotated objects of a method given
*/
public function getMethodAnnotationsObjects($className, $methodName)
@@ -189,7 +218,11 @@ class Extractor
$methodName = $method->getName();
$methodAnnotations = self::parseAnnotations($docblockMethod);
+ $methodAnnotations['ApiTitle'] = !isset($methodAnnotations['ApiTitle'][0]) || !trim($methodAnnotations['ApiTitle'][0]) ? [$method->getName()] : $methodAnnotations['ApiTitle'];
+
$classAnnotations = self::parseAnnotations($dockblockClass);
+ $classAnnotations['ApiTitle'] = !isset($classAnnotations['ApiTitle'][0]) || !trim($classAnnotations['ApiTitle'][0]) ? [$class->getShortName()] : $classAnnotations['ApiTitle'];
+
if (isset($methodAnnotations['ApiInternal']) || $methodName == '_initialize' || $methodName == '_empty') {
return [];
}
@@ -264,15 +297,15 @@ class Extractor
}
}
$methodAnnotations['ApiPermissionLogin'] = [!in_array('*', $noNeedLogin) && !in_array($methodName, $noNeedLogin)];
- $methodAnnotations['ApiPermissionRight'] = [!in_array('*', $noNeedRight) && !in_array($methodName, $noNeedRight)];
+ $methodAnnotations['ApiPermissionRight'] = !$methodAnnotations['ApiPermissionLogin'][0] ? false : [!in_array('*', $noNeedRight) && !in_array($methodName, $noNeedRight)];
return $methodAnnotations;
}
/**
* Parse annotations
*
- * @param string $docblock
- * @param string $name
+ * @param string $docblock
+ * @param string $name
* @return array parsed annotations params
*/
private static function parseCustomAnnotations($docblock, $name = 'param')
@@ -291,7 +324,7 @@ class Extractor
/**
* Parse annotations
*
- * @param string $docblock
+ * @param string $docblock
* @return array parsed annotations params
*/
private static function parseAnnotations($docblock)
@@ -337,7 +370,7 @@ class Extractor
/**
* Parse individual annotation arguments
*
- * @param string $content arguments string
+ * @param string $content arguments string
* @return array annotated arguments
*/
private static function parseArgs($content)
@@ -480,8 +513,8 @@ class Extractor
/**
* Try determinate the original type variable of a string
*
- * @param string $val string containing possibles variables that can be cast to bool or int
- * @param boolean $trim indicate if the value passed should be trimmed after to try cast
+ * @param string $val string containing possibles variables that can be cast to bool or int
+ * @param boolean $trim indicate if the value passed should be trimmed after to try cast
* @return mixed returns the value converted to original type if was possible
*/
private static function castValue($val, $trim = false)
diff --git a/application/admin/command/Api/template/index.html b/application/admin/command/Api/template/index.html
index a0b5424f..4608e506 100755
--- a/application/admin/command/Api/template/index.html
+++ b/application/admin/command/Api/template/index.html
@@ -27,12 +27,12 @@
font-family: "Roboto", "SF Pro SC", "SF Pro Display", "SF Pro Icons", "PingFang SC", BlinkMacSystemFont, -apple-system, "Segoe UI", "Microsoft Yahei", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
font-weight: 400;
}
- h2 { font-size: 1.6em; }
+ h2 { font-size: 1.2em; }
hr { margin-top: 10px; }
.tab-pane { padding-top: 10px; }
.mt0 { margin-top: 0px; }
.footer { font-size: 12px; color: #666; }
- .label { display: inline-block; min-width: 65px; padding: 0.3em 0.6em 0.3em; }
+ .docs-list .label { display: inline-block; min-width: 65px; padding: 0.3em 0.6em 0.3em; }
.string { color: green; }
.number { color: darkorange; }
.boolean { color: blue; }
@@ -65,12 +65,24 @@
#sidebar > .list-group > a{
text-indent:0;
}
+ #sidebar .child > a .tag{
+ position: absolute;
+ right: 10px;
+ top: 11px;
+ }
+ #sidebar .child > a .pull-right{
+ margin-left:3px;
+ }
#sidebar .child {
border:1px solid #ddd;
border-bottom:none;
}
+ #sidebar .child:last-child {
+ border-bottom:1px solid #ddd;
+ }
#sidebar .child > a {
border:0;
+ min-height: 40px;
}
#sidebar .list-group a.current {
background:#f5f5f5;
@@ -94,6 +106,9 @@
.label-primary {
background-color: #248aff;
}
+ .docs-list .panel .panel-body .table {
+ margin-bottom: 0;
+ }
@@ -138,25 +153,34 @@
-
- {foreach name="docslist" id="docs"}
+
+ {foreach name="docsList" id="docs"}
{$key}
{foreach name="docs" id="api" }
@@ -177,10 +201,27 @@
{$api.summary}
+
+
{$lang.Authorization}
+
+
+
+
+ | {$lang.NeedLogin} |
+ {$api.needLogin?'是':'否'} |
+
+
+ | {$lang.NeedRight} |
+ {$api.needRight?'是':'否'} |
+
+
+
+
+
{$lang.Headers}
- {if $api.headerslist}
+ {if $api.headersList}
@@ -191,7 +232,7 @@
- {foreach name="api['headerslist']" id="header"}
+ {foreach name="api['headersList']" id="header"}
| {$header.name} |
{$header.type} |
@@ -209,7 +250,7 @@
{$lang.Parameters}
- {if $api.paramslist}
+ {if $api.paramsList}
@@ -220,7 +261,7 @@
- {foreach name="api['paramslist']" id="param"}
+ {foreach name="api['paramsList']" id="param"}
| {$param.name} |
{$param.type} |
@@ -246,12 +287,12 @@
- {if $api.headerslist}
+ {if $api.headersList}