|
@@ -0,0 +1,700 @@
|
|
|
+<?php
|
|
|
+declare(strict_types = 1);
|
|
|
+
|
|
|
+namespace hg\apidoc\parses;
|
|
|
+
|
|
|
+use ReflectionClass;
|
|
|
+use hg\apidoc\exception\ErrorException;
|
|
|
+use hg\apidoc\utils\DirAndFile;
|
|
|
+use hg\apidoc\utils\Helper;
|
|
|
+use hg\apidoc\utils\Lang;
|
|
|
+
|
|
|
+class ParseApiDetail
|
|
|
+{
|
|
|
+
|
|
|
+ protected $config = [];
|
|
|
+
|
|
|
+ protected $currentApp = [];
|
|
|
+
|
|
|
+ protected $appKey;
|
|
|
+
|
|
|
+ public function __construct($config)
|
|
|
+ {
|
|
|
+ $this->config = $config;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成api接口数据
|
|
|
+ * @param string $appKey
|
|
|
+ * @param string $apiKey
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public function renderApiDetail(string $appKey,string $apiKey)
|
|
|
+ {
|
|
|
+
|
|
|
+ $this->appKey = $appKey;
|
|
|
+ $pathArr = explode("@", $apiKey);
|
|
|
+ $classPath = $pathArr[0];
|
|
|
+ $methodName = $pathArr[1];
|
|
|
+ $currentAppConfig = Helper::getCurrentAppConfig($appKey);
|
|
|
+ $this->currentApp = $currentAppConfig['appConfig'];
|
|
|
+
|
|
|
+ try {
|
|
|
+ $refClass = new ReflectionClass($classPath);
|
|
|
+ $refMethod= $refClass->getMethod($methodName);
|
|
|
+ $methodItem = $this->parseApiMethod($refClass,$refMethod);
|
|
|
+ return $methodItem;
|
|
|
+ } catch (\ReflectionException $e) {
|
|
|
+ throw new ErrorException($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ protected function parseApiMethod($refClass,$refMethod){
|
|
|
+ $config = $this->config;
|
|
|
+ $currentApp = $this->currentApp;
|
|
|
+ if (empty($refMethod->name)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $textAnnotations = ParseAnnotation::parseTextAnnotation($refMethod);
|
|
|
+ // 标注不解析的方法
|
|
|
+ if (in_array("NotParse", $textAnnotations)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $methodAnnotations = $this->getMethodAnnotation($refMethod);
|
|
|
+ $methodAnnotations = self::handleApiBaseInfo($methodAnnotations,$refClass->name,$refMethod->name,$textAnnotations,$config);
|
|
|
+ // 是否开启debug
|
|
|
+ if (
|
|
|
+ in_array("NotDebug", $textAnnotations) ||
|
|
|
+ (isset($config['notDebug']) && $config['notDebug']===true) ||
|
|
|
+ (isset($currentApp['notDebug']) && $currentApp['notDebug']===true)
|
|
|
+ ) {
|
|
|
+ $methodAnnotations['notDebug'] = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!empty($methodAnnotations['md'])){
|
|
|
+ $methodAnnotations['md'] = $this->getFieldMarkdownContent($methodAnnotations['md']);
|
|
|
+ }
|
|
|
+ if(!empty($methodAnnotations['responseSuccessMd'])){
|
|
|
+ $methodAnnotations['responseSuccessMd'] = $this->getFieldMarkdownContent($methodAnnotations['responseSuccessMd']);
|
|
|
+ }
|
|
|
+ if(!empty($methodAnnotations['responseErrorMd'])){
|
|
|
+ $methodAnnotations['responseErrorMd'] = $this->getFieldMarkdownContent($methodAnnotations['responseErrorMd']);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合并全局请求参数-header
|
|
|
+ if (
|
|
|
+ (
|
|
|
+ (!empty($config['params']) && !empty($config['params']['header'])) ||
|
|
|
+ (!empty($currentApp['params']) && !empty($currentApp['params']['header']))
|
|
|
+ ) &&
|
|
|
+ !in_array("NotHeaders", $textAnnotations))
|
|
|
+ {
|
|
|
+ $headers = !empty($methodAnnotations['header'])?$methodAnnotations['header']:[];
|
|
|
+ $methodAnnotations['header'] = $this->mergeGlobalOrAppParams($headers,'header');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合并全局请求参数-query
|
|
|
+ if (
|
|
|
+ (
|
|
|
+ (!empty($config['params']) && !empty($config['params']['query'])) ||
|
|
|
+ (!empty($this->currentApp['params']) && !empty($this->currentApp['params']['query']))
|
|
|
+ ) &&
|
|
|
+ !in_array("NotQuerys", $textAnnotations))
|
|
|
+ {
|
|
|
+ $querys = !empty($methodAnnotations['query'])?$methodAnnotations['query']:[];
|
|
|
+ $methodAnnotations['query'] = $this->mergeGlobalOrAppParams($querys,'query');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合并全局请求参数-body
|
|
|
+ if (
|
|
|
+ (
|
|
|
+ (!empty($config['params']) && !empty($config['params']['body'])) ||
|
|
|
+ (!empty($this->currentApp['params']) && !empty($this->currentApp['params']['body']))
|
|
|
+ ) &&
|
|
|
+ !in_array("NotParams", $textAnnotations))
|
|
|
+ {
|
|
|
+ $params = !empty($methodAnnotations['param'])?$methodAnnotations['param']:[];
|
|
|
+ $methodAnnotations['param'] = $this->mergeGlobalOrAppParams($params,'body');
|
|
|
+ }
|
|
|
+
|
|
|
+ //添加成功响应体
|
|
|
+ $methodAnnotations['responseSuccess'] = $this->handleApiResponseSuccess($methodAnnotations,$textAnnotations);
|
|
|
+ //添加异常响应体
|
|
|
+ $methodAnnotations['responseError'] = $this->handleApiResponseError($methodAnnotations,$textAnnotations);
|
|
|
+
|
|
|
+ // 合并全局事件after
|
|
|
+ if (
|
|
|
+ (
|
|
|
+ (!empty($config['debug_events']) && !empty($config['debug_events']['after'])) ||
|
|
|
+ (!empty($this->currentApp['debug_events']) && !empty($this->currentApp['debug_events']['after']))
|
|
|
+ ) &&
|
|
|
+ !in_array("NotEvent", $textAnnotations))
|
|
|
+ {
|
|
|
+ $debugAfterEvents = !empty($methodAnnotations['after'])?$methodAnnotations['after']:[];
|
|
|
+ $methodAnnotations['after'] = $this->mergeGlobalOrAppEvents($debugAfterEvents,'after');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合并全局事件before
|
|
|
+ if (
|
|
|
+ (
|
|
|
+ (!empty($config['debug_events']) && !empty($config['debug_events']['before'])) ||
|
|
|
+ (!empty($this->currentApp['debug_events']) && !empty($this->currentApp['debug_events']['before']))
|
|
|
+ ) &&
|
|
|
+ !in_array("NotEvent", $textAnnotations))
|
|
|
+ {
|
|
|
+ $debugBeforeEvents = !empty($methodAnnotations['before'])?$methodAnnotations['before']:[];
|
|
|
+ $methodAnnotations['before'] = $this->mergeGlobalOrAppEvents($debugBeforeEvents,'before');
|
|
|
+ }
|
|
|
+
|
|
|
+ return $methodAnnotations;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取md注解内容
|
|
|
+ * @param $mdAnnotations
|
|
|
+ * @return mixed|string
|
|
|
+ */
|
|
|
+ protected function getFieldMarkdownContent($mdAnnotations){
|
|
|
+ if(!empty($mdAnnotations['name'])){
|
|
|
+ return $mdAnnotations['name'];
|
|
|
+ }else if(!empty($mdAnnotations['ref'])){
|
|
|
+ return ParseMarkdown::getContent($this->appKey,$mdAnnotations['ref']);
|
|
|
+ }
|
|
|
+ return $mdAnnotations;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取方法的注解,并处理参数
|
|
|
+ * @param $refMethod
|
|
|
+ * @param string $refField ref时指定处理的参数
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ protected function getMethodAnnotation($refMethod,$refField=""){
|
|
|
+ $annotations = (new ParseAnnotation($this->config))->getMethodAnnotation($refMethod);
|
|
|
+ // 需要处理的注解字段
|
|
|
+ if (!empty($refField)){
|
|
|
+ $handleFields = [$refField];
|
|
|
+ }else{
|
|
|
+ $handleFields = ["header","query","param","routeParam","returned","before","after","responseSuccess","responseError"];
|
|
|
+ }
|
|
|
+ foreach ($handleFields as $field) {
|
|
|
+ if (!empty($annotations[$field])){
|
|
|
+ $annotations[$field]=$this->handleMethodParams($annotations[$field],$field);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $annotations;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ protected function mergeGlobalOrAppParams($params,$paramType='param'){
|
|
|
+ $config = $this->config;
|
|
|
+ $currentApp = $this->currentApp;
|
|
|
+ $globalParams = [];
|
|
|
+ if (!empty($currentApp['params']) && !empty($currentApp['params'][$paramType])){
|
|
|
+ // 不合并global的处理方式
|
|
|
+ $globalParams = $currentApp['params'][$paramType];
|
|
|
+ // 合并global的处理方式
|
|
|
+ // $globalHeaders = Helper::arrayMergeAndUnique("name", $globalHeaders, $this->currentApp['params'][$paramType]);
|
|
|
+ }else if(!empty($config['params']) && !empty($config['params'][$paramType])){
|
|
|
+ $globalParams = $config['params'][$paramType];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($params) && count($params) && count($globalParams)) {
|
|
|
+ return Helper::arrayMergeAndUnique("name", $globalParams, $params);
|
|
|
+ }
|
|
|
+ return $globalParams;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function mergeGlobalOrAppEvents($events,$eventType='after'){
|
|
|
+ $config = $this->config;
|
|
|
+ $globalEvents = [];
|
|
|
+ if (!empty($this->currentApp['debug_events']) && !empty($this->currentApp['debug_events'][$eventType])){
|
|
|
+ $globalEvents = $this->currentApp['debug_events'][$eventType];
|
|
|
+ }else if(!empty($config['debug_events']) && !empty($config['debug_events'][$eventType])){
|
|
|
+ $globalEvents = $config['debug_events'][$eventType];
|
|
|
+ }
|
|
|
+ $mergeEvents = [];
|
|
|
+ foreach ($globalEvents as $item){
|
|
|
+ if (!empty($item['desc'])){
|
|
|
+ $item['desc'] = Lang::getLang($item['desc']);
|
|
|
+ }
|
|
|
+ $mergeEvents[] = $item;
|
|
|
+ }
|
|
|
+ if (!empty($events) && count($events)){
|
|
|
+ foreach ($events as $event) {
|
|
|
+ $mergeEvents[] = $event;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $mergeEvents;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理接口成功响应参数
|
|
|
+ * @param $methodAnnotations
|
|
|
+ * @param $textAnnotations
|
|
|
+ * @return array|mixed
|
|
|
+ */
|
|
|
+ protected function handleApiResponseSuccess($methodAnnotations,$textAnnotations){
|
|
|
+ $returned = !empty($methodAnnotations['returned'])?$methodAnnotations['returned']:"";
|
|
|
+ $currentApp = $this->currentApp;
|
|
|
+ $config = $this->config;
|
|
|
+ $mergeParams = [];
|
|
|
+ $paramType='success';
|
|
|
+ if (
|
|
|
+ in_array("NotResponses", $textAnnotations) ||
|
|
|
+ in_array("NotResponseSuccess", $textAnnotations)
|
|
|
+ ) {
|
|
|
+ // 注解了不使用全局响应
|
|
|
+ $mergeParams = [];
|
|
|
+ }else if (!empty($currentApp['responses']) && !empty($currentApp['responses'][$paramType])){
|
|
|
+ $mergeParams = $currentApp['params'][$paramType];
|
|
|
+ }else if(!empty($config['responses']) && !empty($config['responses'][$paramType])){
|
|
|
+ $mergeParams = $config['responses'][$paramType];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($methodAnnotations['responseSuccess'])){
|
|
|
+ if (!is_int(Helper::arrayKeyFirst($methodAnnotations['responseSuccess']))){
|
|
|
+ $methodResponseSuccess = [$methodAnnotations['responseSuccess']];
|
|
|
+ }else{
|
|
|
+ $methodResponseSuccess = $methodAnnotations['responseSuccess'];
|
|
|
+ }
|
|
|
+ $mergeParams = Helper::arrayMergeAndUnique("name", $mergeParams,$methodResponseSuccess);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($mergeParams) && count($mergeParams)){
|
|
|
+ $resData = [];
|
|
|
+ foreach ($mergeParams as $item) {
|
|
|
+ if (!empty($item['main']) && $item['main'] === true){
|
|
|
+ $item['children'] = $returned;
|
|
|
+ }
|
|
|
+ $item['desc'] = Lang::getLang($item['desc']);
|
|
|
+ if (!empty($item['md'])){
|
|
|
+ $item['md'] = ParseMarkdown::getContent($this->appKey,$item['md']);
|
|
|
+ }
|
|
|
+ $resData[]=$item;
|
|
|
+ }
|
|
|
+ return $resData;
|
|
|
+ }
|
|
|
+ return $returned;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理接口异常响应参数
|
|
|
+ * @param $methodAnnotations
|
|
|
+ * @param $textAnnotations
|
|
|
+ * @return array|mixed|void
|
|
|
+ */
|
|
|
+ protected function handleApiResponseError($methodAnnotations,$textAnnotations){
|
|
|
+ $config = $this->config;
|
|
|
+ $currentApp = $this->currentApp;
|
|
|
+ $responseErrors = [];
|
|
|
+ $paramType = "error";
|
|
|
+ $mergeParams = [];
|
|
|
+ if (
|
|
|
+ in_array("NotResponses", $textAnnotations) ||
|
|
|
+ in_array("NotResponseError", $textAnnotations)
|
|
|
+ ) {
|
|
|
+ // 注解了不使用全局响应
|
|
|
+ $mergeParams = [];
|
|
|
+ }else if (!empty($currentApp['responses']) && !empty($currentApp['responses'][$paramType])){
|
|
|
+ $mergeParams = $currentApp['params'][$paramType];
|
|
|
+ }else if(!empty($config['responses']) && !empty($config['responses'][$paramType])){
|
|
|
+ $mergeParams = $config['responses'][$paramType];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($methodAnnotations['responseError'])){
|
|
|
+ if (!is_int(Helper::arrayKeyFirst($methodAnnotations['responseError']))){
|
|
|
+ $methodResponseError = [$methodAnnotations['responseError']];
|
|
|
+ }else{
|
|
|
+ $methodResponseError = $methodAnnotations['responseError'];
|
|
|
+ }
|
|
|
+ $mergeParams = Helper::arrayMergeAndUnique("name", $mergeParams,$methodResponseError);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($mergeParams) && count($mergeParams)){
|
|
|
+ $resData = [];
|
|
|
+ foreach ($mergeParams as $item) {
|
|
|
+ $item['desc'] = Lang::getLang($item['desc']);
|
|
|
+ if (!empty($item['md'])){
|
|
|
+ $item['md'] = ParseMarkdown::getContent($this->appKey,$item['md']);
|
|
|
+ }
|
|
|
+ $resData[]=$item;
|
|
|
+ }
|
|
|
+ return $resData;
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public static function handleApiBaseInfo($methodInfo,$className,$methodName,$textAnnotations,$config){
|
|
|
+ // 无标题,且有文本注释
|
|
|
+ if (empty($methodInfo['title']) && !empty($textAnnotations) && count($textAnnotations) > 0) {
|
|
|
+ $methodInfo['title'] = Lang::getLang($textAnnotations[0]);
|
|
|
+ }else if (!empty($methodInfo['title'])){
|
|
|
+ $methodInfo['title'] = Lang::getLang($methodInfo['title']);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 默认method
|
|
|
+ if (!empty($methodInfo['method'])) {
|
|
|
+ $apiMethods = Helper::handleApiMethod($methodInfo['method']);
|
|
|
+ $methodInfo['method'] = count($apiMethods)==1?$apiMethods[0]:$apiMethods;
|
|
|
+ }else{
|
|
|
+ $methodInfo['method'] = !empty($config['default_method']) ? strtoupper($config['default_method']) : '*';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 默认default_author
|
|
|
+ if (empty($methodInfo['author']) && !empty($config['default_author']) && !in_array("NotDefaultAuthor", $textAnnotations)) {
|
|
|
+ $methodInfo['author'] = $config['default_author'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($methodInfo['tag'])){
|
|
|
+ $methodInfo['tag'] = static::handleTags($methodInfo['tag']);
|
|
|
+ }
|
|
|
+ // 无url,自动生成
|
|
|
+ if (empty($methodInfo['url'])) {
|
|
|
+ $methodInfo['url'] = static::autoCreateUrl($className,$methodName,$config);
|
|
|
+ } else if (!empty($methodInfo['url']) && is_string($methodInfo['url']) && substr($methodInfo['url'], 0, 1) != "/") {
|
|
|
+ $methodInfo['url'] = "/" . $methodInfo['url'];
|
|
|
+ }
|
|
|
+ $methodInfo['name'] = $methodName;
|
|
|
+ $methodInfo['menuKey'] = Helper::createApiKey($className,$methodName);
|
|
|
+ return $methodInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理方法的注解参数
|
|
|
+ * @param $params array 注解参数
|
|
|
+ * @param $field string 指定处理的参数字段名
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ protected function handleMethodParams($params,$field){
|
|
|
+ // 不处理合并的注解字段
|
|
|
+ $notMergeNameFields=['before','after'];
|
|
|
+ $data=[];
|
|
|
+ if (!empty($params)){
|
|
|
+ // 处理单个注解为对象的参数
|
|
|
+ if (!is_int(Helper::arrayKeyFirst($params))){
|
|
|
+ $params = [$params];
|
|
|
+ }
|
|
|
+ foreach ($params as $param) {
|
|
|
+ $item=$this->handleAnnotationsParamItem($param,$field);
|
|
|
+ if (!empty($item) && is_int(Helper::arrayKeyFirst($item))){
|
|
|
+ if (in_array($field,$notMergeNameFields)){
|
|
|
+ $data = $item;
|
|
|
+ }else{
|
|
|
+ $data = Helper::arrayMergeAndUnique("name",$data,$item);
|
|
|
+ }
|
|
|
+ }else if ($item!==false){
|
|
|
+ $data[]=$item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理注解某一参数
|
|
|
+ * @param $param array 参数
|
|
|
+ * @param $field string 处理的字段名
|
|
|
+ * @return array|array[]|mixed
|
|
|
+ */
|
|
|
+ protected function handleAnnotationsParamItem($param,$field){
|
|
|
+ // 事件字段,不处理ref的数据过滤
|
|
|
+ $eventFields=['before','after'];
|
|
|
+ $data = [];
|
|
|
+ if (!empty($param['ref'])){
|
|
|
+ $refParams = $this->renderRef($param['ref'],$field);
|
|
|
+ if (!empty($refParams[$field])){
|
|
|
+ if (in_array($field,$eventFields)){
|
|
|
+ $data=$refParams[$field];
|
|
|
+ }else{
|
|
|
+ $data = $this->handleRefData($param,$refParams[$field],$field);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }else if(!empty($param['table'])){
|
|
|
+ $tableParams = (new ParseModel($this->config))->getTableDocument($param['table'],[]);
|
|
|
+ $data = $this->handleRefData($param,$tableParams,$field);
|
|
|
+ } else{
|
|
|
+ $data = $param;
|
|
|
+ }
|
|
|
+ if (!empty($data['desc'])){
|
|
|
+ $data['desc'] = Lang::getLang($data['desc']);
|
|
|
+ }
|
|
|
+ if (!empty($data['md'])){
|
|
|
+ $data['md'] = ParseMarkdown::getContent($this->appKey,$data['md']);
|
|
|
+ }
|
|
|
+ if (!empty($data['children']) && is_array($data['children'])){
|
|
|
+ $childrenData = [];
|
|
|
+ foreach ($data['children'] as $child) {
|
|
|
+ $paramItem=$this->handleAnnotationsParamItem($child,$field);
|
|
|
+
|
|
|
+ if ($paramItem!==false){
|
|
|
+ if (!empty($paramItem) && is_array($paramItem) && Helper::arrayKeyFirst($paramItem)===0){
|
|
|
+ $childrenData = Helper::arrayMergeAndUnique("name",$childrenData,$paramItem);
|
|
|
+ }else{
|
|
|
+ $childrenData[] = $paramItem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $data['children'] = $childrenData;
|
|
|
+ }
|
|
|
+ if (!empty($data['type']) && $data['type'] === 'tree' ) {
|
|
|
+ // 类型为tree的
|
|
|
+ $data['children'][] = [
|
|
|
+ 'children' => $data['children'],
|
|
|
+ 'name' =>!empty($data['childrenField']) ?$data['childrenField']:'children',
|
|
|
+ 'type' => 'array',
|
|
|
+ 'desc' => !empty($data['childrenDesc'])?Lang::getLang($data['childrenDesc']):"",
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 自定义解析
|
|
|
+ if (!empty($this->config['parsesAnnotation'])){
|
|
|
+ $callback = $this->config['parsesAnnotation']($data);
|
|
|
+ if (!empty($callback)){
|
|
|
+ $data = $callback;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function handleTags($tagStr){
|
|
|
+ if (!empty($tagStr)) {
|
|
|
+ $tagStr = Lang::getLang($tagStr);
|
|
|
+ $tagList = [];
|
|
|
+ if (is_string($tagStr) && strpos($tagStr, ',') !== false) {
|
|
|
+ $tagArr = explode(",", $tagStr);
|
|
|
+ foreach ($tagArr as $tag) {
|
|
|
+ $tagList[]=Lang::getLang($tag);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $tagList = [Lang::getLang($tagStr)];
|
|
|
+ }
|
|
|
+ return $tagList;
|
|
|
+ }
|
|
|
+ return $tagStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自动生成url
|
|
|
+ * @param $method
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public static function autoCreateUrl($className,$methodName,$config): string
|
|
|
+ {
|
|
|
+
|
|
|
+ $pathArr = explode("\\", $className);
|
|
|
+ $filterPathNames = !empty($config['auto_url']) && !empty($config['auto_url']['filter_keys'])?$config['auto_url']['filter_keys']:[];
|
|
|
+ $classUrlArr = [];
|
|
|
+ foreach ($pathArr as $item) {
|
|
|
+ if (!in_array($item, $filterPathNames)) {
|
|
|
+ if (!empty($config['auto_url'])){
|
|
|
+ $key = $item;
|
|
|
+ if (!empty($config['auto_url']['letter_rule'])){
|
|
|
+ switch ($config['auto_url']['letter_rule']) {
|
|
|
+ case 'lcfirst':
|
|
|
+ $key = lcfirst($item);
|
|
|
+ break;
|
|
|
+ case 'ucfirst':
|
|
|
+ $key = ucfirst($item);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ $key = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!empty($config['auto_url']['handle_key'])){
|
|
|
+ $classUrlArr[] = $config['auto_url']['handle_key']($key);
|
|
|
+ }else{
|
|
|
+ $classUrlArr[] = $key;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ $classUrlArr[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $classUrl = implode('/', $classUrlArr);
|
|
|
+ $prefix = !empty($config['auto_url']) && !empty($config['auto_url']['prefix'])?$config['auto_url']['prefix']:"";
|
|
|
+ $url = $prefix . '/' . $classUrl . '/' . $methodName;
|
|
|
+ if (!empty($config['auto_url']) && !empty($config['auto_url']['custom']) && is_callable($config['auto_url']['custom'])){
|
|
|
+ return $config['auto_url']['custom']($className,$methodName,$url);
|
|
|
+ }
|
|
|
+ return $url;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * ref引用
|
|
|
+ */
|
|
|
+ public function renderRef($refPath,$field): array
|
|
|
+ {
|
|
|
+ $res = ['type' => 'model'];
|
|
|
+ $config = $this->config;
|
|
|
+ $methodName ="";
|
|
|
+ if (is_string($refPath)){
|
|
|
+ if (strpos($refPath, '\\') === false) {
|
|
|
+ // 引入通用注解
|
|
|
+ $classPath = $config['definitions'];
|
|
|
+ $methodName = $refPath;
|
|
|
+ }else if (class_exists($refPath)) {
|
|
|
+ // use类
|
|
|
+ $classPath = $refPath;
|
|
|
+ }else if (strpos($refPath, '@') !== false){
|
|
|
+ // 带@指定方法
|
|
|
+ $pathArr = explode("@", $refPath);
|
|
|
+ $classPath = $pathArr[0];
|
|
|
+ $methodName = $pathArr[1];
|
|
|
+ }else{
|
|
|
+ // 直接指定方法
|
|
|
+ $pathArr = explode("\\", $refPath);
|
|
|
+ $methodName = $pathArr[count($pathArr) - 1];
|
|
|
+ unset($pathArr[count($pathArr) - 1]);
|
|
|
+ $classPath = implode("\\", $pathArr);
|
|
|
+ }
|
|
|
+ }else if(is_array($refPath)){
|
|
|
+ $classPath = $refPath[0];
|
|
|
+ $methodName = !empty($refPath[1])?$refPath[1]:"";
|
|
|
+ }else{
|
|
|
+ // 未知ref
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ $modelClass = ParseModel::getModelClass($classPath);
|
|
|
+ $classReflect = new \ReflectionClass($classPath);
|
|
|
+ if (!empty($methodName) && empty($modelClass)){
|
|
|
+ // 类ref引用
|
|
|
+ $methodName = trim($methodName);
|
|
|
+ $refMethod = $classReflect->getMethod($methodName);
|
|
|
+ $res = $this->getMethodAnnotation($refMethod,$field);
|
|
|
+ return $res;
|
|
|
+ }
|
|
|
+ // 模型解析
|
|
|
+ $modelParams = (new ParseModel($config))->parseModelTable($modelClass,$classReflect,$methodName);
|
|
|
+ return [$field=>$modelParams];
|
|
|
+
|
|
|
+ } catch (\ReflectionException $e) {
|
|
|
+ throw new ErrorException($e->getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public function handleRefData($annotation,$refParams, string $field): array
|
|
|
+ {
|
|
|
+
|
|
|
+ // 过滤field
|
|
|
+ if (!empty($annotation['field'])) {
|
|
|
+ $refParams = static::filterParamsField($refParams, $annotation['field'], 'field');
|
|
|
+ }
|
|
|
+ // 过滤withoutField
|
|
|
+ if (!empty($annotation['withoutField'])) {
|
|
|
+ $refParams = static::filterParamsField($refParams, $annotation['withoutField'], 'withoutField');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($annotation['name'])) {
|
|
|
+ if (!empty($annotation['children'])) {
|
|
|
+ $annotation['children'] = Helper::arrayMergeAndUnique("name",$refParams,$annotation['children']);
|
|
|
+ }else{
|
|
|
+ $annotation['children'] = $refParams;
|
|
|
+ }
|
|
|
+ return $annotation;
|
|
|
+ }
|
|
|
+// else{
|
|
|
+// if (!empty($annotation[$field])) {
|
|
|
+// $annotation[$field] = Helper::arrayMergeAndUnique("name",$refParams,$annotation[$field]);
|
|
|
+// }
|
|
|
+// }
|
|
|
+ return $refParams;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public function handleEventAnnotation($annotation,$type){
|
|
|
+ $config = $this->config;
|
|
|
+ if (!empty($annotation->ref)){
|
|
|
+ if (strpos($annotation->ref, '\\') === false && !empty($config['definitions']) ) {
|
|
|
+ $refPath = $config['definitions'] . '\\' . $annotation->ref;
|
|
|
+ $data = $this->renderService($refPath);
|
|
|
+ if (!empty($data[$type])){
|
|
|
+ return $data[$type];
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!empty($annotation->value) && is_array($annotation->value)){
|
|
|
+ $beforeInfo = Helper::objectToArray($annotation);
|
|
|
+ $valueList = [];
|
|
|
+ foreach ($annotation->value as $valueItem){
|
|
|
+ $valueItemInfo = Helper::objectToArray($valueItem);
|
|
|
+ if ($valueItem instanceof Before){
|
|
|
+ $valueItemInfo['type'] = "before";
|
|
|
+ }else if ($valueItem instanceof After){
|
|
|
+ $valueItemInfo['type'] = "after";
|
|
|
+ }
|
|
|
+ $valueList[] = $valueItemInfo;
|
|
|
+ }
|
|
|
+ $beforeInfo['value'] = $valueList;
|
|
|
+ return [$beforeInfo];
|
|
|
+ }
|
|
|
+ else if (!empty($annotation->value) && is_object($annotation->value)){
|
|
|
+ $valueItemInfo = Helper::objectToArray($annotation->value);
|
|
|
+ if ($annotation->value instanceof Before){
|
|
|
+ $valueItemInfo['type'] = "before";
|
|
|
+ }else if ($annotation->value instanceof After){
|
|
|
+ $valueItemInfo['type'] = "after";
|
|
|
+ }
|
|
|
+ $annotation->value = [$valueItemInfo];
|
|
|
+ return [$annotation];
|
|
|
+ }else{
|
|
|
+ return [$annotation];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 过滤指定字段、或只取指定字段
|
|
|
+ * @param $data 参数
|
|
|
+ * @param $fields 指定字段
|
|
|
+ * @param string $type 处理类型
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function filterParamsField(array $data, $fields, string $type = "field"): array
|
|
|
+ {
|
|
|
+ if (!empty($fields) && is_string($fields)){
|
|
|
+ if (strpos($fields, ',') !== false){
|
|
|
+ $fieldArr = explode(',', $fields);
|
|
|
+ }else{
|
|
|
+ $fieldArr = [$fields];
|
|
|
+ }
|
|
|
+ }else if (!empty($fields) && is_array($fields)){
|
|
|
+ if (Helper::arrayKeyFirst($fields)=="name"){
|
|
|
+ $fieldArr = $fields['name'];
|
|
|
+ }else{
|
|
|
+ $fieldArr = $fields;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+ $dataList = [];
|
|
|
+ foreach ($data as $item) {
|
|
|
+ $has = !empty($item['name']) && in_array($item['name'], $fieldArr);
|
|
|
+ if ($has && $type === 'field') {
|
|
|
+ $dataList[] = $item;
|
|
|
+ } else if (!($has) && $type == "withoutField") {
|
|
|
+ $dataList[] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $dataList;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|