quguofeng il y a 2 ans
Parent
commit
8cc18c05a6
100 fichiers modifiés avec 4460 ajouts et 4137 suppressions
  1. 2 2
      composer.json
  2. 2 1
      vendor/composer/autoload_psr4.php
  3. 6 1
      vendor/composer/autoload_static.php
  4. 94 23
      vendor/composer/installed.json
  5. 17 8
      vendor/composer/installed.php
  6. 0 0
      vendor/hg/apidoc-thinkphp/.gitignore
  7. 1 1
      vendor/hg/apidoc-thinkphp/LICENSE
  8. 75 0
      vendor/hg/apidoc-thinkphp/README.md
  9. 7 12
      vendor/hg/apidoc-thinkphp/composer.json
  10. 69 74
      vendor/hg/apidoc-thinkphp/src/Auth.php
  11. 287 0
      vendor/hg/apidoc-thinkphp/src/Controller.php
  12. 36 0
      vendor/hg/apidoc-thinkphp/src/Service.php
  13. 185 177
      vendor/hg/apidoc-thinkphp/src/Utils.php
  14. 0 12
      vendor/hg/apidoc-thinkphp/src/annotation/AddField.php
  15. 1 1
      vendor/hg/apidoc-thinkphp/src/annotation/After.php
  16. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Author.php
  17. 1 1
      vendor/hg/apidoc-thinkphp/src/annotation/Before.php
  18. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/ContentType.php
  19. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Desc.php
  20. 2 12
      vendor/hg/apidoc-thinkphp/src/annotation/EventBase.php
  21. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Field.php
  22. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Group.php
  23. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Header.php
  24. 1 1
      vendor/hg/apidoc-thinkphp/src/annotation/Md.php
  25. 1 1
      vendor/hg/apidoc-thinkphp/src/annotation/Method.php
  26. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Param.php
  27. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/ParamBase.php
  28. 2 4
      vendor/hg/apidoc-thinkphp/src/annotation/ParamMd.php
  29. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/ParamType.php
  30. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Returned.php
  31. 5 4
      vendor/hg/apidoc-thinkphp/src/annotation/ReturnedMd.php
  32. 17 0
      vendor/hg/apidoc-thinkphp/src/annotation/Route.php
  33. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Rule.php
  34. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Sort.php
  35. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Tag.php
  36. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/Title.php
  37. 1 1
      vendor/hg/apidoc-thinkphp/src/annotation/Url.php
  38. 0 0
      vendor/hg/apidoc-thinkphp/src/annotation/WithoutField.php
  39. 51 0
      vendor/hg/apidoc-thinkphp/src/config.php
  40. 33 0
      vendor/hg/apidoc-thinkphp/src/exception/AuthException.php
  41. 47 0
      vendor/hg/apidoc-thinkphp/src/exception/ErrorException.php
  42. 88 80
      vendor/hg/apidoc-thinkphp/src/generator/Index.php
  43. 6 11
      vendor/hg/apidoc-thinkphp/src/generator/ParseTemplate.php
  44. 48 0
      vendor/hg/apidoc-thinkphp/src/parseApi/CacheApiData.php
  45. 863 0
      vendor/hg/apidoc-thinkphp/src/parseApi/ParseAnnotation.php
  46. 31 50
      vendor/hg/apidoc-thinkphp/src/parseApi/ParseMarkdown.php
  47. 245 0
      vendor/hg/apidoc-thinkphp/src/parseApi/ParseModel.php
  48. 0 86
      vendor/hg/apidoc/README.md
  49. 0 24
      vendor/hg/apidoc/src/ConfigProvider.php
  50. 0 321
      vendor/hg/apidoc/src/Controller.php
  51. 0 40
      vendor/hg/apidoc/src/annotation/Query.php
  52. 0 20
      vendor/hg/apidoc/src/annotation/ResponseErrorMd.php
  53. 0 33
      vendor/hg/apidoc/src/annotation/ResponseSuccess.php
  54. 0 45
      vendor/hg/apidoc/src/annotation/RouteParam.php
  55. 0 92
      vendor/hg/apidoc/src/config.php
  56. 0 62
      vendor/hg/apidoc/src/exception/ErrorException.php
  57. 0 33
      vendor/hg/apidoc/src/exception/HttpException.php
  58. 0 17
      vendor/hg/apidoc/src/middleware/LaravelMiddleware.php
  59. 0 17
      vendor/hg/apidoc/src/middleware/ThinkPHPMiddleware.php
  60. 0 35
      vendor/hg/apidoc/src/parses/ParseAnnotation.php
  61. 0 852
      vendor/hg/apidoc/src/parses/ParseApiDetail.php
  62. 0 353
      vendor/hg/apidoc/src/parses/ParseApiMenus.php
  63. 0 104
      vendor/hg/apidoc/src/parses/ParseCodeTemplate.php
  64. 0 277
      vendor/hg/apidoc/src/parses/ParseModel.php
  65. 0 133
      vendor/hg/apidoc/src/providers/BaseService.php
  66. 0 56
      vendor/hg/apidoc/src/providers/CommonService.php
  67. 0 80
      vendor/hg/apidoc/src/providers/HyperfService.php
  68. 0 84
      vendor/hg/apidoc/src/providers/LaravelService.php
  69. 0 71
      vendor/hg/apidoc/src/providers/ThinkPHP5Service.php
  70. 0 78
      vendor/hg/apidoc/src/providers/ThinkPHPService.php
  71. 0 22
      vendor/hg/apidoc/src/utils/ApiCrossDomain.php
  72. 0 298
      vendor/hg/apidoc/src/utils/Cache.php
  73. 0 89
      vendor/hg/apidoc/src/utils/ConfigProvider.php
  74. 0 238
      vendor/hg/apidoc/src/utils/DirAndFile.php
  75. 0 54
      vendor/hg/apidoc/src/utils/Lang.php
  76. 0 46
      vendor/hg/apidoc/src/utils/Request.php
  77. 3 0
      vendor/symfony/class-loader/.gitignore
  78. 145 0
      vendor/symfony/class-loader/ApcClassLoader.php
  79. 41 0
      vendor/symfony/class-loader/CHANGELOG.md
  80. 453 0
      vendor/symfony/class-loader/ClassCollectionLoader.php
  81. 211 0
      vendor/symfony/class-loader/ClassLoader.php
  82. 165 0
      vendor/symfony/class-loader/ClassMapGenerator.php
  83. 19 0
      vendor/symfony/class-loader/LICENSE
  84. 68 0
      vendor/symfony/class-loader/MapClassLoader.php
  85. 96 0
      vendor/symfony/class-loader/Psr4ClassLoader.php
  86. 14 0
      vendor/symfony/class-loader/README.md
  87. 200 0
      vendor/symfony/class-loader/Tests/ApcClassLoaderTest.php
  88. 317 0
      vendor/symfony/class-loader/Tests/ClassCollectionLoaderTest.php
  89. 238 0
      vendor/symfony/class-loader/Tests/ClassLoaderTest.php
  90. 151 0
      vendor/symfony/class-loader/Tests/ClassMapGeneratorTest.php
  91. 17 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/Bar.php
  92. 17 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/Baz.php
  93. 17 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/Foo.php
  94. 17 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/FooBar.php
  95. 6 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/Pearlike/Bar.php
  96. 6 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/Pearlike/Baz.php
  97. 6 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/Pearlike/Foo.php
  98. 6 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Bar.php
  99. 6 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Foo.php
  100. 17 0
      vendor/symfony/class-loader/Tests/Fixtures/Apc/alpha/Apc/NamespaceCollision/A/Bar.php

+ 2 - 2
composer.json

@@ -23,10 +23,10 @@
     "zoujingli/weopen-developer": "dev-master",
     "overtrue/wechat": "~4.0",
     "firebase/php-jwt": "^5.2",
-    "hg/apidoc": "^4.1",
     "alibabacloud/client": "^1.5",
     "alipaysdk/easysdk": "^2.2",
-    "alibabacloud/dingtalk": "^1.4"
+    "alibabacloud/dingtalk": "^1.4",
+    "hg/apidoc-thinkphp": "^3.1"
   },
   "repositories": {
     "packagist": {

+ 2 - 1
vendor/composer/autoload_psr4.php

@@ -8,7 +8,7 @@ $baseDir = dirname($vendorDir);
 return array(
     'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
     'library\\' => array($vendorDir . '/zoujingli/think-library/src'),
-    'hg\\apidoc\\' => array($vendorDir . '/hg/apidoc/src'),
+    'hg\\apidoc\\' => array($vendorDir . '/hg/apidoc-thinkphp/src'),
     'clagiordano\\weblibs\\configmanager\\' => array($vendorDir . '/clagiordano/weblibs-configmanager/src'),
     'WePay\\' => array($vendorDir . '/zoujingli/wechat-developer/WePay'),
     'WePayV3\\' => array($vendorDir . '/zoujingli/wechat-developer/WePayV3'),
@@ -27,6 +27,7 @@ return array(
     'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
     'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
     'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
+    'Symfony\\Component\\ClassLoader\\' => array($vendorDir . '/symfony/class-loader'),
     'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'),
     'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'),
     'Qiniu\\' => array($vendorDir . '/qiniu/php-sdk/src/Qiniu'),

+ 6 - 1
vendor/composer/autoload_static.php

@@ -63,6 +63,7 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
             'Symfony\\Component\\OptionsResolver\\' => 34,
             'Symfony\\Component\\HttpFoundation\\' => 33,
             'Symfony\\Component\\EventDispatcher\\' => 34,
+            'Symfony\\Component\\ClassLoader\\' => 30,
             'Symfony\\Component\\Cache\\' => 24,
             'Symfony\\Bridge\\PsrHttpMessage\\' => 30,
         ),
@@ -223,7 +224,7 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         ),
         'hg\\apidoc\\' => 
         array (
-            0 => __DIR__ . '/..' . '/hg/apidoc/src',
+            0 => __DIR__ . '/..' . '/hg/apidoc-thinkphp/src',
         ),
         'clagiordano\\weblibs\\configmanager\\' => 
         array (
@@ -299,6 +300,10 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         array (
             0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
         ),
+        'Symfony\\Component\\ClassLoader\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/class-loader',
+        ),
         'Symfony\\Component\\Cache\\' => 
         array (
             0 => __DIR__ . '/..' . '/symfony/cache',

+ 94 - 23
vendor/composer/installed.json

@@ -1767,18 +1767,18 @@
             "install-path": "../guzzlehttp/psr7"
         },
         {
-            "name": "hg/apidoc",
-            "version": "v4.1.5",
-            "version_normalized": "4.1.5.0",
+            "name": "hg/apidoc-thinkphp",
+            "version": "v3.1.9",
+            "version_normalized": "3.1.9.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/HGthecode/apidoc-php.git",
-                "reference": "2daa881bce690d055bed0c86a882f0f6a3dd47aa"
+                "url": "https://github.com/HGthecode/thinkphp-apidoc.git",
+                "reference": "877ff07f80d75444b20f0f252e0e5f67e82f6eb1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/HGthecode/apidoc-php/zipball/2daa881bce690d055bed0c86a882f0f6a3dd47aa",
-                "reference": "2daa881bce690d055bed0c86a882f0f6a3dd47aa",
+                "url": "https://api.github.com/repos/HGthecode/thinkphp-apidoc/zipball/877ff07f80d75444b20f0f252e0e5f67e82f6eb1",
+                "reference": "877ff07f80d75444b20f0f252e0e5f67e82f6eb1",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -1789,26 +1789,19 @@
             },
             "require": {
                 "doctrine/annotations": "^1.6",
-                "php": ">=7.1"
+                "php": ">=7.1.0",
+                "symfony/class-loader": "~3.4.47"
             },
-            "time": "2022-12-07T01:10:51+00:00",
-            "type": "library",
+            "time": "2022-08-26T05:55:49+00:00",
+            "type": "think-extend",
             "extra": {
-                "laravel": {
-                    "providers": [
-                        "hg\\apidoc\\providers\\LaravelService"
-                    ]
-                },
                 "think": {
                     "services": [
-                        "hg\\apidoc\\providers\\ThinkPHPService"
+                        "hg\\apidoc\\Service"
                     ],
                     "config": {
                         "apidoc": "src/config.php"
                     }
-                },
-                "hyperf": {
-                    "config": "hg\\apidoc\\ConfigProvider"
                 }
             },
             "installation-source": "dist",
@@ -1827,22 +1820,23 @@
                     "email": "376401263@qq.com"
                 }
             ],
-            "description": "注释自动生成API文档、在线调试、Markdown文档、代码生成器",
+            "description": "thinkphp API文档自动生成",
             "keywords": [
                 "apidoc",
                 "api文档",
                 "markdown",
                 "php api文档",
                 "php接口文档",
+                "thinkphp",
                 "接口文档",
                 "注释生成",
                 "自动生成api"
             ],
             "support": {
-                "issues": "https://github.com/HGthecode/apidoc-php/issues",
-                "source": "https://github.com/HGthecode/apidoc-php/tree/v4.1.5"
+                "issues": "https://github.com/HGthecode/thinkphp-apidoc/issues",
+                "source": "https://github.com/HGthecode/thinkphp-apidoc/tree/v3.1.9"
             },
-            "install-path": "../hg/apidoc"
+            "install-path": "../hg/apidoc-thinkphp"
         },
         {
             "name": "lizhichao/one-sm",
@@ -3140,6 +3134,83 @@
             "install-path": "../symfony/cache-contracts"
         },
         {
+            "name": "symfony/class-loader",
+            "version": "v3.4.47",
+            "version_normalized": "3.4.47.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/class-loader.git",
+                "reference": "a22265a9f3511c0212bf79f54910ca5a77c0e92c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/class-loader/zipball/a22265a9f3511c0212bf79f54910ca5a77c0e92c",
+                "reference": "a22265a9f3511c0212bf79f54910ca5a77c0e92c",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8"
+            },
+            "require-dev": {
+                "symfony/finder": "~2.8|~3.0|~4.0",
+                "symfony/polyfill-apcu": "~1.1"
+            },
+            "suggest": {
+                "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM"
+            },
+            "time": "2020-10-24T10:57:07+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\ClassLoader\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony ClassLoader Component",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/class-loader/tree/v3.4.47"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/class-loader"
+        },
+        {
             "name": "symfony/deprecation-contracts",
             "version": "v2.5.2",
             "version_normalized": "2.5.2.0",

+ 17 - 8
vendor/composer/installed.php

@@ -5,7 +5,7 @@
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
-        'reference' => '3a04b1f76489516e051c2d92f4b0c192acbde037',
+        'reference' => '8a2bea1ae34a93de7b2018d163362acda72b17c4',
         'name' => 'zoujingli/thinkadmin',
         'dev' => true,
     ),
@@ -226,13 +226,13 @@
             'reference' => '67c26b443f348a51926030c83481b85718457d3d',
             'dev_requirement' => false,
         ),
-        'hg/apidoc' => array(
-            'pretty_version' => 'v4.1.5',
-            'version' => '4.1.5.0',
-            'type' => 'library',
-            'install_path' => __DIR__ . '/../hg/apidoc',
+        'hg/apidoc-thinkphp' => array(
+            'pretty_version' => 'v3.1.9',
+            'version' => '3.1.9.0',
+            'type' => 'think-extend',
+            'install_path' => __DIR__ . '/../hg/apidoc-thinkphp',
             'aliases' => array(),
-            'reference' => '2daa881bce690d055bed0c86a882f0f6a3dd47aa',
+            'reference' => '877ff07f80d75444b20f0f252e0e5f67e82f6eb1',
             'dev_requirement' => false,
         ),
         'lizhichao/one-sm' => array(
@@ -454,6 +454,15 @@
                 0 => '1.0|2.0',
             ),
         ),
+        'symfony/class-loader' => array(
+            'pretty_version' => 'v3.4.47',
+            'version' => '3.4.47.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/class-loader',
+            'aliases' => array(),
+            'reference' => 'a22265a9f3511c0212bf79f54910ca5a77c0e92c',
+            'dev_requirement' => false,
+        ),
         'symfony/deprecation-contracts' => array(
             'pretty_version' => 'v2.5.2',
             'version' => '2.5.2.0',
@@ -619,7 +628,7 @@
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
-            'reference' => '3a04b1f76489516e051c2d92f4b0c192acbde037',
+            'reference' => '8a2bea1ae34a93de7b2018d163362acda72b17c4',
             'dev_requirement' => false,
         ),
         'zoujingli/wechat-developer' => array(

+ 0 - 0
vendor/hg/apidoc/.gitignore → vendor/hg/apidoc-thinkphp/.gitignore


+ 1 - 1
vendor/hg/apidoc/LICENSE → vendor/hg/apidoc-thinkphp/LICENSE

@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2022 HG
+Copyright (c) 2021 HG
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 75 - 0
vendor/hg/apidoc-thinkphp/README.md

@@ -0,0 +1,75 @@
+<p align="center">
+    <img width="120" src="https://apidoc.demo.hg-code.com/images/logo.png">
+</p>
+
+<h1 align="center">
+  ThinkPHP ApiDoc
+</h1>
+
+<div align="center">
+ 基于 ThinkPHP 的API接口开发工具
+</div>
+
+<div align="center" style="margin-top:10px;margin-bottom:50px;">
+<a href="https://packagist.org/packages/hg/apidoc"><img src="https://img.shields.io/packagist/v/hg/apidoc"></a>
+<a href="https://packagist.org/packages/hg/apidoc"><img src="https://img.shields.io/packagist/dt/hg/apidoc"></a>
+<a href="https://packagist.org/packages/hg/apidoc"><img src="https://img.shields.io/packagist/l/hg/apidoc"></a>
+<a href="https://github.com/HGthecode/thinkphp-apidoc"><img src="https://img.shields.io/github/issues/HGthecode/thinkphp-apidoc"></a>
+<a href="https://github.com/HGthecode/thinkphp-apidoc"><img src="https://img.shields.io/github/forks/HGthecode/thinkphp-apidoc"></a>
+
+</div>
+
+
+## 🤷‍♀️ Apidoc是什么?
+
+如今,前后端分离的开发模式以必不可少,基于ThinkPHP可以很方便的作为Api接口的开发。可是一个Api开发过程中需要快速调试,开发完成后需要给其它开发者对接等,这时一个功能全面的Api文档工具,就显得特别重要。
+
+大多数开发者可能都是通过各种工具配合来达到这一目的,其各种工具的安装和配置也是繁琐。甚至还有通过word等文本工具手写api文档的,这样的开发效率与可维护性是非常差的。
+
+综合种种Api开发中的痛点,我们专为ThinkPHP开发了Apidoc的扩展,本插件可通过简单的注解即可生成Api文档,及帮助开发者提高生产效率的在线调试、快速生成Crud、一键生成整个模块Api等,涵盖Api开发方方面面。
+
+
+## ✨特性
+
+- 开箱即用:无繁杂的配置、安装后按文档编写注释即可自动生成API文档。
+- 在线调试:在线文档可直接调试,支持全局参数、Mock调试数据、事件执行,接口调试省时省力。
+- 轻松使用:支持公共注释定义、业务逻辑层、数据表字段等引用,几句注释即可完成。
+- 安全高效:支持访问密码验证、应用/版本独立密码;支持文档缓存。
+- 多应用/多版本:可适应各种单应用、多应用、多版本的项目的Api管理。
+- Markdown文档:支持.md文件的文档展示。
+- 控制器分组:支持控制器多级分组,更精细化管理接口目录。
+- 多语言:可结合TP多语言能力,实现接口文档的语言切换。
+
+
+## 📌兼容
+
+ThinkPHP 5.1
+
+ThinkPHP 6.x
+
+## 📖使用文档
+
+[ThinkPHP ApiDoc V3.x文档](https://hg-code.gitee.io/thinkphp-apidoc/)
+
+
+## 🏆支持我们
+
+如果本项目对您有所帮助,请点个Star支持我们
+
+- [Github](https://github.com/HGthecode/thinkphp-apidoc) -> <a href="https://github.com/HGthecode/thinkphp-apidoc" target="_blank">
+  <img height="22" src="https://img.shields.io/github/stars/HGthecode/thinkphp-apidoc?style=social" class="attachment-full size-full" alt="Star me on GitHub" data-recalc-dims="1" /></a>
+- [Gitee](https://gitee.com/hg-code/thinkphp-apidoc) -> <a href="https://gitee.com/hg-code/thinkphp-apidoc/stargazers"><img src="https://gitee.com/hg-code/thinkphp-apidoc/badge/star.svg" alt="star"></a>
+
+## 💡鸣谢
+
+<a href="http://www.thinkphp.cn/" target="_blank">ThinkPHP</a>
+
+<a href="https://github.com/doctrine/annotations" target="_blank">doctrine/annotations</a>
+
+
+## 🔗链接
+ <a href="https://github.com/HGthecode/apidoc-ui" target="_blank">ApiDoc UI</a>
+ 
+ <a href="https://github.com/HGthecode/thinkphp-apidoc-demo" target="_blank">ApiDoc Demo</a>
+
+

+ 7 - 12
vendor/hg/apidoc/composer.json → vendor/hg/apidoc-thinkphp/composer.json

@@ -1,7 +1,9 @@
 {
     "name": "hg/apidoc",
-    "description": "注释自动生成API文档、在线调试、Markdown文档、代码生成器",
+    "description": "thinkphp API文档自动生成",
+    "type": "think-extend",
     "keywords": [
+        "thinkphp",
         "apidoc",
         "api文档",
         "接口文档",
@@ -12,8 +14,9 @@
         "Markdown"
       ],
     "require": {
-        "php": ">=7.1",
-        "doctrine/annotations": "^1.6"
+        "php": ">=7.1.0",
+        "doctrine/annotations": "^1.6",
+        "symfony/class-loader": "~3.4.47"
     },
     "license": "MIT",
     "authors": [
@@ -28,21 +31,13 @@
         }
     },
     "extra": {
-        "laravel": {
-            "providers": [
-                "hg\\apidoc\\providers\\LaravelService"
-            ]
-        },
         "think": {
             "services": [
-                "hg\\apidoc\\providers\\ThinkPHPService"
+                "hg\\apidoc\\Service"
             ],
             "config": {
                 "apidoc": "src/config.php"
             }
-        },
-        "hyperf": {
-            "config": "hg\\apidoc\\ConfigProvider"
         }
     },
     "minimum-stability": "dev"

+ 69 - 74
vendor/hg/apidoc/src/Auth.php → vendor/hg/apidoc-thinkphp/src/Auth.php

@@ -3,98 +3,56 @@ declare(strict_types = 1);
 
 namespace hg\apidoc;
 
-use hg\apidoc\exception\ErrorException;
-use hg\apidoc\utils\ConfigProvider;
-use hg\apidoc\utils\Helper;
+use think\facade\Config;
+use think\facade\Request;
+use hg\apidoc\exception\AuthException;
 
 class Auth
 {
-    protected $authConfig = [];
+    protected $config = [];
 
-    public function __construct($config)
+
+    public function __construct()
     {
-        $authConfig = !empty($config['auth'])?$config['auth']:[];
-        if (empty($authConfig['secret_key'])){
-            $authConfig['secret_key'] = "apidoc#hgcode";
-        }
-        if (empty($authConfig['expire'])){
-            $authConfig['expire'] = 86400;
-        }
-        $this->authConfig = $authConfig;
+        $this->config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
     }
 
     /**
-     * 验证密码是否正确
+     * 验证密码
      * @param $password
      * @return false|string
      */
     public function verifyAuth(string $password, string $appKey)
     {
-        $authConfig = $this->authConfig;
         if (!empty($appKey)) {
-            $currentAppConfig = Helper::getCurrentAppConfig($appKey);
-            $currentApp  = $currentAppConfig['appConfig'];
+            $currentApps = (new Utils())->getCurrentApps($appKey);
+            $currentApp  = $currentApps[count($currentApps) - 1];
             if (!empty($currentApp) && !empty($currentApp['password'])) {
                 // 应用密码
                 if (md5($currentApp['password']) === $password) {
-                    return $this->createToken($currentApp['password'],$authConfig['expire']);
+                    return $this->createToken($currentApp['password']);
                 }
-                throw new ErrorException("password error");
+                throw new AuthException("password error");
             }
         }
-        if ($authConfig['enable']) {
+        if ($this->config['auth']['enable']) {
             // 密码验证
-            if (md5($authConfig['password']) === $password) {
-                return $this->createToken($authConfig['password'],$authConfig['expire']);
+            if (md5($this->config['auth']['password']) === $password) {
+                return $this->createToken($this->config['auth']['password']);
             }
-            throw new ErrorException("password error");
+            throw new AuthException("password error");
         }
         return false;
     }
 
     /**
-     * 验证token是否可用
-     * @param $request
-     * @return bool
-     */
-    public function checkAuth($params=[]): bool
-    {
-        $authConfig = $this->authConfig;
-        $token = !empty($params['token'])?$params['token']:"";
-        $appKey = !empty($params['appKey'])?$params['appKey']:"";
-        if (!empty($appKey)) {
-            $currentAppConfig = Helper::getCurrentAppConfig($appKey);
-            $currentApp  = $currentAppConfig['appConfig'];
-            if (!empty($currentApp) && !empty($currentApp['password'])) {
-                if (empty($token)) {
-                    throw new ErrorException("token not found");
-                }
-                // 应用密码
-                if ($this->checkToken($token, $currentApp['password'])) {
-                    return true;
-                } else {
-                    throw new ErrorException("token error");
-                }
-            } else if (empty($authConfig['enable'])) {
-                return true;
-            }
-        }
-        if($authConfig['enable'] && empty($token)){
-            throw new ErrorException("token not found");
-        }else if (!empty($token) && !$this->checkToken($token, "")  && $authConfig['enable']) {
-            throw new ErrorException("token error");
-        }
-        return true;
-    }
-
-
-    /**
      * 获取tokencode
      * @param string $password
      * @return string
      */
-    protected static function getTokenCode(string $password): string
+    protected function getTokenCode(string $password): string
     {
+//        return md5(md5($password) . strtotime(date('Y-m-d', time())));
         return md5(md5($password));
     }
 
@@ -104,39 +62,76 @@ class Auth
      * @param string $password
      * @return string
      */
-    protected function createToken(string $password): string
+    public function createToken(string $password): string
     {
-        $authConfig = $this->authConfig;
+        $expire = $this->config['auth']['expire']?$this->config['auth']['expire']:86400;
         $data = [
-            'key'=>static::getTokenCode($password),
-            'expire'=>time()+$authConfig['expire']
+            'key'=>$this->getTokenCode($password),
+            'expire'=>time()+$expire
         ];
         $code = json_encode($data);
-        return static::handleToken($code, "CE",$authConfig['secret_key']);
+        return $this->handleToken($code, "CE");
     }
 
     /**
-     * 验证token是否可用
+     * 验证token
      * @param $token
      * @return bool
      */
-    protected function checkToken(string $token, string $password): bool
+    public function checkToken(string $token, string $password): bool
     {
-        $authConfig = $this->authConfig;
-        if (empty($password)){
-            $password = $authConfig['password'];
+        if (empty($password)) {
+            $password = $this->config['auth']['password'];
         }
-        $decode = static::handleToken($token, "DE",$authConfig['secret_key']);
+        $decode = $this->handleToken($token, "DE");
         $deData = json_decode($decode,true);
 
-        if (!empty($deData['key']) && $deData['key'] === static::getTokenCode($password) && !empty($deData['expire']) && $deData['expire']>time()){
+        if (!empty($deData['key']) && $deData['key'] === $this->getTokenCode($password) && !empty($deData['expire']) && $deData['expire']>time()){
             return true;
         }
 
+
+//        if ($decode === $this->getTokenCode($password)) {
+//            return true;
+//        }
         return false;
     }
 
+    /**
+     * @param $request
+     * @return bool
+     */
+    public function checkAuth(string $appKey): bool
+    {
+        $config  = $this->config;
+        $request = Request::instance();
+
+        $token = $request->param("token");
 
+        if (!empty($appKey)) {
+            $currentApps = (new Utils())->getCurrentApps($appKey);
+            $currentApp  = $currentApps[count($currentApps) - 1];
+            if (!empty($currentApp) && !empty($currentApp['password'])) {
+                if (empty($token)) {
+                    throw new AuthException("token not found");
+                }
+                // 应用密码
+                if ($this->checkToken($token, $currentApp['password'])) {
+                    return true;
+                } else {
+                    throw new AuthException("token error");
+                }
+            } else if (!(!empty($config['auth']) && $config['auth']['enable'])) {
+                return true;
+            }
+        }
+        if(!empty($config['auth']) && $config['auth']['enable'] && empty($token)){
+            throw new AuthException("token not found");
+        }else if (!empty($token) && !$this->checkToken($token, "")) {
+            throw new AuthException("token error");
+        }
+        return true;
+    }
 
     /**
      * 处理token
@@ -146,10 +141,10 @@ class Auth
      * @param int $expiry
      * @return false|string
      */
-    protected static function handleToken(string $string, string $operation = 'DE', string $key = '', int $expiry = 0):string
+    protected function handleToken(string $string, string $operation = 'DE', string $key = '', int $expiry = 0):string
     {
         $ckey_length   = 4;
-        $key           = md5($key);
+        $key           = md5($key ? $key : $this->config['auth']['secret_key']);
         $keya          = md5(substr($key, 0, 16));
         $keyb          = md5(substr($key, 16, 16));
         $keyc          = $ckey_length ? ($operation == 'DE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';

+ 287 - 0
vendor/hg/apidoc-thinkphp/src/Controller.php

@@ -0,0 +1,287 @@
+<?php
+declare(strict_types = 1);
+
+namespace hg\apidoc;
+
+use hg\apidoc\exception\AuthException;
+use hg\apidoc\exception\ErrorException;
+use hg\apidoc\parseApi\CacheApiData;
+use hg\apidoc\parseApi\ParseAnnotation;
+use hg\apidoc\parseApi\ParseMarkdown;
+use think\App;
+use think\facade\Config;
+use think\facade\Lang;
+use think\facade\Request;
+
+class Controller
+{
+    protected $app;
+
+    protected $config;
+
+    /**
+     * @var int tp版本
+     */
+    protected $tp_version;
+
+    public function __construct(App $app)
+    {
+        $this->app = $app;
+        $this->tp_version = substr(\think\facade\App::version(), 0, 2) == '5.'? 5: 6;
+        $config = Config::get("apidoc")?Config::get("apidoc"):Config::get("apidoc.");
+        if (!(!empty($config['apps']) && count($config['apps']))){
+            $default_app = Config::get("app.default_app")?Config::get("app.default_app"):Config::get("app.default_module");
+            $namespace = \think\facade\App::getNamespace();
+            // tp5获取 application
+            if ($this->tp_version === 5){
+                $appPath = \think\facade\App::getAppPath();
+                $appPathArr = explode("\\", $appPath);
+                for ($i = count($appPathArr)-1; $i>0 ;$i--){
+                    if ($appPathArr[$i]){
+                        $namespace = $appPathArr[$i];
+                        break;
+                    }
+                }
+            }
+            $path = $namespace.'\\'.$default_app.'\\controller';
+            if (!is_dir($path)){
+                $path =$namespace.'\\controller';
+            }
+            $defaultAppConfig = ['title'=>$default_app,'path'=>$path,'folder'=>$default_app];
+            $config['apps'] = [$defaultAppConfig];
+        }
+        // 过滤关闭的生成器
+        if (!empty($config['generator']) && count($config['generator'])){
+            $generatorList =[];
+            foreach ($config['generator'] as $item) {
+                if (!isset($item['enable']) || (isset($item['enable']) && $item['enable']===true)){
+                    $generatorList[]=$item;
+                }
+            }
+            $config['generator'] = $generatorList;
+        }
+
+
+        Config::set(['apidoc'=>$config]);
+        $this->config = $config;
+
+
+
+    }
+
+    /**
+     * 获取配置
+     * @return \think\response\Json
+     */
+    public function getConfig(){
+        $config = $this->config;
+        if (!empty($config['auth'])){
+            unset($config['auth']['password']);
+            unset($config['auth']['key']);
+        }
+        $request = Request::instance();
+        $params = $request->param();
+
+        if (!empty($params['lang'])){
+            if ($this->tp_version === 5){
+                Lang::setLangCookieVar($params['lang']);
+            }else{
+                \think\facade\App::loadLangPack($params['lang']);
+                Lang::setLangSet($params['lang']);
+            }
+
+        }
+        $config['title'] = Utils::getLang($config['title']);
+        $config['desc'] = Utils::getLang($config['desc']);
+        $config['headers'] = Utils::getArrayLang($config['headers'],"desc");
+        $config['parameters'] = Utils::getArrayLang($config['parameters'],"desc");
+        $config['responses'] = Utils::getArrayLang($config['responses'],"desc");
+
+
+        // 清除apps配置中的password
+        $config['apps'] = (new Utils())->handleAppsConfig($config['apps'],true);
+        return Utils::showJson(0,"",$config);
+    }
+
+    /**
+     * 验证密码
+     * @return false|\think\response\Json
+     * @throws \think\Exception
+     */
+    public function verifyAuth(){
+        $config = $this->config;
+
+        $request = Request::instance();
+        $params = $request->param();
+        $password = $params['password'];
+        if (empty($password)){
+            throw new AuthException( "password not found");
+        }
+        $appKey = !empty($params['appKey'])?$params['appKey']:"";
+
+        if (!$appKey && !(!empty($config['auth']) && $config['auth']['enable'])) {
+            return false;
+        }
+        try {
+            $hasAuth = (new Auth())->verifyAuth($password,$appKey);
+            $res = [
+                "token"=>$hasAuth
+            ];
+            return Utils::showJson(0,"",$res);
+        } catch (AuthException $e) {
+            return Utils::showJson($e->getCode(),$e->getMessage());
+        }
+
+    }
+
+    /**
+     * 获取文档数据
+     * @return \think\response\Json
+     */
+    public function getApidoc(){
+
+        $config = $this->config;
+        $request = Request::instance();
+        $params = $request->param();
+        $lang = "";
+
+        if (!empty($params['lang'])){
+            $lang = $params['lang'];
+            if ($this->tp_version === 5){
+                Lang::setLangCookieVar($lang);
+            }else{
+                \think\facade\App::loadLangPack($params['lang']);
+                Lang::setLangSet($params['lang']);
+            }
+
+        }
+
+        if (!empty($params['appKey'])){
+            // 获取指定应用
+            $appKey = $params['appKey'];
+        }else{
+            // 获取默认控制器
+            $default_app = $config = Config::get("app.default_app");
+            $appKey = $default_app;
+        }
+        $currentApps = (new Utils())->getCurrentApps($appKey);
+        $currentApp  = $currentApps[count($currentApps) - 1];
+
+        (new Auth())->checkAuth($appKey);
+
+        $cacheData=null;
+        if (!empty($config['cache']) && $config['cache']['enable']){
+            $cacheKey = $appKey."_".$lang;
+            $cacheData = (new CacheApiData())->get($cacheKey);
+            if ($cacheData && empty($params['reload'])){
+                $apiData = $cacheData;
+            }else{
+                // 生成数据并缓存
+                $apiData = (new ParseAnnotation())->renderApiData($appKey);
+                (new CacheApiData())->set($cacheKey,$apiData);
+            }
+        }else{
+            // 生成数据
+            $apiData = (new ParseAnnotation())->renderApiData($appKey);
+        }
+
+        // 接口分组
+        if (!empty($currentApp['groups'])){
+            $data = (new ParseAnnotation())->mergeApiGroup($apiData['data'],$currentApp['groups']);
+        }else{
+            $data = $apiData['data'];
+        }
+        $groups=!empty($currentApp['groups'])?$currentApp['groups']:[];
+        $json=[
+            'data'=>$data,
+            'app'=>$currentApp,
+            'groups'=>$groups,
+            'tags'=>$apiData['tags'],
+        ];
+
+        return Utils::showJson(0,"",$json);
+    }
+
+    public function getMdMenus(){
+        // 获取md
+        $request = Request::instance();
+        $params = $request->param();
+        $lang = "";
+        if (!empty($params['lang'])){
+            $lang = $params['lang'];
+            if ($this->tp_version === 5){
+                Lang::setLangCookieVar($params['lang']);
+            }else{
+                \think\facade\App::loadLangPack($params['lang']);
+                Lang::setLangSet($params['lang']);
+            }
+        }
+        if (!empty($params['appKey'])){
+            // 获取指定应用
+            $appKey = $params['appKey'];
+        }else{
+            // 获取默认控制器
+            $default_app = $config = Config::get("app.default_app");
+            $appKey = $default_app;
+        }
+        (new Auth())->checkAuth($appKey);
+
+        $docs = (new ParseMarkdown())->getDocsMenu($lang);
+        return Utils::showJson(0,"",$docs);
+
+    }
+
+    /**
+     * 获取md文档内容
+     * @return \think\response\Json
+     */
+    public function getMdDetail(){
+        $request = Request::instance();
+        $params = $request->param();
+        if (!empty($params['lang'])){
+            if ($this->tp_version === 5){
+                Lang::setLangCookieVar($params['lang']);
+            }else{
+                \think\facade\App::loadLangPack($params['lang']);
+                Lang::setLangSet($params['lang']);
+            }
+        }
+        try {
+            if (empty($params['path'])){
+                throw new ErrorException("mdPath not found");
+            }
+            if (empty($params['appKey'])){
+                throw new ErrorException("appkey not found");
+            }
+            $lang="";
+            if (!empty($params['lang'])){
+                $lang=$params['lang'];
+            }
+            (new Auth())->checkAuth($params['appKey']);
+            $content = (new ParseMarkdown())->getContent($params['appKey'],$params['path'],$lang);
+            $res = [
+                'content'=>$content,
+            ];
+            return Utils::showJson(0,"",$res);
+
+        } catch (ErrorException $e) {
+            return Utils::showJson($e->getCode(),$e->getMessage());
+        }
+    }
+
+
+    public function createGenerator(){
+        $request = Request::instance();
+        $params = $request->param();
+        $res = (new generator\Index())->create($params);
+        return Utils::showJson(0,"",$res);
+    }
+
+
+
+
+
+
+
+
+}

+ 36 - 0
vendor/hg/apidoc-thinkphp/src/Service.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace hg\apidoc;
+
+use think\facade\Config;
+use think\facade\Route;
+
+class Service extends \think\Service
+{
+
+    public function boot()
+    {
+
+        $this->registerRoutes(function (){
+            $apidocConfig = Config::get("apidoc")?Config::get("apidoc"):Config::get("apidoc.");
+            $route_prefix = 'apidoc';
+            $routes = function () {
+                $controller_namespace = '\hg\apidoc\Controller@';
+                Route::get('config'     , $controller_namespace . 'getConfig');
+                Route::get('apiData'     , $controller_namespace . 'getApidoc');
+                Route::get('mdMenus'     , $controller_namespace . 'getMdMenus');
+                Route::get('mdDetail'     , $controller_namespace . 'getMdDetail');
+                Route::post('verifyAuth'     , $controller_namespace . 'verifyAuth');
+                Route::post('generator'     , $controller_namespace . 'createGenerator');
+            };
+            if (!empty($apidocConfig['allowCrossDomain'])){
+                Route::group($route_prefix, $routes)->allowCrossDomain();
+            }else{
+                Route::group($route_prefix, $routes);
+            }
+        });
+
+    }
+
+
+}

+ 185 - 177
vendor/hg/apidoc/src/utils/Helper.php → vendor/hg/apidoc-thinkphp/src/Utils.php

@@ -1,11 +1,14 @@
 <?php
 declare(strict_types = 1);
 
-namespace hg\apidoc\utils;
+namespace hg\apidoc;
 
 use hg\apidoc\exception\ErrorException;
+use think\facade\Config;
+use think\facade\Lang;
+use think\response\Json;
 
-class Helper
+class Utils
 {
     protected static $snakeCache = [];
     /**
@@ -13,22 +16,93 @@ class Helper
      * @param int $code
      * @param string $msg
      * @param string $data
+     * @return \think\response\Json
      */
-    public static function showJson(int $code = 0, string $msg = "", $data = "")
+    public static function showJson(int $code = 0, string $msg = "", $data = ""):Json
     {
         $res = [
             'code' => $code,
-            'message'  => $msg,
+            'msg'  => $msg,
             'data' => $data,
         ];
-        $handle_response_json = ConfigProvider::get("handle_response_json");
-        if (!empty($handle_response_json) && is_callable($handle_response_json)){
-            return $handle_response_json($res);
+        return json($res);
+    }
+
+    /**
+     * 过滤参数字段
+     * @param $data
+     * @param $fields
+     * @param string $type
+     * @return array
+     */
+    public function filterParamsField(array $data, $fields, string $type = "field"): array
+    {
+        if ($fields && strpos($fields, ',') !== false){
+            $fieldArr = explode(',', $fields);
+        }else{
+            $fieldArr = [$fields];
         }
-        return $res;
+
+        $dataList = [];
+        foreach ($data as $item) {
+            if (!empty($item['name']) && in_array($item['name'], $fieldArr) && $type === 'field') {
+                $dataList[] = $item;
+            } else if (!(!empty($item['name']) && in_array($item['name'], $fieldArr)) && $type == "withoutField") {
+                $dataList[] = $item;
+            }
+        }
+        return $dataList;
     }
 
+    /**
+     * 读取文件内容
+     * @param $fileName
+     * @return false|string
+     */
+    public static function getFileContent(string $fileName): string
+    {
+        $content = "";
+        if (file_exists($fileName)) {
+            $handle  = fopen($fileName, "r");
+            $content = fread($handle, filesize($fileName));
+            fclose($handle);
+        }
+        return $content;
+    }
 
+    /**
+     * 保存文件
+     * @param $path
+     * @param $str_tmp
+     * @return bool
+     */
+    public static function createFile(string $path, string $str_tmp): bool
+    {
+        $pathArr = explode("/", $path);
+        unset($pathArr[count($pathArr) - 1]);
+        $dir = implode("/", $pathArr);
+        if (!file_exists($dir)) {
+            mkdir($dir, 0777, true);
+        }
+        $fp = fopen($path, "w") or die("Unable to open file!");
+        fwrite($fp, $str_tmp); //存入内容
+        fclose($fp);
+        return true;
+    }
+
+    /**
+     * 删除文件
+     * @param $path
+     */
+    public static function delFile(string $path)
+    {
+        $url = iconv('utf-8', 'gbk', $path);
+        if (PATH_SEPARATOR == ':') { //linux
+            unlink($path);
+        } else {  //Windows
+            unlink($url);
+        }
+    }
 
     /**
      * 将tree树形数据转成list数据
@@ -36,13 +110,13 @@ class Helper
      * @param string $childName 子节点名称
      * @return array  转换后的list数据
      */
-    public static function treeToList(array $tree, string $childName = 'children',string $key = "id",string $parentField = "parent")
+    public function treeToList(array $tree, string $childName = 'children',string $key = "id",string $parentField = "parent")
     {
         $array = array();
         foreach ($tree as $val) {
             $array[] = $val;
             if (isset($val[$childName])) {
-                $children = static::treeToList($val[$childName], $childName);
+                $children = $this->treeToList($val[$childName], $childName);
                 if ($children) {
                     $newChildren = [];
                     foreach ($children as $item) {
@@ -63,9 +137,9 @@ class Helper
      * @param $tree
      * @param $keys
      */
-    public static function getTreeNodesByKeys(array $tree, array $keys, string $field = "id", string $childrenField = "children")
+    public function getTreeNodesByKeys(array $tree, array $keys, string $field = "id", string $childrenField = "children")
     {
-        $list = static::TreeToList($tree, $childrenField, "key");
+        $list = $this->TreeToList($tree, $childrenField, "folder");
         $data = [];
         foreach ($keys as $k => $v) {
             $parent = !$k ? "" : $keys[$k - 1];
@@ -104,7 +178,7 @@ class Helper
      * @param $currentApps
      * @return string|string[]
      */
-    public static function replaceCurrentAppTemplate(string $temp,array $currentApps):string
+    public function replaceCurrentAppTemplate(string $temp,array $currentApps):string
     {
         $str = $temp;
         if (!empty($currentApps) && count($currentApps) > 0) {
@@ -124,7 +198,7 @@ class Helper
                     }
                 }
             }
-            $str = static::replaceTemplate($str, $data);
+            $str = $this->replaceTemplate($str, $data);
         }
         return $str;
     }
@@ -204,91 +278,68 @@ class Helper
      * @param mixed ...$array
      * @return array
      */
-//    public static function arrayMergeAndUnique(string $key = "name", ...$array):array
-//    {
-//        $newArray = [];
-//        foreach ($array as $k => $arr) {
-//            if ($k===0){
-//                $newArray = array_merge($newArray, $arr);
-//            }else if(is_array($arr)){
-//                foreach ($arr as $item){
-//                    $findIndex = Helper::getArrayFindIndex($newArray,function ($row)use ($key,$item){
-//                        if ($item[$key] === $row[$key]){
-//                            return true;
-//                        }
-//                        return false;
-//                    });
-//                    if($findIndex>-1){
-//                        $data = [];
-//                        foreach ($item as $itemK=>$itemV){
-//                            if ( $itemV !== null){
-//                                $data[$itemK]=$itemV;
-//                            }
-//                        }
-//                        $newArray[$findIndex] = array_merge($newArray[$findIndex],$data);
-//                    }else{
-//                        $newArray[]=$item;
-//                    }
-//                }
-//            }
-//        }
-//
-//
-//        return $newArray;
-//
-//    }
-
     public static function arrayMergeAndUnique(string $key = "name", ...$array):array
     {
-        $arrayByKey = [];
+        $newArray = [];
         foreach ($array as $k => $arr) {
-            if (!empty($arr) && count($arr)){
-                foreach ($arr as $item) {
-                    if (!empty($item[$key])){
-                        $arrayByKey[$item[$key]] = $item;
+            if ($k===0){
+                $newArray = array_merge($newArray, $arr);
+            }else if(is_array($arr)){
+                foreach ($arr as $item){
+                    $findIndex = Utils::getArrayFindIndex($newArray,function ($row)use ($key,$item){
+                        if ($item[$key] === $row[$key]){
+                            return true;
+                        }
+                        return false;
+                    });
+                    if($findIndex>-1){
+                        $data = [];
+                        foreach ($item as $itemK=>$itemV){
+                            if ( $itemV !== null){
+                                $data[$itemK]=$itemV;
+                            }
+                        }
+                        $newArray[$findIndex] = array_merge($newArray[$findIndex],$data);
+                    }else{
+                        $newArray[]=$item;
                     }
                 }
             }
         }
-        $newArray = [];
-        foreach ($arrayByKey as $item) {
-            $newArray[]=$item;
-        }
+
+
         return $newArray;
+
     }
 
     /**
      * 初始化当前所选的应用/版本数据
      * @param $appKey
      */
-    public static function getCurrentAppConfig(string $appKey):array
+    public function getCurrentApps(string $appKey,$configData=""):array
     {
-
-        $config = ConfigProvider::get();
-        $config['apps'] = static::handleAppsConfig($config['apps']);
+        if (!empty($configData)){
+            $config =$configData;
+        }else{
+            $config = Config::get("apidoc")?Config::get("apidoc"):Config::get("apidoc.");
+            $config['apps'] = $this->handleAppsConfig($config['apps']);
+        }
         if (!(!empty($config['apps']) && count($config['apps']) > 0)) {
-            throw new ErrorException("no config apps");
+            throw new ErrorException("no config apps", 500);
         }
         if (strpos($appKey, ',') !== false) {
             $keyArr = explode(",", $appKey);
         } else {
             $keyArr = [$appKey];
         }
-        $currentApps = static::getTreeNodesByKeys($config['apps'], $keyArr, 'key', 'items');
+        $currentApps = $this->getTreeNodesByKeys($config['apps'], $keyArr, 'folder', 'items');
         if (!$currentApps) {
-            throw new ErrorException("appKey error",  [
+            throw new ErrorException("appKey error", 412, [
                 'appKey' => $appKey
             ]);
         }
-        return [
-            'appConfig'=>$currentApps[count($currentApps) - 1],
-            'apps'=>$currentApps
-        ];
-
-    }
+        return $currentApps;
 
-    public static function getCacheKey($type,$appKey,$lang="",$key="",$folder="apis"){
-        return $folder."/".$type."_".$appKey."_".$lang."_".$key;
     }
 
     /**
@@ -296,7 +347,7 @@ class Helper
      * @param array $apps
      * @return array
      */
-    public static function handleAppsConfig(array $apps,$isHandlePassword=false):array
+    public function handleAppsConfig(array $apps,$isHandlePassword=false):array
     {
         $appsConfig = [];
         foreach ($apps as $app) {
@@ -305,61 +356,41 @@ class Helper
                 $app['hasPassword'] = true;
             }
             if (!empty($app['title'])){
-                $app['title'] = Lang::getLang($app['title']);
+                $app['title'] = Utils::getLang($app['title']);
             }
             if (!empty($app['items']) && count($app['items']) > 0) {
-                $app['items'] = static::handleAppsConfig($app['items'],$isHandlePassword);
+                $app['items'] = $this->handleAppsConfig($app['items'],$isHandlePassword);
             }
             if (!empty($app['groups']) && count($app['groups']) > 0){
-                $app['groups'] = static::handleGroupsConfig($app['groups']);
+                $app['groups'] = $this->handleGroupsConfig($app['groups']);
             }
-            if (!empty($app['params'])){
-                if (!empty($app['params']['header']) && count($app['params']['header']) > 0){
-                    $app['params']['header'] = Lang::getArrayLang($app['params']['header'],"desc");
-                }
-                if (!empty($app['params']['query']) && count($app['params']['query']) > 0){
-                    $app['params']['query'] = Lang::getArrayLang($app['params']['query'],"desc");
-                }
-                if (!empty($app['params']['body']) && count($app['params']['body']) > 0){
-                    $app['params']['body'] = Lang::getArrayLang($app['params']['body'],"desc");
-                }
+            if (!empty($app['headers']) && count($app['headers']) > 0){
+                $app['headers'] = Utils::getArrayLang($app['headers'],"desc");
+            }
+            if (!empty($app['parameters']) && count($app['parameters']) > 0){
+                $app['parameters'] = Utils::getArrayLang($app['parameters'],"desc");
             }
             $appsConfig[] = $app;
         }
         return $appsConfig;
     }
 
-    public static function getAllApps(array $apps,$parentKey=""){
-        $appList = [];
-        $separ = !empty($parentKey)?',':'';
-        foreach ($apps as $app) {
-            $appKey = $parentKey.$separ.$app['key'];
-            if (!empty($app['items']) && count($app['items'])){
-               $items = static::getAllApps($app['items'],$appKey);
-               $appList = array_merge($appList,$items);
-            }else{
-                $app['appKey'] = $appKey;
-                $appList[]=$app;
-            }
-        }
-        return $appList;
-    }
-
     /**
      * 处理groups配置参数
      * @param array $groups
      * @return array
      */
-    public static function handleGroupsConfig(array $groups):array
+    public function handleGroupsConfig(array $groups):array
     {
         $groupConfig = [];
         foreach ($groups as $group) {
             if (!empty($group['title'])){
-                $group['title'] = Lang::getLang($group['title']);
+                $group['title'] = Utils::getLang($group['title']);
             }
             if (!empty($group['children']) && count($group['children']) > 0) {
-                $group['children'] = static::handleAppsConfig($group['children']);
+                $group['children'] = $this->handleAppsConfig($group['children']);
             }
+
             $groupConfig[] = $group;
         }
         return $groupConfig;
@@ -390,30 +421,6 @@ class Helper
     }
 
     /**
-     * 下划线转驼峰(首字母小写)
-     *
-     * @param  string $value
-     * @return string
-     */
-    public static function camel(string $value): string
-    {
-        return  lcfirst(static::studly($value));
-    }
-
-
-    /**
-     * 下划线转驼峰(首字母大写)
-     *
-     * @param  string $value
-     * @return string
-     */
-    public static function studly(string $value): string
-    {
-        $value = ucwords(str_replace(['-', '_'], ' ', $value));
-        return  str_replace(' ', '', $value);
-    }
-
-    /**
      * 字符串转小写
      *
      * @param  string $value
@@ -434,21 +441,39 @@ class Helper
     }
 
     /**
-     * 创建api的key
-     * @param string $path
-     * @param string $name
-     * @return string
+     * 获取多语言变量值
+     * @param $string
+     * @return mixed
      */
-    public static function createApiKey(string $path,string $name=""): string{
-        if ($name){
-            $key = $path."@".$name;
-        }else{
-            $key = $path;
+    public static function getLang($string) {
+        if (!$string){
+            return $string;
         }
-        $res = urlencode($key);
-        return $res;
+        if (strpos($string, 'lang(') !== false) {
+            if (preg_match('#lang\((.*)\)#s', $string, $key) !== false){
+                $langKey = $key && count($key)>1 ? trim($key[1]):"";
+                return Lang::get($langKey);
+            }
+        }
+        return $string;
     }
 
+    /**
+     * 二维数组设置指定字段的多语言
+     * @param $array
+     * @param $field
+     * @return array
+     */
+    public static function getArrayLang($array,$field){
+        $data = [];
+        if (!empty($array) && is_array($array)){
+            foreach ($array as $item){
+                $item[$field] = Utils::getLang($item[$field]);
+                $data[]=$item;
+            }
+        }
+        return $data;
+    }
 
     /**
      * 二维数组根据key排序
@@ -468,6 +493,26 @@ class Helper
 
 
     /**
+     * 格式化路径
+     * @param $path
+     * @param string $type
+     * @return array|string|string[]
+     */
+    public static function formatPath($path,$type="/"){
+        if ($type==="/"){
+            $path = str_replace("\\","/",$path);
+        }else{
+            $path = str_replace("/","\\",$path);
+            $path = str_replace("\\\\","\\",$path);
+            $endStr = substr($path, -1);
+            if ($endStr=='\\'){
+                $path = substr($path,0,strlen($path)-1);
+            }
+        }
+       return $path;
+    }
+
+    /**
      * 过滤所有空格换行符
      * @param $str
      * @return array|string|string[]
@@ -479,43 +524,6 @@ class Helper
     }
 
 
-    public static function getObjectFindByField(array $data,string $name = null)
-    {
-        // 无参数时获取所有
-        if (empty($name)) {
-            return $data;
-        }
-        if (false === strpos($name, '.')) {
-            $name = strtolower($name);
-            return $data[$name] ?? [];
-        }
-        $name    = explode('.', $name);
-        $name[0] = strtolower($name[0]);
-        $result  = $data;
-        // 按.拆分成多维数组进行判断
-        foreach ($name as $val) {
-            if (isset($result[$val])) {
-                $result = $result[$val];
-            } else {
-                return [];
-            }
-        }
-        return $result;
-    }
-
-
-    public static function inArrayBuyKeyword(array $arr,string $keyword):bool{
-        $is = false;
-        foreach ($arr as $item) {
-            if (strpos($item, $keyword) !== false){
-                $is=true;
-                break;
-            }
-        }
-        return $is;
-    }
-
-
 
 
 

+ 0 - 12
vendor/hg/apidoc/src/annotation/AddField.php → vendor/hg/apidoc-thinkphp/src/annotation/AddField.php

@@ -41,16 +41,4 @@ class AddField extends Annotation
      * @var bool
      */
     public $require = false;
-
-    /**
-     * 说明md内容
-     * @var string
-     */
-    public $md;
-
-    /**
-     * 引入说明md内容
-     * @var string
-     */
-    public $mdRef;
 }

+ 1 - 1
vendor/hg/apidoc/src/annotation/After.php → vendor/hg/apidoc-thinkphp/src/annotation/After.php

@@ -18,7 +18,7 @@ final class After extends EventBase
 
     /**
      * 事件
-     * @Enum({"setGlobalHeader", "setGlobalQuery", "setGlobalBody","clearGlobalHeader","clearGlobalQuery","clearGlobalBody","ajax"})
+     * @Enum({"setGlobalHeader", "setGlobalParam", "clearGlobalHeader", "clearGlobalParam","ajax"})
      * @var string
      */
     public $event;

+ 0 - 0
vendor/hg/apidoc/src/annotation/Author.php → vendor/hg/apidoc-thinkphp/src/annotation/Author.php


+ 1 - 1
vendor/hg/apidoc/src/annotation/Before.php → vendor/hg/apidoc-thinkphp/src/annotation/Before.php

@@ -15,7 +15,7 @@ final class Before extends EventBase
 {
     /**
      * 事件
-     * @Enum({"setHeader","setQuery","setBody", "clearHeader", "clearQuery", "clearBody", "setGlobalHeader", "setGlobalQuery", "setGlobalBody","clearGlobalHeader","clearGlobalQuery","clearGlobalBody","ajax"})
+     * @Enum({"setHeader", "setGlobalHeader", "setParam", "setGlobalParam", "clearGlobalHeader", "clearGlobalParam", "clearParam","handleParam",""})
      * @var string
      */
     public $event;

+ 0 - 0
vendor/hg/apidoc/src/annotation/ContentType.php → vendor/hg/apidoc-thinkphp/src/annotation/ContentType.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/Desc.php → vendor/hg/apidoc-thinkphp/src/annotation/Desc.php


+ 2 - 12
vendor/hg/apidoc/src/annotation/EventBase.php → vendor/hg/apidoc-thinkphp/src/annotation/EventBase.php

@@ -8,22 +8,12 @@ abstract class EventBase extends Annotation
 {
 
     /**
-     * 名称
-     * @var string
-     */
-    public $name;
-
-    /**
      * key
      * @var string
      */
     public $key;
 
-    /**
-     * 处理值的方法
-     * @var string
-     */
-    public $handleValue;
+
 
     /**
      * ajax时的url
@@ -45,7 +35,7 @@ abstract class EventBase extends Annotation
     public $contentType;
 
     /**
-     * 字段描述
+     * 描述
      * @var string
      */
     public $desc;

+ 0 - 0
vendor/hg/apidoc/src/annotation/Field.php → vendor/hg/apidoc-thinkphp/src/annotation/Field.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/Group.php → vendor/hg/apidoc-thinkphp/src/annotation/Group.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/Header.php → vendor/hg/apidoc-thinkphp/src/annotation/Header.php


+ 1 - 1
vendor/hg/apidoc/src/annotation/Md.php → vendor/hg/apidoc-thinkphp/src/annotation/Md.php

@@ -5,7 +5,7 @@ namespace hg\apidoc\annotation;
 use Doctrine\Common\Annotations\Annotation;
 
 /**
- * Markdown
+ * Url
  * @package hg\apidoc\annotation
  * @Annotation
  * @Target({"METHOD"})

+ 1 - 1
vendor/hg/apidoc/src/annotation/Method.php → vendor/hg/apidoc-thinkphp/src/annotation/Method.php

@@ -5,7 +5,7 @@ namespace hg\apidoc\annotation;
 use Doctrine\Common\Annotations\Annotation;
 
 /**
- * 请求类型
+ * Url
  * @package hg\apidoc\annotation
  * @Annotation
  * @Target({"METHOD"})

+ 0 - 0
vendor/hg/apidoc/src/annotation/Param.php → vendor/hg/apidoc-thinkphp/src/annotation/Param.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/ParamBase.php → vendor/hg/apidoc-thinkphp/src/annotation/ParamBase.php


+ 2 - 4
vendor/hg/apidoc/src/annotation/ResponseError.php → vendor/hg/apidoc-thinkphp/src/annotation/ParamMd.php

@@ -5,19 +5,17 @@ namespace hg\apidoc\annotation;
 use Doctrine\Common\Annotations\Annotation;
 
 /**
- * 异常响应体
+ * md请求参数
  * @package hg\apidoc\annotation
  * @Annotation
  * @Target({"METHOD","ANNOTATION"})
  */
-final class ResponseError extends ParamBase
+final class ParamMd extends Annotation
 {
-
     /**
      * 引入
      * @var string
      */
     public $ref;
 
-
 }

+ 0 - 0
vendor/hg/apidoc/src/annotation/ParamType.php → vendor/hg/apidoc-thinkphp/src/annotation/ParamType.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/Returned.php → vendor/hg/apidoc-thinkphp/src/annotation/Returned.php


+ 5 - 4
vendor/hg/apidoc/src/annotation/ResponseSuccessMd.php → vendor/hg/apidoc-thinkphp/src/annotation/ReturnedMd.php

@@ -5,16 +5,17 @@ namespace hg\apidoc\annotation;
 use Doctrine\Common\Annotations\Annotation;
 
 /**
- * 成功响应体Markdown内容
+ * md返回参数
  * @package hg\apidoc\annotation
  * @Annotation
- * @Target({"METHOD"})
+ * @Target({"METHOD","ANNOTATION"})
  */
-class ResponseSuccessMd extends Annotation
+final class ReturnedMd extends Annotation
 {
     /**
-     * 引入md内容
+     * 引入
      * @var string
      */
     public $ref;
+
 }

+ 17 - 0
vendor/hg/apidoc-thinkphp/src/annotation/Route.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace hg\apidoc\annotation;
+
+use Doctrine\Common\Annotations\Annotation\Enum;
+
+
+final class Route extends Rule
+{
+    /**
+     * 请求类型
+     * @Enum({"GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD"})
+     * @var string
+     */
+    public $method = "GET";
+
+}

+ 0 - 0
vendor/hg/apidoc/src/annotation/Rule.php → vendor/hg/apidoc-thinkphp/src/annotation/Rule.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/Sort.php → vendor/hg/apidoc-thinkphp/src/annotation/Sort.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/Tag.php → vendor/hg/apidoc-thinkphp/src/annotation/Tag.php


+ 0 - 0
vendor/hg/apidoc/src/annotation/Title.php → vendor/hg/apidoc-thinkphp/src/annotation/Title.php


+ 1 - 1
vendor/hg/apidoc/src/annotation/Url.php → vendor/hg/apidoc-thinkphp/src/annotation/Url.php

@@ -5,7 +5,7 @@ namespace hg\apidoc\annotation;
 use Doctrine\Common\Annotations\Annotation;
 
 /**
- * 接口Url
+ * Url
  * @package hg\apidoc\annotation
  * @Annotation
  * @Target({"METHOD"})

+ 0 - 0
vendor/hg/apidoc/src/annotation/WithoutField.php → vendor/hg/apidoc-thinkphp/src/annotation/WithoutField.php


+ 51 - 0
vendor/hg/apidoc-thinkphp/src/config.php

@@ -0,0 +1,51 @@
+<?php
+return [
+    // 文档标题
+    'title'              => 'API接口文档',
+    // 文档描述
+    'desc'               => '',
+    // 默认请求类型
+    'default_method'=>'GET',
+    // 允许跨域访问
+    'allowCrossDomain'=>false,
+    // 设置可选版本
+    'apps'           => [],
+    // 自动生成url规则
+    'auto_url' => [
+        // 字母规则
+        'letter_rule' => "lcfirst",
+        // 多级路由分隔符
+        'multistage_route_separator'  =>"."
+    ],
+    // 指定公共注释定义的文件地址
+    'definitions'        => "app\common\controller\Definitions",
+    // 缓存配置
+    'cache'              => [
+        // 是否开启缓存
+        'enable' => false,
+    ],
+    // 权限认证配置
+    'auth'               => [
+        // 是否启用密码验证
+        'enable'     => false,
+        // 全局访问密码
+        'password'   => "123456",
+        // 密码加密盐
+        'secret_key' => "apidoc#hg_code",
+        // 有效期
+        'expire' => 24*60*60
+    ],
+    // 统一的请求Header
+    'headers'=>[],
+    // 统一的请求参数Parameters
+    'parameters'=>[],
+    // 统一的请求响应体
+    'responses'=>[
+        ['name'=>'code','desc'=>'代码','type'=>'int'],
+        ['name'=>'message','desc'=>'业务信息','type'=>'string'],
+        ['name'=>'data','desc'=>'业务数据','main'=>true,'type'=>'object'],
+    ],
+    // md文档
+    'docs'              => [],
+
+];

+ 33 - 0
vendor/hg/apidoc-thinkphp/src/exception/AuthException.php

@@ -0,0 +1,33 @@
+<?php
+
+
+namespace hg\apidoc\exception;
+
+
+use think\Exception;
+use think\exception\HttpException;
+
+class AuthException extends HttpException
+{
+
+    protected $exceptions = [
+        'password error'     => ['code' => 4001, 'msg' => '密码不正确,请重新输入'],
+        'password not found' => ['code' => 4002, 'msg' => '密码不可为空'],
+        'token error'        => ['code' => 4003, 'msg' => '不合法的Token'],
+        'token not found'    => ['code' => 4004, 'msg' => '不存在Token'],
+    ];
+
+    public function __construct(string $exceptionCode)
+    {
+        $exception = $this->getException($exceptionCode);
+        parent::__construct(401, $exception['msg'], null, [], $exception['code']);
+    }
+
+    public function getException($exceptionCode)
+    {
+        if (isset($this->exceptions[$exceptionCode])) {
+            return $this->exceptions[$exceptionCode];
+        }
+        throw new Exception('exceptionCode "' . $exceptionCode . '" Not Found');
+    }
+}

+ 47 - 0
vendor/hg/apidoc-thinkphp/src/exception/ErrorException.php

@@ -0,0 +1,47 @@
+<?php
+
+
+namespace hg\apidoc\exception;
+
+
+use hg\apidoc\Utils;
+use think\Exception;
+use think\exception\HttpException;
+
+class ErrorException extends HttpException
+{
+
+    protected $exceptions = [
+        'appkey not found'     => ['code' => 4005, 'msg' => '缺少必要参数appKey'],
+        'mdPath not found'     => ['code' => 4006, 'msg' => '缺少必要参数path'],
+        'appKey error'         => ['code' => 4007, 'msg' => '不存在 folder为${appKey}的apps配置'],
+        'template not found'   => ['code' => 4008, 'msg' => '${template}模板不存在'],
+        'path not found'       => ['code' => 4009, 'msg' => '${path}目录不存在'],
+        'classname error'      => ['code' => 4010, 'msg' => '${classname}文件名不合法'],
+        'no config apps'       => ['code' => 5000, 'msg' => 'apps配置不可为空'],
+        'no debug'             => ['code' => 5001, 'msg' => '请在debug模式下,使用该功能'],
+        'no config crud'       => ['code' => 5002, 'msg' => 'crud未配置'],
+        'datatable create error' => ['code' => 5003, 'msg' => '${table}数据表创建失败,请检查配置。【error】${message}。【sql】:${sql}'],
+        'file already exists' => ['code' => 5004, 'msg' => '${filepath}文件已存在'],
+        'file not exists' => ['code' => 5005, 'msg' => '${filepath}文件不存在'],
+        'datatable already exists' => ['code' => 5006, 'msg' => '数据表${table}已存在'],
+        'datatable not exists' => ['code' => 5007, 'msg' => '数据表${table}不存在'],
+        'ref file not exists' => ['code' => 5008, 'msg' => 'ref引入文件${filepath}不存在'],
+    ];
+
+    public function __construct(string $exceptionCode, int $statusCode = 412, array $data = [])
+    {
+        $exception = $this->getException($exceptionCode);
+        $msg       = Utils::replaceTemplate($exception['msg'], $data);
+        parent::__construct($statusCode, $msg, null, [], $exception['code']);
+    }
+
+    public function getException($exceptionCode)
+    {
+        if (isset($this->exceptions[$exceptionCode])) {
+            return $this->exceptions[$exceptionCode];
+        }
+        throw new Exception('exceptionCode "' . $exceptionCode . '" Not Found');
+    }
+
+}

+ 88 - 80
vendor/hg/apidoc/src/generator/Index.php → vendor/hg/apidoc-thinkphp/src/generator/Index.php

@@ -3,8 +3,12 @@
 namespace hg\apidoc\generator;
 use hg\apidoc\exception\ErrorException;
 use hg\apidoc\generator\ParseTemplate;
-use hg\apidoc\utils\DirAndFile;
-use hg\apidoc\utils\Helper;
+use hg\apidoc\Utils;
+use think\facade\App;
+use think\facade\Config;
+use think\facade\Db;
+use think\Db as Db5;
+use think\helper\Str;
 
 class Index
 {
@@ -12,40 +16,14 @@ class Index
 
     protected $middlewares = [];
 
-    protected $databaseConfig = [
-        // 数据库表前缀
-        'prefix'          => '',
-        // 数据库编码,默认为utf8
-        'charset'         =>  'utf8',
-        // 数据库引擎,默认为 InnoDB
-        'engine'          => 'InnoDB',
-    ];
-
-    protected  $systemDefaultValues = [
-        'CURRENT_TIMESTAMP'
-    ];
-
-    public function __construct($config)
+    public function __construct()
     {
-        $this->config = $config;
-        if (!empty($config['database'])){
-            if (!empty($config['database']['prefix'])){
-                $this->databaseConfig['prefix'] = $config['database']['prefix'];
-            }
-            if (!empty($config['database']['charset'])){
-                $this->databaseConfig['charset'] = $config['database']['charset'];
-            }
-            if (!empty($config['database']['engine'])){
-                $this->databaseConfig['engine'] = $config['database']['engine'];
-            }
-        }
+        $this->config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
     }
 
     public function create($params){
         $appKey = $params['form']['appKey'];
-        $currentAppConfig = Helper::getCurrentAppConfig($appKey);
-        $currentApps = $currentAppConfig['apps'];
-        $currentApp  = $currentAppConfig['appConfig'];
+        $currentApps = (new Utils())->getCurrentApps($appKey);
         $generatorItem = $this->config['generator'][$params['index']];
 
         $checkParams = $this->checkFilesAndHandleParams($generatorItem,$params,$currentApps);
@@ -65,8 +43,11 @@ class Index
         }
 
         $this->createModels($checkParams['createModels'],$tplParams);
+
         $this->createFiles($checkParams['createFiles'],$tplParams);
-         //执行after
+
+
+        // 执行after
         if (count($this->middlewares)){
             foreach ($this->middlewares as $middleware) {
                 if (method_exists($instance, 'after')) {
@@ -95,16 +76,16 @@ class Index
         if (!empty($params['files']) && count($params['files'])>0) {
             $files = $params['files'];
             foreach ($files as $file) {
-                $fileConfig = Helper::getArrayFind($generatorItem['files'], function ($item) use ($file) {
+                $fileConfig = Utils::getArrayFind($generatorItem['files'], function ($item) use ($file) {
                     if ($file['name'] === $item['name']) {
                         return true;
                     }
                     return false;
                 });
 
-                $filePath = Helper::replaceCurrentAppTemplate($fileConfig['path'], $currentApps);
+                $filePath = (new Utils())->replaceCurrentAppTemplate($fileConfig['path'], $currentApps);
                 if (!empty($fileConfig['namespace'])) {
-                    $fileNamespace = Helper::replaceCurrentAppTemplate($fileConfig['namespace'], $currentApps);
+                    $fileNamespace = (new Utils())->replaceCurrentAppTemplate($fileConfig['namespace'], $currentApps);
                 } else {
                     $fileNamespace = $filePath;
                 }
@@ -112,7 +93,7 @@ class Index
                 if ($fileNamespaceEndStr == '\\') {
                     $fileNamespace = substr($fileNamespace, 0, strlen($fileNamespace) - 1);
                 }
-                $template = Helper::replaceCurrentAppTemplate($fileConfig['template'], $currentApps);
+                $template = (new Utils())->replaceCurrentAppTemplate($fileConfig['template'], $currentApps);
                 $tplParams[$file['name']] = [
                     'class_name' => $file['value'],
                     'path' => $filePath,
@@ -121,19 +102,19 @@ class Index
                 ];
 
                 // 验证模板是否存在
-                $templatePath =DirAndFile::formatPath( APIDOC_ROOT_PATH . $template,"/");
+                $templatePath =Utils::formatPath( App::getRootPath() . $template,"/");
                 if (is_readable($templatePath) == false) {
-                    throw new ErrorException("template not found",  [
+                    throw new ErrorException("template not found", 412, [
                         'template' => $template
                     ]);
                 }
                 // 验证是否已存在生成的文件
-                $fileFullPath = DirAndFile::formatPath(APIDOC_ROOT_PATH . $filePath, "/");
+                $fileFullPath = Utils::formatPath(App::getRootPath() . $filePath, "/");
                 $type = "folder";
                 if (strpos($fileFullPath, '.php') !== false) {
                     // 路径为php文件,则验证文件是否存在
                     if (is_readable($fileFullPath) == false) {
-                        throw new ErrorException("file not exists",  [
+                        throw new ErrorException("file not exists", 412, [
                             'filepath' => $filePath
                         ]);
                     }
@@ -142,8 +123,8 @@ class Index
                     $fileName = !empty($file['value']) ? $file['value'] : "";
                     $fileFullPath = $fileFullPath . "/" . $fileName . ".php";
                     if (is_readable($fileFullPath)) {
-                        throw new ErrorException("file already exists",[
-                            'filepath' => DirAndFile::formatPath($filePath) . $fileName . ".php"
+                        throw new ErrorException("file already exists", 412, [
+                            'filepath' => Utils::formatPath($filePath) . $fileName . ".php"
                         ]);
                     }
                 }
@@ -153,6 +134,8 @@ class Index
                     'templatePath'=>$templatePath,
                     'type' => $type
                 ];
+
+
             }
         }
 
@@ -171,13 +154,10 @@ class Index
      * @return array
      */
     protected function checkModels($generatorItem,$tplParams){
-        if (empty($this->config['database_query_function'])){
-            throw new ErrorException("not datatable_query_function config");
-        }
-
         $res="";
         $tabls = $tplParams['tables'];
         $createModels = [];
+        $tp_version = \think\facade\App::version();
         if (!empty($tabls) && count($tabls)){
             foreach ($tabls as $k=>$table) {
                 $tableConfig = $generatorItem['table'];
@@ -188,28 +168,36 @@ class Index
                     $path = $tableConfig['items'][$k]['path'];
 
                     // 验证模板是否存在
-                    $templatePath = DirAndFile::formatPath(APIDOC_ROOT_PATH . $template,"/");
+                    $templatePath = Utils::formatPath(App::getRootPath() . $template,"/");
                     if (is_readable($templatePath) == false) {
-                        throw new ErrorException("template not found", [
+                        throw new ErrorException("template not found", 412, [
                             'template' => $template
                         ]);
                     }
                     $tplParams['tables'][$k]['class_name'] =$table['model_name'];
                     // 验证模型是否已存在
                     $fileName = $table['model_name'];
-                    $fileFullPath = DirAndFile::formatPath(APIDOC_ROOT_PATH.$path). "/" . $fileName . ".php";
+                    $fileFullPath = Utils::formatPath(App::getRootPath().$path) . "/" . $fileName . ".php";
                     if (is_readable($fileFullPath)) {
-                        throw new ErrorException("file already exists", [
-                            'filepath' => DirAndFile::formatPath($path) . "/" . $fileName . ".php"
+                        throw new ErrorException("file already exists", 412, [
+                            'filepath' => Utils::formatPath($path) . "/" . $fileName . ".php"
                         ]);
                     }
                 }
                 // 验证表是否存在
                 if ($table['table_name']){
-                    $table_name = $this->databaseConfig['prefix'].$table['table_name'];
-                    $isTable = $this->config['database_query_function']('SHOW TABLES LIKE '."'".$table_name."'");
+                    $driver = Config::get('database.default');
+
+                    $table_prefix=Config::get('database.connections.'.$driver.'.prefix');
+                    $table_name = $table_prefix.$table['table_name'];
+
+                    if (substr($tp_version, 0, 2) == '5.'){
+                        $isTable = Db5::query('SHOW TABLES LIKE '."'".$table_name."'");
+                    }else{
+                        $isTable = Db::query('SHOW TABLES LIKE '."'".$table_name."'");
+                    }
                     if ($isTable){
-                        throw new ErrorException("datatable already exists",  [
+                        throw new ErrorException("datatable already exists", 412, [
                             'table' => $table_name
                         ]);
                     }
@@ -220,7 +208,8 @@ class Index
                     'path'=>$path,
                     'templatePath' =>$templatePath,
                     'table'=>$table,
-                    'fileFullPath'=>$fileFullPath
+                    'fileFullPath'=>$fileFullPath,
+                    'database_engine'=>!empty($tableConfig['items'][$k]['database_engine'])?$tableConfig['items'][$k]['database_engine']:''
                 ];
             }
         }
@@ -241,11 +230,11 @@ class Index
                 $html = (new ParseTemplate())->compile($fileItem['templatePath'],$tplParams);
                 if ($fileItem['type'] === "file"){
                     // 路径为文件,则添加到该文件
-                    $pathFileContent = DirAndFile::getFileContent($fileItem['fileFullPath']);
+                    $pathFileContent = Utils::getFileContent($fileItem['fileFullPath']);
                     $content = $pathFileContent."\r\n".$html;
-                    DirAndFile::createFile($fileItem['fileFullPath'],$content);
+                    Utils::createFile($fileItem['fileFullPath'],$content);
                 }else{
-                    DirAndFile::createFile($fileItem['fileFullPath'],$html);
+                    Utils::createFile($fileItem['fileFullPath'],$html);
                 }
             }
         }
@@ -262,12 +251,13 @@ class Index
             foreach ($createModels as $k=>$item) {
                 $table = $item['table'];
                 if (!empty($table['table_name'])){
+                    $table['database_engine'] = !empty($item['database_engine'])?$item['database_engine']:"";
                     $res =  $this->createTable($table);
                 }
                 if (!empty($table['model_name'])){
                     $tplParams['tables'][$k]['class_name'] =$table['model_name'];
                     $html = (new ParseTemplate())->compile($item['templatePath'],$tplParams);
-                    DirAndFile::createFile($item['fileFullPath'],$html);
+                    Utils::createFile($item['fileFullPath'],$html);
                 }
 
             }
@@ -280,14 +270,24 @@ class Index
      */
     protected function createTable($table){
         $datas = $table['datas'];
+        $tp_version = \think\facade\App::version();
         $comment= "";
         if (!empty($table['table_comment'])){
             $comment =$table['table_comment'];
         }
-        $table_name = $this->databaseConfig['prefix'].$table['table_name'];
+        $driver = Config::get('database.default');
+
+        $engine = !empty($table['database_engine'])?$table['database_engine']:'InnoDB';
+        if (substr($tp_version, 0, 2) == '5.'){
+            $charset = Config::get('database.charset');
+        }else{
+            $charset = Config::get('database.connections.'.$driver.'.charset');//获取配置内的数据库字符集
+        }
+
+        $table_prefix=Config::get('database.connections.'.$driver.'.prefix');
+        $table_name = $table_prefix.$table['table_name'];
         $table_data = '';
         $main_keys = '';
-        $defaultNullTypes = ['timestamp'];
         foreach ($datas as $k=>$item){
             if (!empty($item['not_table_field'])){
                 continue;
@@ -307,15 +307,9 @@ class Index
                 $table_field.=" AUTO_INCREMENT";
             }
             if (!empty($item['default']) || (isset($item['default']) && $item['default']=="0")){
-                $defaultValue = "'".$item['default']."'";
-                if (in_array($item['default'],$this->systemDefaultValues)){
-                    $defaultValue = $item['default'];
-                }
-                $table_field.=" DEFAULT ".$defaultValue."";
+                $table_field.=" DEFAULT '".$item['default']."'";
             }else if (!empty($item['main_key']) && !$item['not_null']){
                 $table_field.=" DEFAULT NULL";
-            }else if (in_array($item['type'],$defaultNullTypes) && empty($item['not_null'])){
-                $table_field.=" NULL DEFAULT NULL";
             }
             $fh = $k < (count($datas)-1)?",":"";
             $table_field.=" COMMENT '".$item['desc']."'".$fh;
@@ -326,23 +320,37 @@ class Index
             $table_data.=",";
             $primaryKey = "PRIMARY KEY (`$main_keys`)";
         }
-
-        $charset = $this->databaseConfig['charset'];
-        $engine = $this->databaseConfig['engine'];
         $sql = "CREATE TABLE IF NOT EXISTS `$table_name` (
         $table_data
         $primaryKey
         ) ENGINE=$engine DEFAULT CHARSET=$charset COMMENT='$comment' AUTO_INCREMENT=1 ;";
 
-        try {
-            $this->config['database_query_function']($sql);
-            return true;
-        } catch (\Exception $e) {
-            throw new ErrorException("datatable create error",  [
-                'table' => $table_name,
-                'message'=>$e->getMessage(),
-                'sql'=>$sql
-            ]);
+        if (substr($tp_version, 0, 2) == '5.'){
+            Db5::startTrans();
+            try {
+                Db5::query($sql);
+                Db5::commit();
+                return true;
+            } catch (\Exception $e) {
+                Db5::rollback();
+                return $e->getMessage();
+            }
+        }else{
+            Db::startTrans();
+            try {
+                Db::query($sql);
+                Db::commit();
+                return true;
+            } catch (\Exception $e) {
+                Db::rollback();
+                throw new ErrorException("datatable create error", 412, [
+                    'table' => $table_name,
+                    'message'=>$e->getMessage(),
+                    'sql'=>$sql
+                ]);
+            }
         }
+
+
     }
 }

+ 6 - 11
vendor/hg/apidoc/src/generator/ParseTemplate.php → vendor/hg/apidoc-thinkphp/src/generator/ParseTemplate.php

@@ -3,8 +3,6 @@ declare(strict_types = 1);
 
 namespace hg\apidoc\generator;
 use hg\apidoc\Utils;
-use hg\apidoc\utils\DirAndFile;
-use hg\apidoc\utils\Helper;
 use think\facade\App;
 
 class ParseTemplate
@@ -13,7 +11,7 @@ class ParseTemplate
     public function compile($path,$params)
     {
         $filePath    =  $path;
-        $tplContent = DirAndFile::getFileContent($filePath);
+        $tplContent = Utils::getFileContent($filePath);
         $tplContent = $this->replaceForeach($tplContent,$params);
         $tplContent = $this->replaceParams($tplContent,$params);
         $tplContent = $this->replaceIf($tplContent,$params);
@@ -37,13 +35,10 @@ class ParseTemplate
                 $fun = $tagArr[0];
                 $k = str_replace(")", "",$tagArr[1] );
                 $v = $this->getObjectValueByKeys($params,$k);
-                if (empty($v)){
-                    return "";
-                }
                 if ($fun === "lower"){
-                   return Helper::lower($v);
+                   return Utils::lower($v);
                 }else if ($fun === "snake"){
-                    return Helper::snake($v);
+                    return Utils::snake($v);
                 }else if ($fun === "lcfirst"){
                     return lcfirst($v);
                 }else if ($fun === "count"){
@@ -174,7 +169,7 @@ class ParseTemplate
                                         $childDataItemData = [$childDataList['itemField']=>$childDataItem,$childDataList['keyField']=>$childDataKey,];
                                         $contentsStr= $this->getForContent($childDataList['content'],array_merge($rowParams,$childDataItemData));
                                         $contentsStr =ltrim($contentsStr,"\r\n");
-                                        if (!empty(Helper::trimEmpty($contentsStr))){
+                                        if (!empty(Utils::trimEmpty($contentsStr))){
                                             $childContents.= $contentsStr;
                                         }
                                     }
@@ -183,12 +178,12 @@ class ParseTemplate
                             }
                             $rowContent=$this->replaceParams($itemStrContent,$rowParams);
                             $itemContentStr=$this->replaceIf($rowContent,$rowParams);
-                            if (!empty(Helper::trimEmpty($itemContentStr))){
+                            if (!empty(Utils::trimEmpty($itemContentStr))){
                                 $itemContent.= $itemContentStr;
                             }
                         }else{
                             $rowContent=$this->getForContent($forOption['content'],$rowParams);
-                            if (empty(Helper::trimEmpty($rowContent))){
+                            if (empty(Utils::trimEmpty($rowContent))){
                                 $rowContent= "";
                             }
                             $itemContent.= $rowContent;

+ 48 - 0
vendor/hg/apidoc-thinkphp/src/parseApi/CacheApiData.php

@@ -0,0 +1,48 @@
+<?php
+declare(strict_types = 1);
+
+namespace hg\apidoc\parseApi;
+
+
+use think\facade\Cache;
+use think\facade\Config;
+
+class CacheApiData
+{
+    protected $config = [];
+
+    public function __construct()
+    {
+        $this->config = Config::get('apidoc');
+    }
+
+
+    /**
+     * 获取接口缓存数据
+     * @param string $appKey
+     * @param string $cacheFileName
+     * @return array|false
+     */
+    public function get(string $appKey)
+    {
+        $json = Cache::get("apidoc_".$appKey);
+        return $json;
+
+    }
+
+    /**
+     * 设置接口缓存
+     * @param string $appKey
+     * @param array $json
+     * @return array|false
+     */
+    public function set(string $appKey, array $json)
+    {
+        if (empty($json)) {
+            return false;
+        }
+        Cache::tag("apidoc")->set("apidoc_".$appKey,$json);
+
+
+    }
+}

+ 863 - 0
vendor/hg/apidoc-thinkphp/src/parseApi/ParseAnnotation.php

@@ -0,0 +1,863 @@
+<?php
+declare(strict_types = 1);
+
+namespace hg\apidoc\parseApi;
+
+use Doctrine\Common\Annotations\AnnotationReader;
+use hg\apidoc\Utils;
+use ReflectionClass;
+use Symfony\Component\ClassLoader\ClassMapGenerator;
+use think\annotation\route\Resource;
+use think\annotation\Route;
+use hg\apidoc\annotation\Group;
+use hg\apidoc\annotation\Sort;
+use hg\apidoc\annotation\Param;
+use hg\apidoc\annotation\Title;
+use hg\apidoc\annotation\Desc;
+use hg\apidoc\annotation\Md;
+use hg\apidoc\annotation\ParamMd;
+use hg\apidoc\annotation\ReturnedMd;
+use hg\apidoc\annotation\Author;
+use hg\apidoc\annotation\Tag;
+use hg\apidoc\annotation\Header;
+use hg\apidoc\annotation\Returned;
+use hg\apidoc\annotation\ParamType;
+use hg\apidoc\annotation\Url;
+use hg\apidoc\annotation\Method;
+use hg\apidoc\annotation\Before;
+use hg\apidoc\annotation\After;
+use hg\apidoc\annotation\ContentType;
+use think\annotation\route\Group as RouteGroup;
+use think\facade\App;
+use think\facade\Config;
+
+class ParseAnnotation
+{
+
+    protected $config = [];
+
+    protected $reader;
+
+    //tags,当前应用/版本所有的tag
+    protected $tags = array();
+
+    //groups,当前应用/版本的分组name
+    protected $groups = array();
+
+    protected $controller_layer = "";
+
+    protected $currentApp = [];
+
+    public function __construct()
+    {
+        $this->reader = new AnnotationReader();
+        $this->config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
+        if (!empty($this->config['ignored_annitation'])){
+            foreach ($this->config['ignored_annitation'] as $item) {
+                AnnotationReader::addGlobalIgnoredName($item);
+            }
+        }
+        $this->controller_layer = Config::get('route.controller_layer',"controller");
+    }
+
+    /**
+     * 生成api接口数据
+     * @param string $appKey
+     * @return array
+     */
+    public function renderApiData(string $appKey): array
+    {
+        $currentApps = (new Utils())->getCurrentApps($appKey);
+        $currentApp  = $currentApps[count($currentApps) - 1];
+        $this->currentApp = $currentApp;
+
+        if (!empty($currentApp['controllers']) && count($currentApp['controllers']) > 0) {
+            // 配置的控制器列表
+            $controllers = $this->getConfigControllers($currentApp['path'],$currentApp['controllers']);
+        } else {
+            // 默认读取所有的
+            $controllers = $this->getDirControllers($currentApp['path']);
+        }
+        $apiData = [];
+        if (!empty($controllers) && count($controllers) > 0) {
+            foreach ($controllers as $class) {
+                $classData = $this->parseController($class);
+                if ($classData !== false) {
+                    $apiData[] = $classData;
+                }
+            }
+        }
+        // 排序
+        $apiList = Utils::arraySortByKey($apiData);
+        $json = array(
+            "data"   => $apiList,
+            "tags"   => $this->tags,
+            "groups" => $this->groups,
+        );
+        return $json;
+    }
+
+    /**
+     * 获取生成文档的控制器列表
+     * @param string $path
+     * @return array
+     */
+    protected function getConfigControllers(string $path,$appControllers): array
+    {
+        $controllers = [];
+        $configControllers = $appControllers;
+        if (!empty($configControllers) && count($configControllers) > 0) {
+            foreach ($configControllers as $item) {
+                if ( strpos($item, $path) !== false && class_exists($item)) {
+                    $controllers[] = $item;
+                }
+            }
+        }
+        return $controllers;
+    }
+
+    /**
+     * 获取目录下的控制器列表
+     * @param string $path
+     * @return array
+     */
+    protected function getDirControllers(string $path): array
+    {
+        if ($path) {
+            if (strpos(App::getRootPath(), '/') !== false) {
+                $pathStr = str_replace("\\", "/", $path);
+            } else {
+                $pathStr = $path;
+            }
+            $dir = App::getRootPath() . $pathStr;
+        } else {
+            $dir = App::getRootPath() . $this->controller_layer;
+        }
+        $controllers = [];
+        if (is_dir($dir)) {
+            $controllers = $this->scanDir($dir, $path);
+        }
+        return $controllers;
+    }
+
+    /**
+     * 处理指定目录下的控制器
+     * @param string $dir
+     * @param string $appPath
+     * @return array
+     */
+    protected function scanDir(string $dir, string $appPath): array
+    {
+        $list = [];
+        foreach (ClassMapGenerator::createMap($dir) as $class => $path) {
+            if (strpos($class, $appPath) !== false || strpos($class, "\\") !== false) {
+                $classNamespace = $class;
+            }else{
+                $pathStr = str_replace("/", "\\", $path);
+                $pathArr   = explode($appPath, $pathStr);
+                if (!empty($pathArr[1])){
+                    $classNamespace = $appPath.str_replace(".php", "", $pathArr[1]);
+                }else{
+                    continue;
+                }
+            }
+            if (
+                !isset($this->config['filter_controllers']) ||
+                (isset($this->config['filter_controllers']) && !in_array($classNamespace, $this->config['filter_controllers'])) &&
+                $this->config['definitions'] != $classNamespace
+            ) {
+                if (strpos($classNamespace, '\\') === false) {
+                    $list[] = $appPath . "\\" . $classNamespace;
+                } else {
+                    $list[] = $classNamespace;
+                }
+            }
+        }
+        return $list;
+    }
+
+    protected function parseController($class)
+    {
+
+        $data                 = [];
+        $refClass             = new ReflectionClass($class);
+        $classTextAnnotations = $this->parseTextAnnotation($refClass);
+        if (in_array("NotParse", $classTextAnnotations)) {
+            return false;
+        }
+        $title = $this->reader->getClassAnnotation($refClass, Title::class);
+        $group = $this->reader->getClassAnnotation($refClass, Group::class);
+        $sort = $this->reader->getClassAnnotation($refClass, Sort::class);
+
+        $routeGroup         = $this->reader->getClassAnnotation($refClass, RouteGroup::class);
+        $controllersNameArr = explode("\\", $class);
+        $controllersName    = $controllersNameArr[count($controllersNameArr) - 1];
+        $data['controller'] = $controllersName;
+        $data['group']      = !empty($group->value) ? $group->value : null;
+        $data['sort']      = !empty($sort->value) ? $sort->value : null;
+        if (!empty($data['group']) && !in_array($data['group'], $this->groups)) {
+            $this->groups[] = $data['group'];
+        }
+        $data['title'] = !empty($title) && !empty($title->value) ? $title->value : "";
+
+        if (empty($title)) {
+            if (!empty($classTextAnnotations) && count($classTextAnnotations) > 0) {
+                $data['title'] = $classTextAnnotations[0];
+            } else {
+                $data['title'] = $controllersName;
+            }
+        }
+        $data['title'] = Utils::getLang($data['title']);
+        $methodList       = [];
+        $data['menu_key'] = Utils::createRandKey($data['controller']);
+
+        foreach ($refClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $refMethod) {
+
+            $methodItem = $this->parseApiMethod($refClass,$refMethod,$routeGroup);
+            if ($methodItem===false){
+                continue;
+            }
+            if (in_array("NotDebug", $classTextAnnotations)) {
+                $methodItem['notDebug'] = true;
+            }
+            $methodList[] = $methodItem;
+
+        }
+        $data['children'] = $methodList;
+        if (count($methodList)===0){
+            return false;
+        }
+        return $data;
+    }
+
+
+    protected function parseApiMethod($refClass,$refMethod,$routeGroup){
+        $config               = $this->config;
+        if (empty($refMethod->name)) {
+            return false;
+        }
+        $methodItem = $this->parseAnnotation($refMethod, true,"controller");
+        if (!count((array)$methodItem)) {
+            return false;
+        }
+        $textAnnotations = $this->parseTextAnnotation($refMethod);
+        // 标注不解析的方法
+        if (in_array("NotParse", $textAnnotations)) {
+            return false;
+        }
+        if (
+            in_array("NotDebug", $textAnnotations) ||
+            (isset($config['notDebug']) && $config['notDebug']===true) ||
+            (isset($this->currentApp['notDebug']) && $this->currentApp['notDebug']===true)
+        ) {
+            $methodItem['notDebug'] = true;
+        }
+        // 无标题,且有文本注释
+        if (empty($methodItem['title']) && !empty($textAnnotations) && count($textAnnotations) > 0) {
+            $methodItem['title'] = Utils::getLang($textAnnotations[0]);
+        }
+        // 添加统一headers请求头参数
+        if ((!empty($config['headers']) || !empty($this->currentApp['headers'])) && !in_array("NotHeaders", $textAnnotations)) {
+            $headers = [];
+            $configHeaders = !empty($config['headers'])?$config['headers']:[];
+            if (!empty($this->currentApp['headers'])){
+                $configHeaders = Utils::arrayMergeAndUnique("name", $configHeaders, $this->currentApp['headers']);
+            }
+            foreach ($configHeaders as $headerItem){
+                $headerItem['desc'] = Utils::getLang($headerItem['desc']);
+                $headers[] = $headerItem;
+            }
+            if (!empty($methodItem['header'])) {
+                $methodItem['header'] = Utils::arrayMergeAndUnique("name", $headers, $methodItem['header']);
+            } else {
+                $methodItem['header'] = $headers;
+            }
+        }
+
+        // 添加统一params请求参数
+        if ((!empty($config['parameters']) || !empty($this->currentApp['parameters'])) && !in_array("NotParameters", $textAnnotations)) {
+            $params = [];
+            $configParams = !empty($config['parameters'])?$config['parameters']:[];
+            if (!empty($this->currentApp['parameters'])){
+                $configParams = Utils::arrayMergeAndUnique("name", $configParams, $this->currentApp['parameters']);
+            }
+            foreach ($configParams as $paramItem){
+                $paramItem['desc'] = Utils::getLang($paramItem['desc']);
+                $params[] = $paramItem;
+            }
+
+            if (!empty($methodItem['param'])) {
+                $methodItem['param'] = Utils::arrayMergeAndUnique("name", $configParams, $methodItem['param']);
+            } else {
+                $methodItem['param'] = $params;
+            }
+        }
+        // 添加responses统一响应体
+        if (
+            !empty($config['responses']) &&
+            !is_string($config['responses']) &&
+            !in_array("NotResponses", $textAnnotations)
+        ) {
+            // 显示在响应体中
+            $returned = [];
+            $hasMian  = false;
+            $responsesData = $config['responses'];
+            // 合并统一响应体及响应参数相同的字段
+            $returnData = [];
+            $resKeys = [];
+            foreach ($responsesData as $resItem) {
+                $resKeys[]=$resItem['name'];
+            }
+            foreach ($methodItem['return'] as $returnItem){
+                if (!(in_array($returnItem['name'],$resKeys) && !empty($returnItem['source']) &&  $returnItem['source']==='controller' && !empty($returnItem['replaceGlobal']))){
+                    $returnData[]=$returnItem;
+                }
+            }
+
+            foreach ($responsesData as $resItem) {
+                $resData = $resItem;
+                $globalFind = Utils::getArrayFind($methodItem['return'],function ($item)use ($resItem){
+                    if ($item['name'] == $resItem['name'] && !empty($item['source']) && $item['source']==='controller' && !empty($item['replaceGlobal'])){
+                        return true;
+                    }
+                    return false;
+                });
+                if (!empty($globalFind)){
+                    $resData = array_merge($resItem,$globalFind);
+                }else if (!empty($resData['main']) && $resData['main'] === true) {
+                    $resData['children'] = $returnData;
+
+                    $resData['resKeys']=$resKeys;
+                    $hasMian           = true;
+                }
+                $resData['find'] =$globalFind;
+                $resData['desc'] = Utils::getLang($resData['desc']);
+                $returned[] = $resData;
+            }
+            if (!$hasMian) {
+                $returned = Utils::arrayMergeAndUnique("name", $returned, $methodItem['return']);
+            }
+            $methodItem['return'] = $returned;
+        }
+        // 默认method
+        if (empty($methodItem['method'])) {
+            $methodItem['method'] = !empty($config['default_method']) ? $config['default_method'] : 'GET';
+        }
+        $methodItem['method'] = strtoupper($methodItem['method']);
+
+
+        // 默认default_author
+        if (empty($methodItem['author']) && !empty($config['default_author']) && !in_array("NotDefaultAuthor", $textAnnotations)) {
+            $methodItem['author'] = $config['default_author'];
+        }
+
+        // Tags
+        if (!empty($methodItem['tag'])) {
+            $tagText = $methodItem['tag'];
+            if (strpos($tagText, ',') !== false) {
+                $tagArr = explode(",", $tagText);
+                $tagList = [];
+                foreach ($tagArr as $tag) {
+                    $t = Utils::getLang($tag);
+                    $tagList[]=$t;
+                    if (!in_array($tag, $this->tags)) {
+                        $this->tags[] =  $t;
+                    }
+                }
+                $methodItem['tag'] = $tagList;
+            } else {
+                $methodItem['tag'] = [Utils::getLang($tagText)];
+                if (!in_array($tagText, $this->tags)) {
+                    $this->tags[] = $tagText;
+                }
+            }
+        }
+        // 无url,自动生成
+        if (empty($methodItem['url'])) {
+            $methodItem['url'] = $this->autoCreateUrl($refClass->name,$refMethod);
+        } else if (!empty($methodItem['url']) && $methodItem['isAnnotationUrl']===false && !empty($routeGroup->value)) {
+            // 路由分组,url加上分组
+            $methodItem['url'] = '/' . $routeGroup->value . '/' . $methodItem['url'];
+        }else if (!empty($methodItem['url']) && substr($methodItem['url'], 0, 1) != "/") {
+            $methodItem['url'] = "/" . $methodItem['url'];
+        }
+        $methodItem['name']     = $refMethod->name;
+        $methodItem['menu_key'] =$this->currentApp['folder']."_".$methodItem['method']."_".$methodItem['url'];
+        return $methodItem;
+    }
+
+    /**
+     * 自动生成url
+     * @param $method
+     * @return string
+     */
+    protected function autoCreateUrl($classPath,$method): string
+    {
+        if (!empty($this->config['auto_url']) && !empty($this->config['auto_url']['custom']) && is_callable($this->config['auto_url']['custom'])){
+           return $this->config['auto_url']['custom']($classPath,$method->name);
+        }
+        $searchString = $this->controller_layer . '\\';
+        $substr = substr(strstr($classPath, $searchString), strlen($searchString));
+        $multistage_route_separator = ".";
+        if (!empty($this->config['auto_url']) && !empty($this->config['auto_url']['multistage_route_separator'])){
+            $multistage_route_separator = $this->config['auto_url']['multistage_route_separator'];
+        }
+        $pathArr = explode("\\", str_replace($substr, str_replace('\\', $multistage_route_separator, $substr), $classPath));
+        $filterPathNames = array($this->controller_layer);
+        $appNameespace = App::getNamespace();
+        if (strpos($appNameespace, '\\') !== false){
+            $appNameespaceArr    = explode("\\", $appNameespace);
+            $filterPathNames[] = $appNameespaceArr[0];
+        }else{
+            $filterPathNames[]=App::getNamespace();
+        }
+        $classUrlArr = [];
+        foreach ($pathArr as $item) {
+            if (!in_array($item, $filterPathNames)) {
+                if (!empty($this->config['auto_url']) && !empty($this->config['auto_url']['letter_rule'])){
+                    switch ($this->config['auto_url']['letter_rule']) {
+                        case 'lcfirst':
+                            $classUrlArr[] = lcfirst($item);
+                            break;
+                        case 'ucfirst':
+                            $classUrlArr[] = ucfirst($item);
+                            break;
+                        default:
+                            $classUrlArr[] = $item;
+                    }
+                }else{
+                    $classUrlArr[] = $item;
+                }
+            }
+        }
+        $classUrl = implode('/', $classUrlArr);
+        return '/' . $classUrl . '/' . $method->name;
+    }
+
+    /**
+     * ref引用
+     * @param $refPath
+     * @param bool $enableRefService
+     * @return false|string[]
+     */
+    protected function renderRef(string $refPath, bool $enableRefService = true): array
+    {
+        $res = ['type' => 'model'];
+        // 通用定义引入
+        if (strpos($refPath, '\\') === false) {
+            $config      = $this->config;
+            $refPath     = $config['definitions'] . '\\' . $refPath;
+            $data        = $this->renderService($refPath);
+            $res['type'] = "service";
+            $res['data'] = $data;
+            return $res;
+        }
+        // 模型引入
+        $modelData = (new ParseModel($this->reader))->renderModel($refPath);
+        if ($modelData !== false) {
+            $res['data'] = $modelData;
+            return $res;
+        }
+        if ($enableRefService === false) {
+            return false;
+        }
+        $data        = $this->renderService($refPath);
+        $res['type'] = "service";
+        $res['data'] = $data;
+        return $res;
+    }
+
+    /**
+     * 解析注释引用
+     * @param $refPath
+     * @return array
+     * @throws \ReflectionException
+     */
+    protected function renderService(string $refPath)
+    {
+        $pathArr    = explode("\\", $refPath);
+        $methodName = $pathArr[count($pathArr) - 1];
+        unset($pathArr[count($pathArr) - 1]);
+        $classPath    = implode("\\", $pathArr);
+        $classReflect = new \ReflectionClass($classPath);
+        $methodName   = trim($methodName);
+        $refMethod    = $classReflect->getMethod($methodName);
+        $res          = $this->parseAnnotation($refMethod, true);
+        return $res;
+    }
+
+    /**
+     * 处理Param/Returned的字段名name、params子级参数
+     * @param $values
+     * @return array
+     */
+    protected function handleParamValue($values, string $field = 'param'): array
+    {
+        $name   = "";
+        $params = [];
+        if (!empty($values) && is_array($values) && count($values) > 0) {
+            foreach ($values as $item) {
+                if (is_string($item)) {
+                    $name = $item;
+                } else if (is_object($item)) {
+                    if (!empty($item->ref)) {
+                        $refRes = $this->renderRef($item->ref, true);
+                        $params = $this->handleRefData($params, $refRes, $item, $field);
+                    } else {
+                        $param         = [
+                            "name"    => "",
+                            "type"    => $item->type,
+                            "desc"    => Utils::getLang($item->desc),
+                            "default" => $item->default,
+                            "require" => $item->require,
+                            "childrenType"=> $item->childrenType
+                        ];
+                        if (!empty($item->mock)){
+                            $param['mock']=$item->mock;
+                        }
+                        $children      = $this->handleParamValue($item->value);
+                        $param['name'] = $children['name'];
+                        if (count($children['params']) > 0) {
+                            $param['children'] = $children['params'];
+                        }
+                        $params[] = $param;
+                    }
+                }
+            }
+        } else {
+            $name = $values;
+        }
+        return ['name' => $name, 'params' => $params];
+    }
+
+    /**
+     * 解析方法注释
+     * @param $refMethod
+     * @param bool $enableRefService 是否终止service的引入
+     * @param string $source 注解来源
+     * @return array
+     */
+    protected function parseAnnotation($refMethod, bool $enableRefService = true,$source=""): array
+    {
+        $data = [];
+        if ($annotations = $this->reader->getMethodAnnotations($refMethod)) {
+            $headers = [];
+            $params  = [];
+            $returns = [];
+            $before = [];
+            $after = [];
+            $isAnnotationUrl = false;
+
+            foreach ($annotations as $annotation) {
+                switch (true) {
+                    case $annotation instanceof Param:
+                        $params = $this->handleParamAndReturned($params,$annotation,'param',$enableRefService);
+                        break;
+                    case $annotation instanceof Returned:
+
+                        $returns = $this->handleParamAndReturned($returns,$annotation,'return',$enableRefService,$source);
+                        break;
+                    case $annotation instanceof Header:
+                        if (!empty($annotation->ref)) {
+                            $refRes  = $this->renderRef($annotation->ref, $enableRefService);
+                            $headers = $this->handleRefData($headers, $refRes, $annotation, 'header');
+                        } else {
+                            $param     = [
+                                "name"    => $annotation->value,
+                                "desc"    => Utils::getLang($annotation->desc),
+                                "require" => $annotation->require,
+                                "type"    => $annotation->type,
+                                "default" => $annotation->default,
+                            ];
+                            $headers[] = $param;
+                        }
+                        break;
+                    case $annotation instanceof Route:
+                        if (empty($data['method'])) {
+                            $data['method'] = $annotation->method;
+                        }
+                        if (empty($data['url'])) {
+                            $data['url'] = $annotation->value;
+                        }
+                        break;
+                    case $annotation instanceof Author:
+                        $data['author'] = $annotation->value;
+                        break;
+
+                    case $annotation instanceof Title:
+                        $data['title'] = Utils::getLang($annotation->value);
+                        break;
+                    case $annotation instanceof Desc:
+                        $data['desc'] = Utils::getLang($annotation->value);
+                        if (!empty($annotation->mdRef)){
+                            $data['md'] = $annotation->mdRef;
+                        }
+                        break;
+                    case $annotation instanceof Md:
+                        $data['md'] = $annotation->value;
+                        if (!empty($annotation->ref)){
+                            $data['md'] = (new ParseMarkdown())->getContent("",$annotation->ref);
+                        }
+                        break;
+                    case $annotation instanceof ParamMd:
+                        $data['paramMd'] = $annotation->value;
+                        if (!empty($annotation->ref)){
+                            $data['paramMd'] = (new ParseMarkdown())->getContent("",$annotation->ref);
+                        }
+                        break;
+                    case $annotation instanceof ReturnedMd:
+                        $data['returnMd'] = $annotation->value;
+                        if (!empty($annotation->ref)){
+                            $data['returnMd'] = (new ParseMarkdown())->getContent("",$annotation->ref);
+                        }
+                        break;
+                    case $annotation instanceof ParamType:
+                        $data['paramType'] = $annotation->value;
+                        break;
+                    case $annotation instanceof Url:
+                        $data['url'] = $annotation->value;
+                        $isAnnotationUrl=true;
+                        break;
+                    case $annotation instanceof Method:
+                        $data['method'] = $annotation->value;
+                        break;
+                    case $annotation instanceof Tag:
+                        $data['tag'] = $annotation->value;
+                        break;
+                    case $annotation instanceof ContentType:
+                    $data['contentType'] = $annotation->value;
+                    break;
+                    case $annotation instanceof Before:
+                        $beforeAnnotation = $this->handleEventAnnotation($annotation,'before');
+                        $before =  array_merge($before,$beforeAnnotation);
+                        break;
+                    case $annotation instanceof After:
+                        $afterAnnotation = $this->handleEventAnnotation($annotation,'after');
+                        $after =array_merge($after,$afterAnnotation);
+                        break;
+                }
+            }
+            if ($headers && count($headers) > 0) {
+                $data['header'] = $headers;
+            }
+            $data['param']  = $params;
+            $data['return'] = $returns;
+            $data['before'] = $before;
+            $data['after'] = $after;
+            $data['isAnnotationUrl'] = $isAnnotationUrl;
+        }
+        return $data;
+    }
+
+    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 = Utils::objectToArray($annotation);
+            $valueList = [];
+            foreach ($annotation->value as $valueItem){
+                $valueItemInfo = Utils::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{
+            return [$annotation];
+        }
+    }
+
+
+    /**
+     * 处理请求参数与返回参数
+     * @param $params
+     * @param $annotation
+     * @param string $type
+     * @param false $enableRefService
+     * @param string $source 注解来源
+     * @return array
+     */
+    protected function handleParamAndReturned($params,$annotation,$type="param",$enableRefService=false,$source=""){
+        if (!empty($annotation->ref)) {
+            $refRes = $this->renderRef($annotation->ref, $enableRefService);
+            $params = $this->handleRefData($params, $refRes, $annotation, $type,$source);
+        } else {
+
+            $param =  Utils::objectToArray($annotation);
+            $param["source"] = $source;
+            $param["desc"] = Utils::getLang($param['desc']);
+
+            $children      = $this->handleParamValue($annotation->value, $type);
+            $param['name'] = $children['name'];
+            if (count($children['params']) > 0) {
+                $param['children'] = $children['params'];
+
+            }
+            if ($annotation->type === 'tree' ) {
+                // 类型为tree的
+                $param['children'][] = [
+                    'children' => $children['params'],
+                    'name'   => !empty($annotation->childrenField)?$annotation->childrenField:"children",
+                    'type'   => 'array',
+                    'desc'   => Utils::getLang($annotation->childrenDesc),
+                ];
+            }
+            // 合并同级已有的字段
+            $params = Utils::arrayMergeAndUnique("name", $params, [$param]);
+        }
+            return $params;
+    }
+
+    /**
+     * 解析非注解文本注释
+     * @param $refMethod
+     * @return array|false
+     */
+    protected function parseTextAnnotation($refMethod): array
+    {
+        $annotation = $refMethod->getDocComment();
+        if (empty($annotation)) {
+            return [];
+        }
+        if (preg_match('#^/\*\*(.*)\*/#s', $annotation, $comment) === false)
+            return [];
+        $comment = trim($comment [1]);
+        if (preg_match_all('#^\s*\*(.*)#m', $comment, $lines) === false)
+            return [];
+        $data = [];
+        foreach ($lines[1] as $line) {
+            $line = trim($line);
+            if (!empty ($line) && strpos($line, '@') !== 0) {
+                $data[] = $line;
+            }
+        }
+        return $data;
+    }
+
+
+    /**
+     * 处理param、returned 参数
+     * @param $params
+     * @param $refRes
+     * @param $annotation
+     * @param string|null $source 注解来源
+     * @return array
+     */
+    protected function handleRefData($params, $refRes, $annotation, string $field,$source=""): array
+    {
+        if ($refRes['type'] === "model" && count($refRes['data']) > 0) {
+            // 模型引入
+            $data = $refRes['data'];
+        } else if ($refRes['type'] === "service" && !empty($refRes['data']) && !empty($refRes['data'][$field])) {
+            // service引入
+            $data = $refRes['data'][$field];
+        } else {
+            return $params;
+        }
+        // 过滤field
+        if (!empty($annotation->field)) {
+            $data = (new Utils())->filterParamsField($data, $annotation->field, 'field');
+        }
+        // 过滤withoutField
+        if (!empty($annotation->withoutField)) {
+            $data = (new Utils())->filterParamsField($data, $annotation->withoutField, 'withoutField');
+        }
+
+        if (!empty($annotation->value)) {
+            $item =  Utils::objectToArray($annotation);
+            $item['children'] = $data;
+            $item['source'] = $source;
+            $param["desc"] = Utils::getLang($item['desc']);
+
+            $children      = $this->handleParamValue($annotation->value, 'param');
+            $item['name'] = $children['name'];
+            if (count($children['params']) > 0) {
+                $item['children'] = Utils::arrayMergeAndUnique("name",$data,$children['params']);
+            }
+            if ($annotation->type === 'tree' ) {
+                // 类型为tree的
+                $item['children'][] = [
+                    'children' => $item['children'],
+                    'name'   =>!empty($annotation->childrenField) ?$annotation->childrenField:'children',
+                    'type'   => 'array',
+                    'desc'   => Utils::getLang($annotation->childrenDesc),
+                ];
+            }
+            $params[] = $item;
+
+
+        } else {
+            $params = Utils::arrayMergeAndUnique("name",$params,$data);
+//            $params = array_merge($params, $data);
+        }
+        return $params;
+    }
+
+
+    /**
+     * 对象分组到tree
+     * @param $tree
+     * @param $objectData
+     * @param string $childrenField
+     * @return array
+     */
+    public function objtctGroupByTree($tree,$objectData,$childrenField='children'){
+        $data = [];
+        foreach ($tree as $node){
+            if (!empty($node[$childrenField])){
+                $node[$childrenField] = $this->objtctGroupByTree($node[$childrenField],$objectData);
+            }else if (!empty($objectData[$node['name']])){
+                $node[$childrenField] =  $objectData[$node['name']];
+            }
+            $node['menu_key'] = Utils::createRandKey( $node['name']);
+            $data[] = $node;
+        }
+        return $data;
+    }
+
+    /**
+     * 合并接口到应用分组
+     * @param $apiData
+     * @param $groups
+     * @return array
+     */
+    public function mergeApiGroup($apiData,$groups){
+        if (empty($groups) || count($apiData)<1){
+            return $apiData;
+        }
+        $apiObject = [];
+        foreach ($apiData as $controller){
+            if (!empty($controller['group'])){
+                if (!empty($apiObject[$controller['group']])){
+                    $apiObject[$controller['group']][] = $controller;
+                }else{
+                    $apiObject[$controller['group']] = [$controller];
+                }
+            }else{
+                if (!empty($apiObject['notGroup'])){
+                    $apiObject['notGroup'][] = $controller;
+                }else{
+                    $apiObject['notGroup'] = [$controller];
+                }
+            }
+        }
+        if (!empty($apiObject['notGroup'])){
+            array_unshift($groups,['title'=>'未分组','name'=>'notGroup']);
+        }
+        $res = $this->objtctGroupByTree($groups,$apiObject);
+        return $res;
+    }
+}

+ 31 - 50
vendor/hg/apidoc/src/parses/ParseMarkdown.php → vendor/hg/apidoc-thinkphp/src/parseApi/ParseMarkdown.php

@@ -1,32 +1,32 @@
 <?php
 declare(strict_types = 1);
 
-namespace hg\apidoc\parses;
+namespace hg\apidoc\parseApi;
 
-
-use hg\apidoc\utils\DirAndFile;
-use hg\apidoc\utils\Helper;
-use hg\apidoc\utils\Lang;
+use think\facade\App;
+use hg\apidoc\Utils;
+use think\facade\Config;
+use think\facade\Lang;
 
 class ParseMarkdown
 {
     protected $config = [];
 
-    public function __construct($config)
+    public function __construct()
     {
-        $this->config = $config;
+        $this->config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
     }
 
     /**
      * 获取md文档菜单
      * @return array
      */
-    public function getDocsMenu($appKey,string $lang): array
+    public function getDocsMenu(string $lang): array
     {
         $config  = $this->config;
         $docData = [];
         if (!empty($config['docs']) && count($config['docs']) > 0) {
-            $docData = $this->handleDocsMenuData($config['docs'],$appKey,$lang);
+            $docData = $this->handleDocsMenuData($config['docs'],$lang);
         }
         return $docData;
     }
@@ -36,44 +36,43 @@ class ParseMarkdown
      * @param array $menus
      * @return array
      */
-    protected function handleDocsMenuData(array $menus,$appKey,string $lang): array
+    protected function handleDocsMenuData(array $menus,string $lang): array
     {
         $list = [];
         foreach ($menus as $item) {
-            $item['title']     = Lang::getLang($item['title']);
-            if (!empty($item['appKey']) && $item['appKey'] != $appKey){
-                continue;
+            $item['title']     = Utils::getLang($item['title']);
+            if(!empty($item['path'])){
+//                $lang = Lang::getLangSet();
+                $item['path'] = Utils::replaceTemplate($item['path'],['lang'=>$lang]);
             }
-
             if (!empty($item['children']) && count($item['children']) > 0) {
-                $item['children']    = $this->handleDocsMenuData($item['children'],$appKey,$lang);
-                $item['menuKey'] = Helper::createRandKey("md_group");
+                $item['children']    = $this->handleDocsMenuData($item['children'],$lang);
+                $item['menu_key'] = Utils::createRandKey("md_group");
             } else {
-                $filePath    = static::getFilePath($appKey,$item['path'],$lang);
-                if (!file_exists($filePath['filePath'])) {
-                    continue;
-                }
-
-                if(!empty($item['path'])){
-                    $item['path'] = Helper::replaceTemplate($item['path'],['lang'=>$lang]);
-                }
                 $item['type']     = 'md';
-                $item['menuKey'] = Helper::createApiKey($item['path']);
+                $item['menu_key'] = Utils::createRandKey("md");
             }
             $list[]           = $item;
         }
         return $list;
     }
 
-    public static function getFilePath(string $appKey, string $path,$lang=""){
+
+    /**
+     * 获取md文档内容
+     * @param string $appKey
+     * @param string $path
+     * @return string
+     */
+    public function getContent(string $appKey, string $path,$lang="")
+    {
         if (!empty($appKey)){
-            $currentAppConfig = Helper::getCurrentAppConfig($appKey);
-            $currentApps = $currentAppConfig['apps'];
-            $fullPath      = Helper::replaceCurrentAppTemplate($path, $currentApps);
+            $currentApps = (new Utils())->getCurrentApps($appKey);
+            $fullPath      = (new Utils())->replaceCurrentAppTemplate($path, $currentApps);
         }else{
             $fullPath = $path;
         }
-        $fullPath = Helper::replaceTemplate($fullPath,[
+        $fullPath = Utils::replaceTemplate($fullPath,[
             'lang'=>$lang
         ]);
 
@@ -89,26 +88,8 @@ class ParseMarkdown
         if (strpos($fullPath, '.md') === false) {
             $fileSuffix = ".md";
         }
-        $filePath    = APIDOC_ROOT_PATH . $mdPath . $fileSuffix;
-        return [
-            'filePath'=>$filePath,
-            'anchor'=>$mdAnchor
-        ];
-    }
-
-
-    /**
-     * 获取md文档内容
-     * @param string $appKey
-     * @param string $path
-     * @return string
-     */
-    public static function getContent(string $appKey, string $path,$lang="")
-    {
-        $filePathArr    = static::getFilePath($appKey,$path,$lang);
-        $mdAnchor = $filePathArr['anchor'];
-        $filePath = $filePathArr['filePath'];
-        $contents    = DirAndFile::getFileContent($filePath);
+        $filePath    = App::getRootPath() . $mdPath . $fileSuffix;
+        $contents    = Utils::getFileContent($filePath);
         // 获取指定h2标签内容
         if (!empty($mdAnchor)){
             if (strpos($contents, '## ') !== false) {

+ 245 - 0
vendor/hg/apidoc-thinkphp/src/parseApi/ParseModel.php

@@ -0,0 +1,245 @@
+<?php
+declare(strict_types = 1);
+
+namespace hg\apidoc\parseApi;
+
+use Doctrine\Common\Annotations\Reader;
+use hg\apidoc\exception\ErrorException;
+use think\Db as Db5;
+use think\facade\Db;
+use hg\apidoc\annotation\Field;
+use hg\apidoc\annotation\WithoutField;
+use hg\apidoc\annotation\AddField;
+use think\helper\Str;
+use hg\apidoc\Utils;
+
+class ParseModel
+{
+    protected $reader;
+
+    public function __construct(Reader $reader)
+    {
+        $this->reader = $reader;
+    }
+
+    /**
+     * 生成模型数据
+     * @param string $path
+     * @return array|false
+     * @throws \ReflectionException
+     */
+    public function renderModel(string $path)
+    {
+
+        if (strpos($path, '@') !== false){
+            $pathArr   = explode("@", $path);
+            $modelClassPath = $pathArr[0];
+            $methodName =  $pathArr[1];
+            $model = $this->getModelClass($modelClassPath);
+            return $this->parseModelTable($model,$modelClassPath,$methodName);
+        }else if (class_exists($path)) {
+            $model = $this->getModelClass($path);
+            return $this->parseModelTable($model,$path,"");
+        } else {
+            $modelClassArr   = explode("\\", $path);
+            $methodName = $modelClassArr[count($modelClassArr) - 1];
+            unset($modelClassArr[count($modelClassArr) - 1]);
+            $modelClassPath  = implode("\\", $modelClassArr);
+            if (class_exists($modelClassPath)){
+                $model = $this->getModelClass($modelClassPath);
+                return $this->parseModelTable($model,$modelClassPath,$methodName);
+            }else{
+                throw new ErrorException("ref file not exists", 412, [
+                    'filepath' => $path
+                ]);
+            }
+        }
+    }
+
+    protected function parseModelTable($model,$path,$methodName=""){
+        if (!is_callable(array($model, 'getTable'))) {
+            return false;
+        }
+        $classReflect    = new \ReflectionClass($path);
+        // 获取所有模型属性
+        $propertys = $classReflect->getDefaultProperties();
+
+        $table = $this->getTableDocument($model, $propertys);
+        if (empty($methodName)){
+            return $table;
+        }
+        $methodAction    = $classReflect->getMethod($methodName);
+        // 模型注释-field
+        if ($fieldAnnotations = $this->reader->getMethodAnnotation($methodAction, Field::class)) {
+            $table = (new Utils())->filterParamsField($table, $fieldAnnotations->value, 'field');
+        }
+        // 模型注释-withoutField
+        if ($fieldAnnotations = $this->reader->getMethodAnnotation($methodAction, WithoutField::class)) {
+            $table = (new Utils())->filterParamsField($table, $fieldAnnotations->value, 'withoutField');
+        }
+        // 模型注释-addField
+        if ($annotations = $this->reader->getMethodAnnotations($methodAction)) {
+            foreach ($annotations as $annotation) {
+                switch (true) {
+                    case $annotation instanceof AddField:
+                        $param         = [
+                            "name"    => "",
+                            "desc"    => $annotation->desc,
+                            "require" => $annotation->require,
+                            "type"    => $annotation->type,
+                            "default" => $annotation->default
+                        ];
+                        $children      = $this->handleParamValue($annotation->value);
+                        $param['name'] = $children['name'];
+                        if (count($children['params']) > 0) {
+                            $param['children'] = $children['params'];
+                        }
+                        $isExists = false;
+                        $newTable = [];
+                        foreach ($table as $item) {
+                            if ($param['name'] === $item['name']) {
+                                $isExists   = true;
+                                $newTable[] = $param;
+                            } else {
+                                $newTable[] = $item;
+                            }
+                        }
+                        $table = $newTable;
+                        if (!$isExists) {
+                            $table[] = $param;
+                        }
+                        break;
+                }
+            }
+        }
+        return $table;
+    }
+
+    /**
+     * 处理字段参数
+     * @param $values
+     * @return array
+     */
+    protected function handleParamValue($values): array
+    {
+        $name   = "";
+        $params = [];
+        if (!empty($values) && is_array($values) && count($values) > 0) {
+            foreach ($values as $item) {
+                if (is_string($item)) {
+                    $name = $item;
+                } else if (is_object($item)) {
+                    $param         = [
+                        "name"    => "",
+                        "type"    => $item->type,
+                        "desc"    => $item->desc,
+                        "default" => $item->default,
+                        "require" => $item->require,
+                    ];
+                    $children      = $this->handleParamValue($item->value);
+                    $param['name'] = $children['name'];
+                    if (count($children['params']) > 0) {
+                        $param['children'] = $children['params'];
+                    }
+                    $params[] = $param;
+                }
+            }
+        } else {
+            $name = $values;
+        }
+        return ['name' => $name, 'params' => $params];
+    }
+
+    /**
+     * 获取模型实例
+     * @param $method
+     * @return mixed|null
+     */
+    public function getModelClass($namespaceName)
+    {
+        if (!empty($namespaceName) && class_exists($namespaceName)) {
+            $modelInstance = new $namespaceName();
+            return $modelInstance;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * 获取模型注解数据
+     * @param $model
+     * @param $propertys
+     * @return array
+     */
+    public function getTableDocument($model,array $propertys):array
+    {
+
+        $tp_version = \think\facade\App::version();
+        if (substr($tp_version, 0, 2) == '5.'){
+            $createSQL = Db5::query("show create table " . $model->getTable())[0];
+        }else{
+            $createSQL = Db::query("show create table " . $model->getTable())[0];
+        }
+
+        $createTable = "";
+        if (!empty($createSQL['Create Table'])){
+            $createTable = $createSQL['Create Table'];
+        }else  if(!empty($createSQL['create table'])){
+            $createTable = $createSQL['create table'];
+        }else{
+            throw new ErrorException("datatable not exists", 412, $createSQL);
+        }
+        preg_match_all("#[^KEY]`(.*?)` (.*?) (.*?),\n#", $createTable, $matches);
+        $fields       = $matches[1];
+        $types        = $matches[2];
+        $contents     = $matches[3];
+        $fieldComment = [];
+        //组织注释
+        for ($i = 0; $i < count($matches[0]); $i++) {
+            $key     = $fields[$i];
+            $type    = $types[$i];
+            $default = "";
+            $require = "";
+            $desc    = "";
+            $content = $contents[$i];
+            if (strpos($type, '(`') !== false) {
+                continue;
+            }
+            if (strpos($content, 'COMMENT') !== false) {
+                // 存在字段注释
+                preg_match_all("#COMMENT\s*'(.*?)'#", $content, $edscs);
+                if (!empty($edscs[1]) && !empty($edscs[1][0])){
+                    $desc = Utils::getLang($edscs[1][0]);
+
+                }
+
+            }
+            if (strpos($content, 'DEFAULT') !== false) {
+                // 存在字段默认值
+                preg_match_all("#DEFAULT\s*'(.*?)'#", $content, $defaults);
+                $default = $defaults[1] && is_array($defaults[1])?$defaults[1][0]:"";
+            }
+
+            if (strpos($content, 'NOT NULL') !== false) {
+                // 必填字段
+                $require = "1";
+            }
+
+            $name = $key;
+            // 转换字段名为驼峰命名(用于输出)
+            if (isset($propertys['convertNameToCamel']) && $propertys['convertNameToCamel'] === true) {
+                $name = Str::camel($key);
+            }
+            $fieldComment[] = [
+                "name"    => $name,
+                "type"    => $type,
+                "desc"    => $desc,
+                "default" => $default,
+                "require" => $require,
+            ];
+        }
+        return $fieldComment;
+    }
+
+}

+ 0 - 86
vendor/hg/apidoc/README.md

@@ -1,86 +0,0 @@
-<div align="center">
-    <img width="160"  src="https://docs.apidoc.icu/logo.png">
-</div>
-
-<h1 align="center" style="margin-top: 0;padding-top: 0;">
-  Apidoc
-</h1>
-
-<div align="center">
- 基于PHP的注解生成API文档及Api接口开发工具
-</div>
-
-<div align="center" style="margin-top:10px;margin-bottom:50px;">
-<a href="https://packagist.org/packages/hg/apidoc"><img src="https://img.shields.io/packagist/v/hg/apidoc"></a>
-<a href="https://packagist.org/packages/hg/apidoc"><img src="https://img.shields.io/packagist/dt/hg/apidoc"></a>
-<a href="https://packagist.org/packages/hg/apidoc"><img src="https://img.shields.io/packagist/l/hg/apidoc"></a>
-<a href="https://github.com/HGthecode/apidoc-php"><img src="https://img.shields.io/github/issues/HGthecode/apidoc-php"></a>
-<a href="https://github.com/HGthecode/apidoc-php"><img src="https://img.shields.io/github/forks/HGthecode/apidoc-php"></a>
-
-</div>
-
-
-## 🤷‍♀️ Apidoc是什么?
-
-Apidoc是一个通过解析注解生成Api接口文档的PHP composer扩展,兼容Laravel、ThinkPHP、Hyperf、Webman等框架;
-全面的注解引用、数据表字段引用,简单的注解即可生成Api文档,而Apidoc不仅于接口文档,在线接口调试、Mock调试数据、调试事件处理、Json/TypeScript生成、接口生成器、代码生成器等诸多实用功能,致力于提高Api接口开发效率。
-
-
-## ✨特性
-
-- 开箱即用:无繁杂的配置、安装后按文档编写注释即可自动生成API文档。
-- 轻松编写:支持通用注释引用、业务逻辑层、数据表字段的引用,几句注释即可完成。
-- 在线调试:在线文档可直接调试,并支持全局请求/Mock参数/事件处理,接口调试省时省力。
-- 安全高效:支持访问密码验证、应用/版本独立密码;支持文档缓存。
-- 多应用/多版本:可适应各种单应用、多应用、多版本的项目的Api管理。
-- 分组/Tag:可对控制器/接口进行多级分组或定义Tag。
-- Markdown文档:支持.md文件的文档展示。
-- Json/TypeScript生成:文档自动生成接口的Json及TypeScript。
-- 代码生成器:配置+模板即可快速生成代码及数据表的创建,大大提高工作效率。
-
-
-
-## 📌兼容
-
-以下框架已内置兼容,可开箱即用。其它框架可参考[其它框架安装说明](https://docs.apidoc.icu/guide/install/other.html)进行手动兼容。
-
-|框架|版本|说明|
-|-|-|-|
-|ThinkPHP|5.1、6.x||
-|Laravel|8.x、9.x|其它版本未测试|
-|Hyperf|2.x|其它版本未测试|
-|Webman|2.x|需手动配置兼容|
-
-
-## 📖使用文档
-
-[ApiDoc 文档](https://docs.apidoc.icu/)
-
-
-## 🏆支持我们
-
-如果本项目对您有所帮助,请点个Star支持我们
-
-- [Github](https://github.com/HGthecode/apidoc-php) -> <a href="https://github.com/HGthecode/apidoc-php" target="_blank">
-  <img height="22" src="https://img.shields.io/github/stars/HGthecode/apidoc-php?style=social" class="attachment-full size-full" alt="Star me on GitHub" data-recalc-dims="1" /></a>
-
-- [Gitee](https://gitee.com/hg-code/apidoc-php) -> <a href="https://gitee.com/hg-code/apidoc-php/stargazers"><img src="https://gitee.com/hg-code/apidoc-php/badge/star.svg" alt="star"></a>
-
-
-## 🌐交流群
-
-![QQ群](https://docs.apidoc.icu/qq-qun.png)
-
-
-
-## 💡鸣谢
-
-<a href="https://github.com/doctrine/annotations" target="_blank">doctrine/annotations</a>
-
-
-## 🔗链接
- <a href="https://github.com/HGthecode/apidoc-ui" target="_blank">ApiDoc UI</a>
- 
- <a href="https://github.com/HGthecode/apidoc-demos" target="_blank">ApiDoc Demo</a>
-
-

+ 0 - 24
vendor/hg/apidoc/src/ConfigProvider.php

@@ -1,24 +0,0 @@
-<?php
-declare(strict_types=1);
-/**
- * Hyperf the Config Provider
- */
-namespace hg\apidoc;
-
-class ConfigProvider
-{
-    public function __invoke(): array
-    {
-        return [
-            'dependencies' => [],
-            'publish' => [
-                [
-                    'id' => 'config',
-                    'description' => 'The config of apidoc.',
-                    'source' => __DIR__ . '/config.php',
-                    'destination' => BASE_PATH . '/config/autoload/apidoc.php',
-                ],
-            ],
-        ];
-    }
-}

+ 0 - 321
vendor/hg/apidoc/src/Controller.php

@@ -1,321 +0,0 @@
-<?php
-
-
-namespace hg\apidoc;
-
-use hg\apidoc\Parser;
-use think\facade\Request;
-
-class Controller
-{
-    protected  $config = [
-        'title'=>'APi接口文档',
-        'copyright'=>'Powered By HG',
-        'controllers' => [
-        ],
-        'versions'=>[
-        ],
-        'groups'=>[],
-        'with_cache'=>false,
-        'responses'=>'{
-            "code":"状态码",
-            "message":"操作描述",
-            "data":"业务数据",
-            "timestamp":"响应时间戳"
-        }',
-        'global_auth_key'=>"Authorization",
-        'auth'=>[
-            'with_auth'=>false,
-            'auth_password'=>"123456",
-            'headers_key'=>"apidocToken",
-        ],
-        'definitions'=>"hg\apidoc\Definitions",
-        'filter_method'=>[
-            '_empty'
-        ],
-    ];
-
-    /**
-     * 架构方法 设置参数
-     * @param  array $config 配置参数
-     */
-    public function __construct($config = [])
-    {
-        $this->config = array_merge($this->config, $config);
-    }
-
-    /**
-     * 获取配置
-     * @return array
-     */
-    public function getConfig(){
-        $config = config('apidoc')?config('apidoc'):config('apidoc.');
-        $this->config = array_merge($this->config, $config);
-        if (!empty($this->config['auth'])){
-            $this->config['auth'] = [
-                'with_auth'=>$this->config['auth']['with_auth'],
-                // 验证类型,password=密码验证,只在进入时做密码验证
-                'headers_key'=>$this->config['auth']['headers_key'],
-            ];
-        }
-
-        return json($this->config);
-    }
-
-    /**
-     * 验证身份
-     */
-    public function verifyAuth(){
-        $config = config('apidoc')?config('apidoc'):config('apidoc.');
-        $this->config = array_merge($this->config, $config);
-        $request = Request::instance();
-        $params = $request->param();
-        if ($this->config['auth']['with_auth'] === true){
-            // 密码验证
-            if (md5($this->config['auth']['auth_password']) === $params['password']){
-                $token = md5($params['password'].strtotime(date('Y-m-d',time())));
-                return json(array("token"=>$token));
-            }else{
-                throw new \think\Exception("密码不正确,请重新输入");
-            }
-        }
-        return json($params);
-    }
-
-    public function verifyToken(){
-        $request = Request::instance();
-        if (!empty($this->config['auth'])) {
-            if ($this->config['auth']['with_auth'] === true){
-                $token = $request->header($this->config['auth']['headers_key']);
-
-                if ($token === md5(md5($this->config['auth']['auth_password']).strtotime(date('Y-m-d',time())))){
-                    return true;
-                }else{
-                    throw new \think\exception\HttpException(401, "身份令牌已过期,请重新登录");
-                }
-            }
-        }
-        return true;
-    }
-
-
-
-
-    /**
-     * 获取接口列表
-     * @return array
-     */
-    public function getList()
-    {
-        $config = config('apidoc')?config('apidoc'):config('apidoc.');
-        $this->config = array_merge($this->config, $config);
-        // 验证token身份
-        if ($this->config['auth']['with_auth'] === true){
-            $tokenRes = $this->verifyToken();
-        }
-
-        $request = Request::instance();
-        $params = $request->param();
-        $version = "";
-        if (!empty($params) && !empty($params['version'])){
-            $version = $params['version'];
-        }
-        $cacheFiles= [];
-        $cacheName="";
-        if ($this->config['with_cache']){
-            // 获取缓存数据
-            $cachePath = "../runtime/apidoc/".$version;
-            if (file_exists($cachePath) && $params['reload']=='false' ){
-                $cacheFilePath = "";
-                $filePaths=glob($cachePath.'/*.json');
-                if (count($filePaths)>0){
-                    $cacheFilePath =  $filePaths[count($filePaths)-1];
-                }
-                if (!empty($params) && !empty($params['cacheFileName'])){
-                    // 前端传入的缓存文件名
-                    $cacheFileName = $params['cacheFileName'];
-                    $cacheFilePath = $cachePath."/".$cacheFileName.'.json';
-                }
-
-                if ($cacheFilePath && file_exists($cacheFilePath)){
-                    $fileContent= file_get_contents($cacheFilePath);
-
-                    if (!empty($fileContent)){
-                        $fileJson = json_decode($fileContent);
-                        $list = $fileJson;
-                        $cacheName=str_replace(".json","",basename($cacheFilePath));
-
-                    }else{
-                        $list = $this->getApiList($version);
-                    }
-                }else{
-                    // 不存在缓存文件,生成数据并存缓存
-                    $list = $this->getApiList($version);
-                    // 生成缓存数据
-                    $cacheName=$this->createJsonFile($list,$version);
-                }
-
-            }else{
-                // 不存在缓存文件,生成数据并存缓存
-                $list = $this->getApiList($version);
-                // 生成缓存数据
-                $cacheName=$this->createJsonFile($list,$version);
-            }
-            $filePaths=glob($cachePath.'/*.json');
-            if (count($filePaths)>0){
-                foreach($filePaths as $item)
-                {
-                    $cacheFiles[]=str_replace(".json","",basename($item));
-                }
-            }
-        }else{
-            $list = $this->getApiList($version);
-        }
-
-        if (isset($this->config['groups']) && count($this->config['groups'])>0){
-            array_unshift($this->config['groups'],['title'=>'全部','name'=>0]);
-        }
-
-        $data=array(
-            "title"=>$this->config['title'],
-            "version"=>$version,
-            "copyright"=>$this->config['copyright'],
-            "responses"=>$this->config['responses'],
-            "list"=>$list,
-            "cacheFiles"=>$cacheFiles,
-            "cacheName"=>$cacheName,
-            "groups"=>$this->config['groups']
-        );
-
-        $res=[
-            'code'=>0,
-            'data'=>$data,
-        ];
-        return json($res);
-
-    }
-
-    /**
-     * 获取api接口文档
-     */
-    public function getApiList($version){
-        $config = config('apidoc')?config('apidoc'):config('apidoc.');
-        $this->config = array_merge($this->config, $config);
-        $list=[];
-        $controllers = $this->config['controllers'];
-        $versionPath = "";
-        if (!empty($version)){
-            foreach ($this->config['versions'] as $item){
-                if ($item['title'] == $version && !empty($item['folder'])){
-                    $versionPath = $item['folder']."\\";
-                }
-            }
-        }
-        foreach ($controllers as $k => $class) {
-            $class = "app\\" .$versionPath. $class;
-            if (class_exists($class)) {
-                $reflection = new \ReflectionClass($class);
-                $doc_str = $reflection->getDocComment();
-                $doc = new Parser($this->config);
-                // 解析控制器类的注释
-                $class_doc = $doc->parseClass($doc_str);
-
-                // 获取当前控制器Class的所有方法
-                $method = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
-                $filter_method = array_merge(['__construct'], $this->config['filter_method']);
-                $actions=[];
-                foreach ($method as $j=>$action){
-                    // 过滤不解析的方法
-                    if(!in_array($action->name, $filter_method))
-                    {
-                        // 获取当前方法的注释
-                        $actionDoc = new Parser($this->config);
-                        $actionDocStr = $action->getDocComment();
-                        if($actionDocStr)
-                        {
-                            // 解析当前方法的注释
-                            $action_doc = $actionDoc->parseAction($actionDocStr);
-//                                $action_doc['name'] = $class."::".$action->name;
-                            $action_doc['id'] = $k."-".$j;
-//                                // 解析方法
-                            $actions[] = $action_doc;
-                        }
-                    }
-                }
-                $class_doc['children'] = $actions;
-                $class_doc['id'] = $k."";
-                if (empty($class_doc['title']) && empty($class_doc['controller'])){
-                    $class_doc['title']=$controllers[$k];
-                }
-                $list[]  = $class_doc;
-            }
-        }
-        return $list;
-    }
-
-
-
-    /**
-     * 获取文件夹内的所有文件
-     * @param string $class
-     * @param string $action
-     *
-     * @return array|bool
-     */
-    protected function listDirFiles($app,$isapp=true)
-    {
-        $arr = [];
-        $base = base_path();
-        if($isapp){
-            $dir = $base.$app;
-        }else{
-            $dir = $app;
-        }
-
-        if (is_dir($dir)) {//如果是目录,则进行下一步操作
-            $d = opendir($dir);//打开目录
-            if ($d) {//目录打开正常
-                while (($file = readdir($d)) !== false) {//循环读出目录下的文件,直到读不到为止
-                    if  ($file != '.' && $file != '..') {//排除一个点和两个点
-                        if (is_dir($dir.'/'.$file)) {//如果当前是目录
-                            $arr = array_merge($arr,self::listDirFiles($dir.'/'.$file,false));//进一步获取该目录里的文件
-                        } else {
-                            if(pathinfo($dir.'/'.$file)['extension'] == 'php'){
-                                $arr[] = str_replace([$base,'/','.php'],['','\\',''],$dir.'/'.$file);//进一步获取该目录里的文件
-                            }
-                        }
-                    }
-                }
-            }
-            closedir($d);//关闭句柄
-        }
-        asort($arr);
-        return $arr;
-    }
-
-    /**
-     * 创建接口参数缓存文件
-     * @param $json
-     * @param $version
-     * @return bool|false|string
-     */
-    protected function createJsonFile($json,$version){
-        if (empty($json)){
-            return false;
-        }
-        $fileName =date("Y-m-d H_i_s");
-        $fileJson = $json;
-        $fileContent = json_encode($fileJson);
-        $dir = "../runtime/apidoc/".$version;
-        $path = $dir."/".$fileName.".json";
-        //判断文件夹是否存在
-        if (!file_exists($dir)) {
-            mkdir($dir, 0777, true);
-        }
-        $myfile = fopen($path, "w") or die("Unable to open file!");
-        fwrite($myfile, $fileContent);
-        fclose($myfile);
-        return $fileName;
-    }
-
-}

+ 0 - 40
vendor/hg/apidoc/src/annotation/Query.php

@@ -1,40 +0,0 @@
-<?php
-
-namespace hg\apidoc\annotation;
-
-
-/**
- * Query参数
- * @package hg\apidoc\annotation
- * @Annotation
- * @Target({"METHOD","ANNOTATION"})
- */
-final class Query extends ParamBase
-{
-
-
-    /**
-     * 类型
-     * @Enum({"string", "integer", "number", "boolean", "double", "float","date","time","datetime","timeStamp","int","object","array"})
-     * @var string
-     */
-    public $type;
-
-    /**
-     * 必须
-     * @var bool
-     */
-    public $require;
-    
-    /**
-     * 引入
-     * @var string
-     */
-    public $ref;
-
-    /**
-     * mock
-     * @var string
-     */
-    public $mock;
-}

+ 0 - 20
vendor/hg/apidoc/src/annotation/ResponseErrorMd.php

@@ -1,20 +0,0 @@
-<?php
-
-namespace hg\apidoc\annotation;
-
-use Doctrine\Common\Annotations\Annotation;
-
-/**
- * 异常响应体的Markdown内容
- * @package hg\apidoc\annotation
- * @Annotation
- * @Target({"METHOD"})
- */
-class ResponseErrorMd extends Annotation
-{
-    /**
-     * 引入md内容
-     * @var string
-     */
-    public $ref;
-}

+ 0 - 33
vendor/hg/apidoc/src/annotation/ResponseSuccess.php

@@ -1,33 +0,0 @@
-<?php
-
-namespace hg\apidoc\annotation;
-
-
-/**
- * 成功响应体
- * @package hg\apidoc\annotation
- * @Annotation
- * @Target({"METHOD","ANNOTATION"})
- */
-final class ResponseSuccess extends ParamBase
-{
-
-    /**
-     * 必须
-     * @var bool
-     */
-    public $require;
-
-    /**
-     * 引入
-     * @var string
-     */
-    public $ref;
-
-    /**
-     * 数据挂载节点
-     * @var boolean
-     */
-    public $main;
-
-}

+ 0 - 45
vendor/hg/apidoc/src/annotation/RouteParam.php

@@ -1,45 +0,0 @@
-<?php
-
-namespace hg\apidoc\annotation;
-
-
-/**
- * 路由参数
- * @package hg\apidoc\annotation
- * @Annotation
- * @Target({"METHOD"})
- */
-class RouteParam extends ParamBase
-{
-    /**
-     * 必须
-     * @var bool
-     */
-    public $require = false;
-
-    /**
-     * 类型
-     * @var string
-     */
-    public $type;
-
-    /**
-     * 引入
-     * @var string
-     */
-    public $ref;
-
-
-    /**
-     * 描述
-     * @var string
-     */
-    public $desc;
-
-    /**
-     * mock
-     * @var string
-     */
-    public $mock;
-
-}

+ 0 - 92
vendor/hg/apidoc/src/config.php

@@ -1,92 +0,0 @@
-<?php
-return [
-    // (选配)文档标题,显示在左上角与首页
-    'title'              => 'Apidoc',
-    // (选配)文档描述,显示在首页
-    'desc'               => '',
-    // (必须)设置文档的应用/版本
-    'apps'           => [
-        [
-            // (必须)标题
-            'title'=>'Api接口',
-            // (必须)控制器目录地址
-            'path'=>'app\controller',
-            // (必须)唯一的key
-            'key'=>'api',
-        ]
-    ],
-    // (必须)指定通用注释定义的文件地址
-    'definitions'        => "app\common\controller\Definitions",
-    // (必须)自动生成url规则,当接口不添加@Apidoc\Url ("xxx")注解时,使用以下规则自动生成
-    'auto_url' => [
-        // 字母规则,lcfirst=首字母小写;ucfirst=首字母大写;
-        'letter_rule' => "lcfirst",
-        // url前缀
-        'prefix'=>"",
-    ],
-    // (必须)缓存配置
-    'cache'              => [
-        // 是否开启缓存
-        'enable' => false,
-    ],
-    // (必须)权限认证配置
-    'auth'               => [
-        // 是否启用密码验证
-        'enable'     => false,
-        // 全局访问密码
-        'password'   => "123456",
-        // 密码加密盐
-        'secret_key' => "apidoc#hg_code",
-        // 授权访问后的有效期
-        'expire' => 24*60*60
-    ],
-    // 全局参数
-    'params'=>[
-        // (选配)全局的请求Header
-        'header'=>[
-            // name=字段名,type=字段类型,require=是否必须,default=默认值,desc=字段描述
-            ['name'=>'Authorization','type'=>'string','require'=>true,'desc'=>'身份令牌Token'],
-        ],
-        // (选配)全局的请求Query
-        'query'=>[
-            // 同上 header
-        ],
-        // (选配)全局的请求Body
-        'body'=>[
-            // 同上 header
-        ],
-    ],
-    // 全局响应体
-    'responses'=>[
-        // 成功响应体
-        'success'=>[
-            ['name'=>'code','desc'=>'业务代码','type'=>'int','require'=>1],
-            ['name'=>'message','desc'=>'业务信息','type'=>'string','require'=>1],
-            //参数同上 headers;main=true来指定接口Returned参数挂载节点
-            ['name'=>'data','desc'=>'业务数据','main'=>true,'type'=>'object','require'=>1],
-        ],
-        // 异常响应体
-        'error'=>[
-            ['name'=>'code','desc'=>'业务代码','type'=>'int','require'=>1,'md'=>'/docs/HttpError.md'],
-            ['name'=>'message','desc'=>'业务信息','type'=>'string','require'=>1],
-        ]
-    ],
-    //(选配)默认作者
-    'default_author'=>'',
-    //(选配)默认请求类型
-    'default_method'=>'GET',
-    //(选配)允许跨域访问
-    'allowCrossDomain'=>false,
-    /**
-     * (选配)解析时忽略带@注解的关键词,当注解中存在带@字符并且非Apidoc注解,如 @key test,此时Apidoc页面报类似以下错误时:
-     * [Semantical Error] The annotation "@key" in method xxx() was never imported. Did you maybe forget to add a "use" statement for this annotation?
-     */
-    'ignored_annitation'=>[],
-
-    // (选配)数据库配置
-    'database'=>[],
-    // (选配)Markdown文档
-    'docs'              => [],
-    // (选配)代码生成器配置 注意:是一个二维数组
-    'generator' =>[]
-];

+ 0 - 62
vendor/hg/apidoc/src/exception/ErrorException.php

@@ -1,62 +0,0 @@
-<?php
-
-
-namespace hg\apidoc\exception;
-
-
-use hg\apidoc\utils\ConfigProvider;
-use hg\apidoc\utils\Helper;
-
-class ErrorException extends HttpException
-{
-
-    protected $exceptions = [
-        'apidoc close'     => ['status'=>404,'code' => 4004, 'msg' => '文档已关闭'],
-        'password error'     => ['status'=>402,'code' => 4002, 'msg' => '密码不正确,请重新输入'],
-        'password not found' => ['status'=>402,'code' => 4002, 'msg' => '密码不可为空'],
-        'token error'        => ['status'=>401,'code' => 4001, 'msg' => '不合法的Token'],
-        'token not found'    => ['status'=>401,'code' => 4001, 'msg' => '不存在Token'],
-        'appkey not found'     => ['status'=>412,'code' => 4005, 'msg' => '缺少必要参数appKey'],
-        'mdPath not found'     => ['status'=>412,'code' => 4006, 'msg' => '缺少必要参数path'],
-        'appKey error'         => ['status'=>412,'code' => 4007, 'msg' => '不存在 key为${appKey}的apps配置'],
-        'template not found'   => ['status'=>412,'code' => 4008, 'msg' => '${template}模板不存在'],
-        'path not found'       => ['status'=>412,'code' => 4009, 'msg' => '${path}目录不存在'],
-        'classname error'      => ['status'=>412,'code' => 4010, 'msg' => '${classname}文件名不合法'],
-        'apiKey not found'     => ['status'=>412,'code' => 4011, 'msg' => '缺少必要参数apiKey'],
-        'no config apps'       => ['status'=>412,'code' => 5000, 'msg' => 'apps配置不可为空'],
-        'unknown error'       => ['status'=>501,'code' => 5000, 'msg' => '未知异常'],
-        'no debug'             => ['status'=>412,'code' => 5001, 'msg' => '请在debug模式下,使用该功能'],
-        'no config crud'       => ['status'=>412,'code' => 5002, 'msg' => 'crud未配置'],
-        'datatable crud error' => ['status'=>412,'code' => 5003, 'msg' => '数据表创建失败,请检查配置'],
-        'file already exists' => ['status'=>412,'code' => 5004, 'msg' => '${filepath}文件已存在'],
-        'file not exists' => ['status'=>412,'code' => 5005, 'msg' => '${filepath}文件不存在'],
-        'datatable already exists' => ['status'=>412,'code' => 5004, 'msg' => '数据表${table}已存在'],
-        'datatable not exists' => ['status'=>412,'code' => 5004, 'msg' => '数据表${table}不存在'],
-        'ref file not exists' => ['status'=>412,'code' => 5005, 'msg' => 'ref引入 ${path} 文件不存在'],
-        'ref method not exists' => ['status'=>412,'code' => 5005, 'msg' => 'ref引入${path} 中 ${method} 方法不存在'],
-        'datatable create error' => ['status'=>412,'code' => 5006, 'msg' => '数据表[${table}]创建失败,error:${message},sql:${sql}'],
-    ];
-
-    public function __construct(string $exceptionCode, array $data = [])
-    {
-        $config = ConfigProvider::get();
-        $exception = $this->getException($exceptionCode);
-        if ($exception){
-            $msg       = Helper::replaceTemplate($exception['msg'], $data);
-        }else{
-            $exception = $this->exceptions['unknown error'];
-            $msg = $exceptionCode;
-        }
-        parent::__construct($exception['status'], $msg, null, [], $exception['code']);
-
-    }
-
-    public function getException($exceptionCode)
-    {
-        if (isset($this->exceptions[$exceptionCode])) {
-            return $this->exceptions[$exceptionCode];
-        }
-        return null;
-    }
-
-}

+ 0 - 33
vendor/hg/apidoc/src/exception/HttpException.php

@@ -1,33 +0,0 @@
-<?php
-declare (strict_types = 1);
-
-namespace hg\apidoc\exception;
-
-use Exception;
-
-/**
- * HTTP异常
- */
-class HttpException extends \RuntimeException
-{
-    private $statusCode;
-    private $headers;
-
-    public function __construct(int $statusCode, string $message = '', Exception $previous = null, array $headers = [], $code = 0)
-    {
-        $this->statusCode = $statusCode;
-        $this->headers    = $headers;
-
-        parent::__construct($message, $code, $previous);
-    }
-
-    public function getStatusCode()
-    {
-        return $this->statusCode;
-    }
-
-    public function getHeaders()
-    {
-        return $this->headers;
-    }
-}

+ 0 - 17
vendor/hg/apidoc/src/middleware/LaravelMiddleware.php

@@ -1,17 +0,0 @@
-<?php
-
-namespace hg\apidoc\middleware;
-
-use hg\apidoc\utils\ConfigProvider;
-
-class LaravelMiddleware
-{
-    public function handle($request, \Closure $next)
-    {
-        $params = $request->all();
-        $config =  ConfigProvider::get();
-        $config['request_params'] = $params;
-        ConfigProvider::set($config);
-        return $next($request);
-    }
-}

+ 0 - 17
vendor/hg/apidoc/src/middleware/ThinkPHPMiddleware.php

@@ -1,17 +0,0 @@
-<?php
-
-namespace hg\apidoc\middleware;
-
-use hg\apidoc\utils\ConfigProvider;
-
-class ThinkPHPMiddleware
-{
-    public function handle($request, \Closure $next)
-    {
-        $params = $request->param();
-        $config =  ConfigProvider::get();
-        $config['request_params'] = $params;
-        ConfigProvider::set($config);
-        return $next($request);
-    }
-}

+ 0 - 35
vendor/hg/apidoc/src/parses/ParseAnnotation.php

@@ -1,35 +0,0 @@
-<?php
-declare(strict_types = 1);
-
-namespace hg\apidoc\parses;
-
-class ParseAnnotation
-{
-
-    /**
-     * 解析非@注解的文本注释
-     * @param $refMethod
-     * @return array|false
-     */
-    public static function parseTextAnnotation($refMethod): array
-    {
-        $annotation = $refMethod->getDocComment();
-        if (empty($annotation)) {
-            return [];
-        }
-        if (preg_match('#^/\*\*(.*)\*/#s', $annotation, $comment) === false)
-            return [];
-        $comment = trim($comment [1]);
-        if (preg_match_all('#^\s*\*(.*)#m', $comment, $lines) === false)
-            return [];
-        $data = [];
-        foreach ($lines[1] as $line) {
-            $line = trim($line);
-            if (!empty ($line) && strpos($line, '@') !== 0) {
-                $data[] = $line;
-            }
-        }
-        return $data;
-    }
-
-}

+ 0 - 852
vendor/hg/apidoc/src/parses/ParseApiDetail.php

@@ -1,852 +0,0 @@
-<?php
-declare(strict_types = 1);
-
-namespace hg\apidoc\parses;
-
-use ReflectionClass;
-use Doctrine\Common\Annotations\AnnotationReader;
-use hg\apidoc\exception\ErrorException;
-use hg\apidoc\utils\DirAndFile;
-use hg\apidoc\utils\Helper;
-use hg\apidoc\utils\Lang;
-use hg\apidoc\annotation\Group;
-use hg\apidoc\annotation\Sort;
-use hg\apidoc\annotation\Param;
-use hg\apidoc\annotation\Query;
-use hg\apidoc\annotation\ResponseSuccess;
-use hg\apidoc\annotation\ResponseSuccessMd;
-use hg\apidoc\annotation\ResponseError;
-use hg\apidoc\annotation\ResponseErrorMd;
-use hg\apidoc\annotation\Title;
-use hg\apidoc\annotation\Desc;
-use hg\apidoc\annotation\Md;
-use hg\apidoc\annotation\RouteParam;
-use hg\apidoc\annotation\Author;
-use hg\apidoc\annotation\Tag;
-use hg\apidoc\annotation\Header;
-use hg\apidoc\annotation\Returned;
-use hg\apidoc\annotation\ParamType;
-use hg\apidoc\annotation\Url;
-use hg\apidoc\annotation\Method;
-use hg\apidoc\annotation\Before;
-use hg\apidoc\annotation\After;
-use hg\apidoc\annotation\ContentType;
-
-class ParseApiDetail
-{
-
-    protected $config = [];
-
-    protected $reader;
-
-
-    protected $currentApp = [];
-
-    protected $basePath = "";
-
-    protected $parseModel;
-
-    protected $appKey;
-
-    public function __construct($config)
-    {
-        $this->reader = new AnnotationReader();
-        if (!empty($config['ignored_annitation'])){
-            foreach ($config['ignored_annitation'] as $item) {
-                AnnotationReader::addGlobalIgnoredName($item);
-            }
-        }
-        $this->config = $config;
-        $this->basePath = APIDOC_ROOT_PATH;
-        $this->parseModel = new ParseModel($this->reader,$config);
-
-    }
-
-    /**
-     * 生成api接口数据
-     * @param string $classPath
-     * @param string $methodName
-     * @return array
-     */
-    public function renderApiDetail(string $appKey,string $classPath,string $methodName)
-    {
-
-        $this->appKey = $appKey;
-        $currentAppConfig = Helper::getCurrentAppConfig($appKey);
-        $this->currentApp  = $currentAppConfig['appConfig'];
-        $json =DirAndFile::formatPath( $this->basePath . $classPath,"/");
-
-        try {
-            $refClass  = new ReflectionClass($classPath);
-            $classTextAnnotations =ParseAnnotation::parseTextAnnotation($refClass);
-
-            $refMethod= $refClass->getMethod($methodName);
-            $methodItem = $this->parseApiMethod($refClass,$refMethod);
-            if ($methodItem===false){
-                return "no";
-            }
-            if (in_array("NotDebug", $classTextAnnotations)) {
-                $methodItem['notDebug'] = true;
-            }
-            $methodItem['menuKey'] =Helper::createApiKey($refClass->name,$refMethod->name);
-            return $methodItem;
-        } catch (\ReflectionException $e) {
-            throw new ErrorException($e->getMessage());
-        }
-    }
-
-    protected function mergeGlobalOrAppParams($params,$paramType='param'){
-        $config  = $this->config;
-        $globalParams = [];
-        if (!empty($this->currentApp['params']) && !empty($this->currentApp['params'][$paramType])){
-            // 不合并global的处理方式
-            $globalParams = $this->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];
-        }
-        $mergeParams = [];
-        foreach ($globalParams as $item){
-            if (!empty($item['desc'])){
-                $item['desc'] = Lang::getLang($item['desc']);
-            }
-            if (!empty($item['md'])){
-                $item['md'] = ParseMarkdown::getContent($this->appKey,$item['md']);
-            }
-            $mergeParams[] = $item;
-        }
-        if (!empty($params) && count($params)) {
-            return Helper::arrayMergeAndUnique("name", $mergeParams, $params);
-        }
-        return $mergeParams;
-    }
-
-    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 $apiInfo
-     * @param $textAnnotations
-     * @return array|mixed
-     */
-    protected function handleApiResponseSuccess($apiInfo,$textAnnotations){
-        $returned = $apiInfo['returned'];
-        if (
-            in_array("NotResponses", $textAnnotations) ||
-            in_array("NotResponseSuccess", $textAnnotations)
-        ) {
-            return $returned;
-        }
-        $config  = $this->config;
-        $mergeParams = [];
-        $paramType='success';
-        if (!empty($apiInfo['responseSuccess']) && count($apiInfo['responseSuccess'])){
-            $mergeParams = $apiInfo['responseSuccess'];
-        }else if (!empty($this->currentApp['responses']) && !empty($this->currentApp['responses'][$paramType])){
-            $mergeParams = $this->currentApp['params'][$paramType];
-        }else if(!empty($config['responses']) && !empty($config['responses'][$paramType])){
-            $mergeParams = $config['responses'][$paramType];
-        }
-        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 $apiInfo
-     * @param $textAnnotations
-     * @return array|mixed|void
-     */
-    protected function handleApiResponseError($apiInfo,$textAnnotations){
-        $config  = $this->config;
-        $responseErrors = [];
-        if (
-            in_array("NotResponses", $textAnnotations) ||
-            in_array("NotResponseError", $textAnnotations)
-        ){
-            $responseErrors = [];
-        }else if (!empty($apiInfo['responseError']) && count($apiInfo['responseError'])){
-            $responseErrors = $apiInfo['responseError'];
-        }else if (
-            !empty($this->currentApp['responses']) &&
-            !empty($this->currentApp['responses']['error']) &&
-            count($this->currentApp['responses']['error'])
-        ){
-            $responseErrors = $this->currentApp['responses']['error'];
-        }else if (
-            !empty($config['responses']) &&
-            !empty($config['responses']['error']) &&
-            count($config['responses']['error'])
-        ){
-            $responseErrors = $config['responses']['error'];
-        }
-
-        $data = [];
-        foreach ($responseErrors as $item) {
-            $item['desc'] = Lang::getLang($item['desc']);
-            if (!empty($item['md'])){
-                $item['md'] = ParseMarkdown::getContent($this->appKey,$item['md']);
-            }
-            $data[]=$item;
-        }
-        return $data;
-    }
-
-
-    protected function parseApiMethod($refClass,$refMethod){
-        $config  = $this->config;
-        if (empty($refMethod->name)) {
-            return false;
-        }
-
-        $textAnnotations = ParseAnnotation::parseTextAnnotation($refMethod);
-        // 标注不解析的方法
-        if (in_array("NotParse", $textAnnotations)) {
-            return false;
-        }
-        $methodInfo = $this->parseAnnotation($refMethod, true,"controller");
-        if (empty($methodInfo)){
-            return false;
-        }
-        $methodInfo = $this->handleApiBaseInfo($methodInfo,$refClass,$refMethod,$textAnnotations);
-
-        // 是否开启debug
-        if (
-            in_array("NotDebug", $textAnnotations) ||
-            (isset($config['notDebug']) && $config['notDebug']===true) ||
-            (isset($this->currentApp['notDebug']) && $this->currentApp['notDebug']===true)
-        ) {
-            $methodInfo['notDebug'] = true;
-        }
-
-
-        // 合并全局请求头参数
-        if (
-            (
-                (!empty($config['params']) && !empty($config['params']['header']))  ||
-                (!empty($this->currentApp['params']) && !empty($this->currentApp['params']['header']))
-            ) &&
-            !in_array("NotHeaders", $textAnnotations))
-        {
-            $headers = !empty($methodInfo['header'])?$methodInfo['header']:[];
-            $methodInfo['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($methodInfo['query'])?$methodInfo['query']:[];
-            $methodInfo['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($methodInfo['param'])?$methodInfo['param']:[];
-            $methodInfo['param'] = $this->mergeGlobalOrAppParams($params,'body');
-        }
-
-        //添加成功响应体
-        $methodInfo['responseSuccess'] = $this->handleApiResponseSuccess($methodInfo,$textAnnotations);
-        //添加异常响应体
-        $methodInfo['responseError'] = $this->handleApiResponseError($methodInfo,$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($methodInfo['after'])?$methodInfo['after']:[];
-            $methodInfo['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($methodInfo['before'])?$methodInfo['before']:[];
-            $methodInfo['before'] = $this->mergeGlobalOrAppEvents($debugBeforeEvents,'before');
-        }
-
-        return $methodInfo;
-    }
-
-
-    public function handleApiBaseInfo($methodInfo,$refClass,$refMethod,$textAnnotations){
-        $config  = $this->config;
-        // 无标题,且有文本注释
-        if (empty($methodInfo['title']) && !empty($textAnnotations) && count($textAnnotations) > 0) {
-            $methodInfo['title'] = Lang::getLang($textAnnotations[0]);
-        }
-
-        // 默认method
-        if (empty($methodInfo['method'])) {
-            $methodInfo['method'] = !empty($config['default_method']) ? strtoupper($config['default_method']) : 'GET';
-        }
-
-        // 默认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($refClass->name,$refMethod,$config);
-        } else if (!empty($methodInfo['url']) && substr($methodInfo['url'], 0, 1) != "/") {
-            $methodInfo['url'] = "/" . $methodInfo['url'];
-        }
-        $methodInfo['name']     = $refMethod->name;
-        $methodInfo['menuKey'] = Helper::createApiKey($refClass->name,$refMethod->name);
-        return $methodInfo;
-    }
-
-    public static function handleTags($tagStr){
-        if (!empty($tagStr)) {
-            $tagStr = Lang::getLang($tagStr);
-            $tagList = [];
-            if (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($classPath,$method,$config): string
-    {
-
-        $pathArr = explode("\\", $classPath);
-        $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 . '/' . $method->name;
-        if (!empty($config['auto_url']) && !empty($config['auto_url']['custom']) && is_callable($config['auto_url']['custom'])){
-            return $config['auto_url']['custom']($classPath,$method->name,$url);
-        }
-        return $url;
-    }
-
-    /**
-     * ref引用
-     * @param $refPath
-     * @param bool $enableRefService
-     * @return false|string[]
-     */
-    protected function renderRef(string $refPath, bool $enableRefService = true): array
-    {
-        $res = ['type' => 'model'];
-        $config      = $this->config;
-        // 通用定义引入
-        if (strpos($refPath, '\\') === false) {
-            $refPath     = $config['definitions'] . '\\' . $refPath;
-            $data        = $this->renderService($refPath);
-            $res['type'] = "service";
-            $res['data'] = $data;
-            return $res;
-        }
-        // 模型引入
-        $modelData = $this->parseModel->renderModel($refPath);
-        if ($modelData !== false) {
-            $res['data'] = $modelData;
-            return $res;
-        }
-        if ($enableRefService === false) {
-            return false;
-        }
-        $data        = $this->renderService($refPath);
-        $res['type'] = "service";
-        $res['data'] = $data;
-        return $res;
-    }
-
-    /**
-     * 解析注释引用
-     * @param $refPath
-     * @return array
-     * @throws \ReflectionException
-     */
-    protected function renderService(string $refPath)
-    {
-        $pathArr    = explode("\\", $refPath);
-        $methodName = $pathArr[count($pathArr) - 1];
-        unset($pathArr[count($pathArr) - 1]);
-        $classPath    = implode("\\", $pathArr);
-        if (!class_exists($classPath)){
-            throw new ErrorException("ref file not exists",  [
-                'path' => $classPath
-            ]);
-        }
-        try {
-            $classReflect = new \ReflectionClass($classPath);
-            $methodName   = trim($methodName);
-            $refMethod    = $classReflect->getMethod($methodName);
-            $res          = $this->parseAnnotation($refMethod, true);
-            return $res;
-        } catch (\ReflectionException $e) {
-            throw new ErrorException('Class '.$classPath.' '.$e->getMessage());
-        }
-
-    }
-
-    /**
-     * 处理Param/Returned的字段名name、params子级参数
-     * @param $values
-     * @return array
-     */
-    protected function handleParamValue($values, string $field = 'param'): array
-    {
-        $name   = "";
-        $params = [];
-        if (!empty($values) && is_array($values) && count($values) > 0) {
-            foreach ($values as $item) {
-                if (is_string($item)) {
-                    $name = $item;
-                } else if (is_object($item)) {
-                    if (!empty($item->ref)) {
-                        $refRes = $this->renderRef($item->ref, true);
-                        $params = $this->handleRefData($params, $refRes, $item, $field);
-                    } else {
-                        $param         = [
-                            "name"    => "",
-                            "type"    => $item->type,
-                            "desc"    => Lang::getLang($item->desc),
-                            "default" => $item->default,
-                            "require" => $item->require,
-                            "childrenType"=> $item->childrenType
-                        ];
-                        if (!empty($item->mock)){
-                            $param['mock']=$item->mock;
-                        }
-                        $children      = $this->handleParamValue($item->value);
-                        $param['name'] = $children['name'];
-                        if (count($children['params']) > 0) {
-                            $param['children'] = $children['params'];
-                        }
-                        $params[] = $param;
-                    }
-                }
-            }
-        } else if(!empty($values) && is_object($values)) {
-            $item = $values;
-            if (!empty($item->ref)) {
-                $refRes = $this->renderRef($item->ref, true);
-                $params = $this->handleRefData($params, $refRes, $item, $field);
-            } else {
-                $param         = [
-                    "name"    => "",
-                    "type"    => $item->type,
-                    "desc"    => Lang::getLang($item->desc),
-                    "default" => $item->default,
-                    "require" => $item->require,
-                    "childrenType"=> $item->childrenType
-                ];
-                if (!empty($item->mock)){
-                    $param['mock']=$item->mock;
-                }
-                $children      = $this->handleParamValue($item->value);
-                $param['name'] = $children['name'];
-                if (count($children['params']) > 0) {
-                    $param['children'] = $children['params'];
-                }
-                $params[] = $param;
-            }
-        } else {
-            $name = $values;
-        }
-        return ['name' => $name, 'params' => $params];
-    }
-
-    /**
-     * 解析注释
-     * @param $refMethod
-     * @param bool $enableRefService 是否终止service的引入
-     * @param string $source 注解来源
-     * @return array
-     */
-    protected function parseAnnotation($refMethod, bool $enableRefService = true,$source=""): array
-    {
-
-        $data = [];
-        if ($annotations = $this->reader->getMethodAnnotations($refMethod)) {
-            $headers = [];
-            $querys = [];
-            $params  = [];
-            $returns = [];
-            $before = [];
-            $after = [];
-            $responseErrors=[];
-            $routeParams=[];
-            $responseSuccess=[];
-
-            foreach ($annotations as $annotation) {
-                switch (true) {
-                    case $annotation instanceof ResponseSuccess:
-                        $responseSuccess = $this->handleParamAndReturned($responseSuccess,$annotation,'responseSuccess',$enableRefService);
-                        break;
-
-                    case $annotation instanceof Query:
-                        $querys = $this->handleParamAndReturned($querys,$annotation,'query',$enableRefService);
-                        break;
-                    case $annotation instanceof Param:
-                        $params = $this->handleParamAndReturned($params,$annotation,'param',$enableRefService);
-                        break;
-                    case $annotation instanceof Returned:
-                        $returns = $this->handleParamAndReturned($returns,$annotation,'returned',$enableRefService,$source);
-                        break;
-                    case $annotation instanceof ResponseError:
-                        $responseErrors = $this->handleParamAndReturned($responseErrors,$annotation,'responseError',$enableRefService,$source);
-                        break;
-                    case $annotation instanceof RouteParam:
-                        $routeParams = $this->handleParamAndReturned($routeParams,$annotation,'routeParam',$enableRefService,$source);
-                        break;
-                    case $annotation instanceof Header:
-                        if (!empty($annotation->ref)) {
-                            $refRes  = $this->renderRef($annotation->ref, $enableRefService);
-                            $headers = $this->handleRefData($headers, $refRes, $annotation, 'header');
-                        } else {
-                            $param     = [
-                                "name"    => $annotation->value,
-                                "desc"    => Lang::getLang($annotation->desc),
-                                "require" => $annotation->require,
-                                "type"    => $annotation->type,
-                                "default" => $annotation->default,
-                            ];
-                            $headers[] = $param;
-                        }
-                        break;
-
-                    case $annotation instanceof Author:
-                        $data['author'] = $annotation->value;
-                        break;
-
-                    case $annotation instanceof Title:
-                        $data['title'] = Lang::getLang($annotation->value);
-                        break;
-                    case $annotation instanceof Desc:
-                        $data['desc'] = Lang::getLang($annotation->value);
-//                        if (!empty($annotation->mdRef)){
-//                            $data['md'] = $annotation->mdRef;
-//                        }
-                        break;
-                    case $annotation instanceof Md:
-                        $data['md'] = $annotation->value;
-                        if (!empty($annotation->ref)){
-                            $data['md'] = ParseMarkdown::getContent("",$annotation->ref);
-                        }
-                        break;
-                    case $annotation instanceof ResponseSuccessMd:
-                        $data['responseSuccessMd'] = $annotation->value;
-                        if (!empty($annotation->ref)){
-                            $data['responseSuccessMd'] = ParseMarkdown::getContent("",$annotation->ref);
-                        }
-                        break;
-                    case $annotation instanceof ResponseErrorMd:
-                        $data['responseErrorMd'] = $annotation->value;
-                        if (!empty($annotation->ref)){
-                            $data['responseErrorMd'] = ParseMarkdown::getContent("",$annotation->ref);
-                        }
-                        break;
-                    case $annotation instanceof ParamType:
-                        $data['paramType'] = $annotation->value;
-                        break;
-                    case $annotation instanceof Url:
-                        $data['url'] = $annotation->value;
-                        break;
-                    case $annotation instanceof Method:
-                        if ($annotation->value && strpos($annotation->value, ',') !== false){
-                            $data['method'] =  explode(",", $annotation->value);
-                        }else{
-                            $data['method'] = strtoupper($annotation->value);
-                        }
-                        break;
-                    case $annotation instanceof Tag:
-                        $data['tag'] = $annotation->value;
-                        break;
-                    case $annotation instanceof ContentType:
-                    $data['contentType'] = $annotation->value;
-                    break;
-                    case $annotation instanceof Before:
-                        $beforeAnnotation = $this->handleEventAnnotation($annotation,'before');
-                        $before =  array_merge($before,$beforeAnnotation);
-                        break;
-                    case $annotation instanceof After:
-                        $afterAnnotation = $this->handleEventAnnotation($annotation,'after');
-                        $after =array_merge($after,$afterAnnotation);
-                        break;
-                }
-            }
-            if ($headers && count($headers) > 0) {
-                $data['header'] = $headers;
-            }
-            $data['query'] = $querys;
-            $data['param']  = $params;
-            $data['returned'] = $returns;
-            $data['responseSuccess'] = $responseSuccess;
-            $data['responseError'] = $responseErrors;
-            $data['routeParam'] = $routeParams;
-            $data['before'] = $before;
-            $data['after'] = $after;
-        }
-        return $data;
-    }
-
-    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{
-            return [$annotation];
-        }
-    }
-
-
-    /**
-     * 处理请求参数与返回参数
-     * @param $params
-     * @param $annotation
-     * @param string $type
-     * @param false $enableRefService
-     * @param string $source 注解来源
-     * @return array
-     */
-    protected function handleParamAndReturned($params,$annotation,$type="param",$enableRefService=false,$source=""){
-        if (!empty($annotation->ref)) {
-            $refRes = $this->renderRef($annotation->ref, $enableRefService);
-            $params = $this->handleRefData($params, $refRes, $annotation, $type,$source);
-        } else {
-
-            $param =  Helper::objectToArray($annotation);
-            $param["source"] = $source;
-            $param["desc"] = Lang::getLang($param['desc']);
-
-            $children      = $this->handleParamValue($annotation->value, $type);
-            $param['name'] = $children['name'];
-            if (count($children['params']) > 0) {
-                $param['children'] = $children['params'];
-            }
-            if (!empty($param['mdRef'])){
-                $param['md'] = ParseMarkdown::getContent("",$param['mdRef']);
-            }
-            if ($annotation->type === 'tree' ) {
-                // 类型为tree的
-                $param['children'][] = [
-                    'children' => $children['params'],
-                    'name'   => !empty($annotation->childrenField)?$annotation->childrenField:"children",
-                    'type'   => 'array<object>',
-                    'desc'   => Lang::getLang($annotation->childrenDesc),
-                ];
-            }
-            // 合并同级已有的字段
-            $params = Helper::arrayMergeAndUnique("name", $params, [$param]);
-        }
-            return $params;
-    }
-
-
-
-
-    /**
-     * 处理param、returned 参数
-     * @param $params
-     * @param $refRes
-     * @param $annotation
-     * @param string|null $source 注解来源
-     * @return array
-     */
-    protected function handleRefData($params, $refRes, $annotation, string $field,$source=""): array
-    {
-        if ($refRes['type'] === "model" && count($refRes['data']) > 0) {
-            // 模型引入
-            $data = $refRes['data'];
-        } else if ($refRes['type'] === "service" && !empty($refRes['data']) && !empty($refRes['data'][$field])) {
-            // service引入
-            $data = $refRes['data'][$field];
-        } else {
-            return $params;
-        }
-        // 过滤field
-        if (!empty($annotation->field)) {
-            $data = static::filterParamsField($data, $annotation->field, 'field');
-        }
-        // 过滤withoutField
-        if (!empty($annotation->withoutField)) {
-            $data = static::filterParamsField($data, $annotation->withoutField, 'withoutField');
-        }
-
-        if (!empty($annotation->value)) {
-            $item =  Helper::objectToArray($annotation);
-            $item['children'] = $data;
-            $item['source'] = $source;
-            $param["desc"] = Lang::getLang($item['desc']);
-
-            $children      = $this->handleParamValue($annotation->value, 'param');
-            $item['name'] = $children['name'];
-            if (count($children['params']) > 0) {
-                $item['children'] = Helper::arrayMergeAndUnique("name",$data,$children['params']);
-            }
-            if ($annotation->type === 'tree' ) {
-                // 类型为tree的
-                $item['children'][] = [
-                    'children' => $item['children'],
-                    'name'   =>!empty($annotation->childrenField) ?$annotation->childrenField:'children',
-                    'type'   => 'array',
-                    'desc'   => Lang::getLang($annotation->childrenDesc),
-                ];
-            }
-            if (!empty($item['name']) ){
-                $params[] = $item;
-            }else{
-                if (count($children['params']) > 0) {
-                    $data = Helper::arrayMergeAndUnique("name",$data,$children['params']);
-                }
-                $params = Helper::arrayMergeAndUnique("name",$params,$data);
-            }
-        } else {
-            $params = Helper::arrayMergeAndUnique("name",$params,$data);
-        }
-        return $params;
-    }
-
-    /**
-     * Params、Returned过滤指定字段、或只取指定字段
-     * @param $data 参数
-     * @param $fields 指定字段
-     * @param string $type 处理类型
-     * @return array
-     */
-    public static function filterParamsField(array $data, $fields, string $type = "field"): array
-    {
-        if ($fields && strpos($fields, ',') !== false){
-            $fieldArr = explode(',', $fields);
-        }else{
-            $fieldArr = [$fields];
-        }
-        $dataList = [];
-        foreach ($data as $item) {
-            if (!empty($item['name']) && in_array($item['name'], $fieldArr) && $type === 'field') {
-                $dataList[] = $item;
-            } else if (!(!empty($item['name']) && in_array($item['name'], $fieldArr)) && $type == "withoutField") {
-                $dataList[] = $item;
-            }
-        }
-        return $dataList;
-    }
-
-
-
-}

+ 0 - 353
vendor/hg/apidoc/src/parses/ParseApiMenus.php

@@ -1,353 +0,0 @@
-<?php
-declare(strict_types = 1);
-
-namespace hg\apidoc\parses;
-
-use Doctrine\Common\Annotations\AnnotationReader;
-use hg\apidoc\utils\DirAndFile;
-use hg\apidoc\utils\Helper;
-use hg\apidoc\utils\Lang;
-use ReflectionClass;
-use Symfony\Component\ClassLoader\ClassMapGenerator;
-use hg\apidoc\annotation\Group;
-use hg\apidoc\annotation\Sort;
-use hg\apidoc\annotation\Title;
-use hg\apidoc\annotation\Desc;
-use hg\apidoc\annotation\Author;
-use hg\apidoc\annotation\Tag;
-use hg\apidoc\annotation\Header;
-use hg\apidoc\annotation\ParamType;
-use hg\apidoc\annotation\Url;
-use hg\apidoc\annotation\Method;
-use hg\apidoc\annotation\ContentType;
-
-class ParseApiMenus
-{
-
-    protected $config = [];
-
-    protected $reader;
-
-    //tags,当前应用/版本所有的tag
-    protected $tags = array();
-
-    //groups,当前应用/版本的分组name
-    protected $groups = array();
-
-    protected $controller_layer = "App";
-
-    protected $currentApp = [];
-
-    protected $parseApiDetail;
-
-    public function __construct($config)
-    {
-        $this->reader = new AnnotationReader();
-        if (!empty($config['ignored_annitation'])){
-            foreach ($config['ignored_annitation'] as $item) {
-                AnnotationReader::addGlobalIgnoredName($item);
-            }
-        }
-        $this->config = $config;
-    }
-
-    /**
-     * 生成api接口数据
-     * @param string $appKey
-     * @return array
-     */
-    public function renderApiMenus(string $appKey): array
-    {
-        $currentAppConfig = Helper::getCurrentAppConfig($appKey);
-        $currentApp = $currentAppConfig['appConfig'];
-        $this->currentApp  = $currentApp;
-
-        if (!empty($currentApp['controllers']) && count($currentApp['controllers']) > 0) {
-            // 配置的控制器列表
-            $controllers = $this->getConfigControllers($currentApp['path'],$currentApp['controllers']);
-        } else {
-            // 默认读取所有的
-            $controllers = $this->getDirControllers($currentApp['path']);
-        }
-
-
-        $apiData = [];
-        if (!empty($controllers) && count($controllers) > 0) {
-            foreach ($controllers as $class) {
-                $classData = $this->parseController($class);
-                if ($classData !== false) {
-                    $apiData[] = $classData;
-                }
-            }
-        }
-        // 排序
-        $apiList = Helper::arraySortByKey($apiData);
-        $json = array(
-            "data"   => $apiList,
-            "tags"   => $this->tags,
-            "groups" => $this->groups,
-        );
-        return $json;
-    }
-
-    /**
-     * 获取生成文档的控制器列表
-     * @param string $path
-     * @return array
-     */
-    protected function getConfigControllers(string $path,$appControllers): array
-    {
-        $controllers = [];
-        $configControllers = $appControllers;
-        if (!empty($configControllers) && count($configControllers) > 0) {
-            foreach ($configControllers as $item) {
-                if ( strpos($item, $path) !== false && class_exists($item)) {
-                    $controllers[] = $item;
-                }
-            }
-        }
-        return $controllers;
-    }
-
-    /**
-     * 获取目录下的控制器列表
-     * @param string $path
-     * @return array
-     */
-    protected function getDirControllers(string $path): array
-    {
-
-        if ($path) {
-            if (strpos(APIDOC_ROOT_PATH, '/') !== false) {
-                $pathStr = str_replace("\\", "/", $path);
-            } else {
-                $pathStr = $path;
-            }
-            $dir = APIDOC_ROOT_PATH . $pathStr;
-        } else {
-            $dir = APIDOC_ROOT_PATH . $this->controller_layer;
-        }
-        $controllers = [];
-        if (is_dir($dir)) {
-            $controllers = $this->scanDir($dir, $path);
-        }
-        return $controllers;
-    }
-
-
-
-    protected function scanDir($dir) {
-
-        $classList= DirAndFile::getClassList($dir);
-        $list=[];
-
-        $configFilterController = !empty($this->config['filter_controllers']) ? $this->config['filter_controllers'] : [];
-        $currentAppFilterController =  !empty($this->currentApp['filter_controllers']) ? $this->currentApp['filter_controllers'] : [];
-        $filterControllers = array_merge($configFilterController,$currentAppFilterController);
-
-        $configFilterDir = !empty($this->config['filter_dirs']) ? $this->config['filter_dirs'] : [];
-        $currentAppFilterDir =  !empty($this->currentApp['filter_dirs']) ? $this->currentApp['filter_dirs'] : [];
-        $filterDirList = array_merge($configFilterDir,$currentAppFilterDir);
-        $filterDirs=[];
-        foreach ($filterDirList as $dirItem) {
-            $dirItemPath = DirAndFile::formatPath($dirItem,"/");
-            $filterDirs[]=$dirItemPath;
-        }
-
-        foreach ($classList as $item) {
-            $classNamespace = $item['name'];
-
-            $isFilterDir = false;
-            foreach ($filterDirs as $dirItem) {
-                if (strpos($item['path'], $dirItem) !== false){
-                    $isFilterDir=true;
-                }
-            }
-            if ($isFilterDir){
-                continue;
-            }else if (
-                !in_array($classNamespace, $filterControllers) &&
-                $this->config['definitions'] != $classNamespace
-
-            ) {
-                $list[] = $classNamespace;
-            }
-        }
-
-        return $list;
-    }
-
-    public function parseController($class)
-    {
-
-        $data                 = [];
-        $refClass             = new ReflectionClass($class);
-        $classTextAnnotations = ParseAnnotation::parseTextAnnotation($refClass);
-        if (in_array("NotParse", $classTextAnnotations)) {
-            return false;
-        }
-        $title = $this->reader->getClassAnnotation($refClass, Title::class);
-        $group = $this->reader->getClassAnnotation($refClass, Group::class);
-        $sort = $this->reader->getClassAnnotation($refClass, Sort::class);
-        $routeGroup         = $this->reader->getClassAnnotation($refClass, RouteGroup::class);
-
-        $controllersNameArr = explode("\\", $class);
-        $controllersName    = $controllersNameArr[count($controllersNameArr) - 1];
-        $data['controller'] = $controllersName;
-        $data['path'] = $class;
-        $data['group']      = !empty($group->value) ? $group->value : null;
-        $data['sort']      = !empty($sort->value) ? $sort->value : null;
-        if (!empty($data['group']) && !in_array($data['group'], $this->groups)) {
-            $this->groups[] = $data['group'];
-        }
-        $data['title'] = !empty($title) && !empty($title->value) ? $title->value : "";
-
-        if (empty($title)) {
-            if (!empty($classTextAnnotations) && count($classTextAnnotations) > 0) {
-                $data['title'] = $classTextAnnotations[0];
-            } else {
-                $data['title'] = $controllersName;
-            }
-        }
-        $data['title'] = Lang::getLang($data['title']);
-        $methodList       = [];
-        $data['menuKey'] = Helper::createRandKey($data['controller']);
-        $isNotDebug = in_array("NotDebug", $classTextAnnotations);
-
-        foreach ($refClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $refMethod) {
-            $methodItem = $this->parseApiMethod($refClass,$refMethod,$routeGroup);
-            if ($methodItem===false){
-                continue;
-            }
-            if ($isNotDebug) {
-                $methodItem['notDebug'] = true;
-            }
-            $methodList[] = $methodItem;
-        }
-        $data['children'] = $methodList;
-        if (count($methodList)===0){
-            return false;
-        }
-        return $data;
-    }
-
-
-    protected function parseApiMethod($refClass,$refMethod,$routeGroup){
-        $config               = $this->config;
-        if (empty($refMethod->name)) {
-            return false;
-        }
-        if (empty($this->parseApiDetail)){
-            $this->parseApiDetail = new ParseApiDetail($config);
-        }
-        $textAnnotations = ParseAnnotation::parseTextAnnotation($refMethod);
-        $methodInfo = $this->parseMethodAnnotation($refMethod);
-        if (empty($methodInfo)){
-            return false;
-        }
-        $methodInfo = $this->parseApiDetail->handleApiBaseInfo($methodInfo,$refClass,$refMethod,$textAnnotations);
-        return $methodInfo;
-
-    }
-
-
-    /**
-     * 解析方法注释
-     * @param $refMethod
-     * @return array
-     */
-    protected function parseMethodAnnotation($refMethod): array
-    {
-        $data = [];
-        if ($annotations = $this->reader->getMethodAnnotations($refMethod)) {
-            foreach ($annotations as $annotation) {
-                switch (true) {
-                    case $annotation instanceof Author:
-                        $data['author'] = $annotation->value;
-                        break;
-
-                    case $annotation instanceof Title:
-                        $data['title'] = Lang::getLang($annotation->value);
-                        break;
-                    case $annotation instanceof ParamType:
-                        $data['paramType'] = $annotation->value;
-                        break;
-                    case $annotation instanceof Url:
-                        $data['url'] = $annotation->value;
-                        break;
-                    case $annotation instanceof Method:
-                        if ($annotation->value && strpos($annotation->value, ',') !== false){
-                            $data['method'] =  explode(",", $annotation->value);
-                        }else{
-                            $data['method'] = strtoupper($annotation->value);
-                        }
-                        break;
-                    case $annotation instanceof Tag:
-                        $data['tag'] = $annotation->value;
-                        break;
-                    case $annotation instanceof ContentType:
-                    $data['contentType'] = $annotation->value;
-                    break;
-                }
-            }
-
-        }
-        return $data;
-    }
-
-
-
-    /**
-     * 对象分组到tree
-     * @param $tree
-     * @param $objectData
-     * @param string $childrenField
-     * @return array
-     */
-    public static function objtctGroupByTree($tree,$objectData,$childrenField='children'){
-        $data = [];
-        foreach ($tree as $node){
-            if (!empty($node[$childrenField])){
-                $node[$childrenField] = static::objtctGroupByTree($node[$childrenField],$objectData);
-            }else if (!empty($objectData[$node['name']])){
-                $node[$childrenField] =  $objectData[$node['name']];
-            }
-            $node['menuKey'] = Helper::createRandKey( $node['name']);
-            $data[] = $node;
-        }
-        return $data;
-    }
-
-    /**
-     * 合并接口到应用分组
-     * @param $apiData
-     * @param $groups
-     * @return array
-     */
-    public static function mergeApiGroup($apiData,$groups){
-        if (empty($groups) || count($apiData)<1){
-            return $apiData;
-        }
-        $apiObject = [];
-        foreach ($apiData as $controller){
-            if (!empty($controller['group'])){
-                if (!empty($apiObject[$controller['group']])){
-                    $apiObject[$controller['group']][] = $controller;
-                }else{
-                    $apiObject[$controller['group']] = [$controller];
-                }
-            }else{
-                if (!empty($apiObject['notGroup'])){
-                    $apiObject['notGroup'][] = $controller;
-                }else{
-                    $apiObject['notGroup'] = [$controller];
-                }
-            }
-        }
-        if (!empty($apiObject['notGroup'])){
-            array_unshift($groups,['title'=>'未分组','name'=>'notGroup']);
-        }
-        $res = static::objtctGroupByTree($groups,$apiObject);
-        return $res;
-    }
-}

+ 0 - 104
vendor/hg/apidoc/src/parses/ParseCodeTemplate.php

@@ -1,104 +0,0 @@
-<?php
-declare(strict_types = 1);
-
-namespace hg\apidoc\parses;
-
-use Doctrine\Common\Annotations\AnnotationReader;
-use hg\apidoc\exception\ErrorException;
-use hg\apidoc\generator\ParseTemplate;
-use hg\apidoc\utils\DirAndFile;
-use hg\apidoc\utils\Helper;
-use hg\apidoc\utils\Lang;
-
-class ParseCodeTemplate
-{
-
-    protected $config = [];
-
-    protected $currentApp = [];
-
-
-    public function __construct($config)
-    {
-
-        $this->config = $config;
-    }
-
-    public function renderCode($params)
-    {
-        $appKey = $params['appKey'];
-        $currentAppConfig = Helper::getCurrentAppConfig($appKey);
-        $currentApp = $currentAppConfig['appConfig'];
-        $this->currentApp  = $currentApp;
-
-        $codeTemplate = $params['template'];
-
-        //验证参数
-
-        //验证模板文件是否存在
-
-        //解析接口数据
-        $tplData = [];
-        if ($codeTemplate['select_mode'] == 'controller'){
-            $parseApiMenusService = new ParseApiMenus($this->config);
-            $controllers = $params['selected'];
-            if (!empty($controllers) && count($controllers) > 0) {
-                $controllerList = [];
-                foreach ($controllers as $class) {
-                    $classData = $parseApiMenusService->parseController($class);
-                    if ($classData !== false) {
-                        $controllerList[] = $classData;
-                    }
-                }
-                if (empty($codeTemplate['multiple'])){
-                    $tplData = $controllerList[0];
-                }else{
-                    $tplData = $controllerList;
-                }
-            }
-        }else{
-            // api
-            $apis = $params['selected'];
-            if (!empty($apis) && count($apis) > 0) {
-                $parseApiDetailService = new ParseApiDetail($this->config);
-                $apiList = [];
-                foreach ($apis as $key) {
-                    $apiKey = urldecode($key);
-                    $pathArr   = explode("@", $apiKey);
-                    $classPath = $pathArr[0];
-                    $method = $pathArr[1];
-
-                    $apiDetail = $parseApiDetailService->renderApiDetail($appKey,$classPath,$method);
-                    if ($apiDetail !== false) {
-                        $apiList[] = $apiDetail;
-                    }
-                }
-                if (empty($codeTemplate['multiple'])){
-                    $tplData = $apiList[0];
-                }else{
-                    $tplData = $apiList;
-                }
-            }
-        }
-
-
-        // 读取模板
-        $templatePath =DirAndFile::formatPath( APIDOC_ROOT_PATH . $codeTemplate['template'],"/");
-        if (is_readable($templatePath) == false) {
-            throw new ErrorException("template not found",  [
-                'template' => $template
-            ]);
-        }
-        $tplParams = [
-            'form'=>  $params['form'],
-            'data'=>$tplData
-        ];
-        $html = (new ParseTemplate())->compile($templatePath,$tplParams);
-
-
-
-        return $html;
-    }
-
-
-}

+ 0 - 277
vendor/hg/apidoc/src/parses/ParseModel.php

@@ -1,277 +0,0 @@
-<?php
-declare(strict_types = 1);
-
-namespace hg\apidoc\parses;
-
-use Doctrine\Common\Annotations\Reader;
-use hg\apidoc\exception\ErrorException;
-use hg\apidoc\annotation\Field;
-use hg\apidoc\annotation\WithoutField;
-use hg\apidoc\annotation\AddField;
-use hg\apidoc\utils\Helper;
-use hg\apidoc\utils\Lang;
-
-
-class ParseModel
-{
-    protected static $reader;
-    protected static $config=[];
-
-    public function __construct(Reader $reader,$config=[])
-    {
-         self::$reader = $reader;
-         self::$config = $config;
-    }
-
-    /**
-     * 生成模型数据
-     * @param string $path
-     * @return array|false
-     * @throws \ReflectionException
-     */
-    public function renderModel(string $path)
-    {
-            if (class_exists($path)) {
-
-                $model = static::getModelClass($path);
-                return static::parseModelTable($model,$path,"");
-            } else {
-                if (strpos($path, '@') !== false){
-                    $pathArr   = explode("@", $path);
-                    $modelClassPath = $pathArr[0];
-                    $methodName =  $pathArr[1];
-                }else{
-                    $modelClassArr   = explode("\\", $path);
-                    $methodName = $modelClassArr[count($modelClassArr) - 1];
-                    unset($modelClassArr[count($modelClassArr) - 1]);
-                    $modelClassPath  = implode("\\", $modelClassArr);
-                }
-                if (class_exists($modelClassPath)){
-                    $model = static::getModelClass($modelClassPath);
-                    return static::parseModelTable($model,$modelClassPath,$methodName);
-                }else{
-                    throw new ErrorException("ref file not exists",  [
-                        'path' => $path
-                    ]);
-                }
-            }
-    }
-
-    protected static function parseModelTable($model,$path,$methodName=""){
-        if (!is_callable(array($model, 'getTable'))) {
-            return false;
-        }
-        $reader=static::$reader;
-        try {
-            $classReflect    = new \ReflectionClass($path);
-            // 获取所有模型属性
-            $propertys = $classReflect->getDefaultProperties();
-            $table =static::getTableDocument($model, $propertys);
-            if (empty($methodName)){
-                return $table;
-            }
-
-            $methodAction    = $classReflect->getMethod($methodName);
-            // 模型注释-field
-            if ($fieldAnnotations = $reader->getMethodAnnotation($methodAction, Field::class)) {
-                $table = ParseApiDetail::filterParamsField($table, $fieldAnnotations->value, 'field');
-            }
-            // 模型注释-withoutField
-            if ($fieldAnnotations = $reader->getMethodAnnotation($methodAction, WithoutField::class)) {
-                $table = ParseApiDetail::filterParamsField($table, $fieldAnnotations->value, 'withoutField');
-            }
-            // 模型注释-addField
-            if ($annotations = $reader->getMethodAnnotations($methodAction)) {
-                foreach ($annotations as $annotation) {
-                    switch (true) {
-                        case $annotation instanceof AddField:
-                            $param         = [
-                                "name"    => "",
-                                "desc"    => $annotation->desc,
-                                "require" => $annotation->require,
-                                "type"    => $annotation->type,
-                                "default" => $annotation->default,
-                            ];
-                            if (!empty($annotation->mdRef)){
-                                $param['md'] = ParseMarkdown::getContent("",$annotation->mdRef);
-                            }
-                            if (!empty($annotation->md)){
-                                $param['md'] = $annotation->md;
-                            }
-                            $children      = static::handleParamValue($annotation->value);
-                            $param['name'] = $children['name'];
-                            if (count($children['params']) > 0) {
-                                $param['children'] = $children['params'];
-                            }
-                            $isExists = false;
-                            $newTable = [];
-                            foreach ($table as $item) {
-                                if ($param['name'] === $item['name']) {
-                                    $isExists   = true;
-                                    $newTable[] = $param;
-                                } else {
-                                    $newTable[] = $item;
-                                }
-                            }
-                            $table = $newTable;
-                            if (!$isExists) {
-                                $table[] = $param;
-                            }
-                            break;
-                    }
-                }
-            }
-            return $table;
-        } catch (\ReflectionException $e) {
-            throw new ErrorException('Class '.$path.' '.$e->getMessage());
-        }
-
-    }
-    /**
-     * 处理字段参数
-     * @param $values
-     * @return array
-     */
-    protected static function handleParamValue($values): array
-    {
-        $name   = "";
-        $params = [];
-        if (!empty($values) && is_array($values) && count($values) > 0) {
-            foreach ($values as $item) {
-                if (is_string($item)) {
-                    $name = $item;
-                } else if (is_object($item)) {
-                    $param         = [
-                        "name"    => "",
-                        "type"    => $item->type,
-                        "desc"    => $item->desc,
-                        "default" => $item->default,
-                        "require" => $item->require,
-                    ];
-                    $children      = static::handleParamValue($item->value);
-                    $param['name'] = $children['name'];
-                    if (count($children['params']) > 0) {
-                        $param['children'] = $children['params'];
-                    }
-                    $params[] = $param;
-                }
-            }
-        } else {
-            $name = $values;
-        }
-        return ['name' => $name, 'params' => $params];
-    }
-
-    /**
-     * 获取模型实例
-     * @param $method
-     * @return mixed|null
-     */
-    public static function getModelClass($namespaceName)
-    {
-        if (!empty($namespaceName) && class_exists($namespaceName)) {
-            $modelInstance = new $namespaceName();
-            return $modelInstance;
-        } else {
-            return null;
-        }
-    }
-
-
-
-
-    /**
-     * 获取模型注解数据
-     * @param $model
-     * @param $propertys
-     * @return array
-     */
-    public static function getTableDocument($model,array $propertys):array
-    {
-        $config = static::$config;
-        if (empty($config['database_query_function'])){
-            throw new ErrorException("not datatable_query_function config");
-        }
-        $sqlRes = $config['database_query_function']("show create table " . $model->getTable());
-        $createTableObj = $sqlRes[0];
-        $createTableArray = Helper::objectToArray($createTableObj);
-        $createTable = "";
-        if (!empty($createTableArray['Create Table'])){
-            $createTable = $createTableArray['Create Table'];
-        }else  if(!empty($createTableArray['create table'])){
-            $createTable = $createTableArray['create table'];
-        }else{
-            throw new ErrorException("datatable not exists",  $createTableArray);
-        }
-        preg_match_all("#[^KEY]`(.*?)` (.*?) (.*?),\n#", $createTable, $matches);
-        $fields       = $matches[1];
-        $types        = $matches[2];
-        $contents     = $matches[3];
-        $fieldComment = [];
-        //组织注释
-        for ($i = 0; $i < count($matches[0]); $i++) {
-            $key     = $fields[$i];
-            $type    = $types[$i];
-            $default = "";
-            $require = "";
-            $desc    = "";
-            $mock = "";
-            $md="";
-            $content = $contents[$i];
-            if (strpos($type, '(`') !== false) {
-                continue;
-            }
-            if (strpos($content, 'COMMENT') !== false) {
-                // 存在字段注释
-                preg_match_all("#COMMENT\s*'(.*?)'#", $content, $edscs);
-                if (!empty($edscs[1]) && !empty($edscs[1][0])){
-                    $desc = Lang::getLang($edscs[1][0]);
-                    if (strpos($desc, 'mock(') !== false){
-                        // 存在mock
-                        preg_match('#mock\((.*)\)#s', $content, $mocks);
-                        if (!empty($mocks[1])) {
-                            $mock = $mocks[1];
-                            $desc = str_replace($mocks[0],"",$desc);
-                        }
-                    }
-                    if (strpos($desc, 'mdRef="') !== false){
-                        // 存在mdRef
-                        preg_match('#mdRef="(.*)"#s', $content, $mdRefs);
-                        if (!empty($mdRefs[1])) {
-                            $md = ParseMarkdown::getContent("",$mdRefs[1]);
-                            $desc = str_replace($mdRefs[0],"",$desc);
-                        }
-                    }
-                }
-
-            }
-            if (strpos($content, 'DEFAULT') !== false) {
-                // 存在字段默认值
-                preg_match_all("#DEFAULT\s*'(.*?)'#", $content, $defaults);
-                $default = $defaults[1] && is_array($defaults[1])?$defaults[1][0]:"";
-            }
-
-            if (strpos($content, 'NOT NULL') !== false) {
-                // 必填字段
-                $require = "1";
-            }
-
-            $name = $key;
-            // 转换字段名为驼峰命名(用于输出)
-            if (isset($propertys['convertNameToCamel']) && $propertys['convertNameToCamel'] === true) {
-                $name = Helper::camel($key);
-            }
-            $fieldComment[] = [
-                "name"    => $name,
-                "type"    => $type,
-                "desc"    => $desc,
-                "default" => $default,
-                "require" => $require,
-                "mock"=>$mock,
-                "md"=>$md
-            ];
-        }
-        return $fieldComment;
-    }
-
-}

+ 0 - 133
vendor/hg/apidoc/src/providers/BaseService.php

@@ -1,133 +0,0 @@
-<?php
-
-namespace hg\apidoc\providers;
-
-use hg\apidoc\utils\ConfigProvider;
-
-trait BaseService
-{
-
-    static $routes = [
-        ['rule'=>'config','route'=>'getConfig','method'=>'GET'],
-        ['rule'=>'apiMenus','route'=>'getApiMenus','method'=>'POST'],
-        ['rule'=>'apiDetail','route'=>'getApiDetail','method'=>'POST'],
-        ['rule'=>'docMenus','route'=>'getMdMenus','method'=>'POST'],
-        ['rule'=>'docDetail','route'=>'getMdDetail','method'=>'POST'],
-        ['rule'=>'verifyAuth','route'=>'verifyAuth','method'=>'POST'],
-        ['rule'=>'generator','route'=>'createGenerator','method'=>'POST'],
-        ['rule'=>'cancelAllCache','route'=>'cancelAllCache','method'=>'POST'],
-        ['rule'=>'createAllCache','route'=>'createAllCache','method'=>'POST'],
-        ['rule'=>'renderCodeTemplate','route'=>'renderCodeTemplate','method'=>'POST'],
-    ];
-
-
-
-    /**
-     * 获取apidoc配置
-     * @return array 返回apidoc配置
-     */
-    abstract static function getApidocConfig();
-
-
-    /**
-     * 注册apidoc路由
-     * @param $route 路由参数
-     * @return mixed
-     */
-    abstract static function registerRoute($route);
-
-    /**
-     * 执行Sql语句
-     * @return mixed
-     */
-    abstract static function databaseQuery($sql);
-
-    /**
-     * 获取项目根目录
-     * @return string 返回项目根目录
-     */
-    abstract static function getRootPath();
-
-    /**
-     * 获取缓存目录
-     * @return string 返回项目缓存目录
-     */
-    abstract static function getRuntimePath();
-
-
-    /**
-     * 设置当前语言
-     * @param $locale 语言标识
-     * @return mixed
-     */
-    abstract static function setLang($locale);
-
-    /**
-     * 获取语言定义
-     * @param $lang
-     * @return string
-     */
-    abstract static function getLang($lang);
-
-
-    /**
-     * 处理apidoc接口响应的数据
-     * @return mixed
-     */
-    abstract static function handleResponseJson($res);
-
-    abstract static function getTablePrefix();
-
-
-    public function initConfig(){
-        ! defined('APIDOC_ROOT_PATH') && define('APIDOC_ROOT_PATH', $this->getRootPath());
-        ! defined('APIDOC_STORAGE_PATH') && define('APIDOC_STORAGE_PATH', $this->getRuntimePath());
-        $config = self::getApidocConfig();
-        $config['database_query_function'] = function ($sql){
-            return self::databaseQuery($sql);
-        };
-        $config['lang_register_function'] = function ($sql){
-            return self::setLang($sql);
-        };
-        $config['lang_get_function'] = function ($lang){
-            return self::getLang($lang);
-        };
-        $config['handle_response_json'] = function ($res){
-            return self::handleResponseJson($res);
-        };
-        $table_prefix = self::getTablePrefix();
-        if (!empty($config['database'])){
-            if (empty($config['prefix'])){
-                $config['database']['prefix'] = $table_prefix;
-            }
-        }else{
-            $config['database']=[
-                'prefix'=>$table_prefix
-            ];
-        }
-        ConfigProvider::set($config);
-    }
-
-    /**
-     * @param null $routeFun
-     */
-    static public function registerApidocRoutes($routeFun=null){
-        $routes = static::$routes;
-        $controller_namespace = '\hg\apidoc\Controller@';
-        $route_prefix = "/apidoc/";
-        foreach ($routes as $item) {
-            $route = [
-                'uri'=>$route_prefix.$item['rule'],
-                'callback'=>$controller_namespace.$item['route'],
-                'route'=>$item['route'],
-                'method'=>$item['method']
-            ];
-            if (!empty($routeFun)){
-                $routeFun($route);
-            }else{
-                self::registerRoute($route);
-            }
-        }
-    }
-
-}

+ 0 - 56
vendor/hg/apidoc/src/providers/CommonService.php

@@ -1,56 +0,0 @@
-<?php
-
-namespace hg\apidoc\providers;
-
-use hg\apidoc\utils\ConfigProvider;
-
-class CommonService
-{
-    use BaseService;
-
-    static function getApidocConfig()
-    {
-        // TODO: Implement getApidocConfig() method.
-    }
-
-    static function registerRoute($route)
-    {
-        // TODO: Implement registerRoute() method.
-    }
-
-    static function databaseQuery($sql)
-    {
-        // TODO: Implement databaseQuery() method.
-    }
-
-    static function getRootPath()
-    {
-        // TODO: Implement getRootPath() method.
-    }
-
-    static function getRuntimePath()
-    {
-        // TODO: Implement getRuntimePath() method.
-    }
-
-    static function setLang($locale)
-    {
-        // TODO: Implement setLang() method.
-    }
-
-    static function getLang($lang)
-    {
-        // TODO: Implement getLang() method.
-    }
-
-    static function handleResponseJson($res)
-    {
-        // TODO: Implement handleResponseJson() method.
-    }
-
-    static function getTablePrefix()
-    {
-        // TODO: Implement getTablePrefix() method.
-    }
-
-}

+ 0 - 80
vendor/hg/apidoc/src/providers/HyperfService.php

@@ -1,80 +0,0 @@
-<?php
-
-namespace hg\apidoc\providers;
-
-use hg\apidoc\utils\ConfigProvider;
-use Hyperf\DbConnection\Db;
-
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Server\RequestHandlerInterface;
-
-class HyperfService
-{
-    use BaseService;
-
-    static $langLocale="zh_CN";
-
-    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
-    {
-        $this->initConfig();
-
-        if ($request->getMethod() == "GET"){
-            $params = $request->getQueryParams();
-        }else{
-            $params = $request->getParsedBody();
-        }
-        $config =  ConfigProvider::get();
-        $config['request_params'] = $params;
-        ConfigProvider::set($config);
-        return $handler->handle($request);
-    }
-
-    static function getApidocConfig()
-    {
-        $config = config("apidoc");
-        if (!(!empty($config['auto_url']) && !empty($config['auto_url']['filter_keys']))){
-            $config['auto_url']['filter_keys'] = ['App','Controller'];
-        }
-        return $config;
-    }
-
-    static function registerRoute($route)
-    {
-        // TODO: Implement registerRoute() method.
-    }
-
-    static function databaseQuery($sql)
-    {
-        return Db::select($sql);
-    }
-
-    static function getRootPath()
-    {
-        return BASE_PATH."/";
-    }
-
-    static function getRuntimePath()
-    {
-        return BASE_PATH."/runtime/";
-    }
-
-    static function setLang($locale)
-    {
-        static::$langLocale = $locale;
-    }
-
-    static function getLang($lang): string
-    {
-        return trans($lang);
-    }
-
-    static function handleResponseJson($res)
-    {
-        return $res;
-    }
-
-    static function getTablePrefix(){
-        return config('databases.default.prefix','');
-    }
-}

+ 0 - 84
vendor/hg/apidoc/src/providers/LaravelService.php

@@ -1,84 +0,0 @@
-<?php
-
-namespace hg\apidoc\providers;
-
-use hg\apidoc\middleware\LaravelMiddleware;
-use Illuminate\Support\Facades\Lang;
-use Illuminate\Support\Facades\Request;
-use Illuminate\Support\ServiceProvider;
-use Illuminate\Support\Facades\Route;
-use Exception;
-use hg\apidoc\utils\ApiCrossDomain;
-use Illuminate\Support\Facades\DB;
-
-class LaravelService extends ServiceProvider
-{
-
-    use BaseService;
-
-    public function boot()
-    {
-        $this->publishes([
-            __DIR__.'/../config.php' => config_path('apidoc.php'),
-        ]);
-    }
-
-    public function register()
-    {
-        $config = static::getApidocConfig();
-        $this->initConfig();
-        self::registerApidocRoutes();
-    }
-
-    static function getApidocConfig()
-    {
-        $config = config("apidoc");
-        if (!(!empty($config['auto_url']) && !empty($config['auto_url']['filter_keys']))){
-            $config['auto_url']['filter_keys'] = ['App','Http','Controllers'];
-        }
-        return $config;
-    }
-
-    static function registerRoute($route){
-        $config = self::getApidocConfig();
-        $registerRoute =  Route::match([$route['method']],$route['uri'], $route['callback']);
-        $registerRoute->middleware([LaravelMiddleware::class]);
-        if (!empty($config['allowCrossDomain'])) {
-            $registerRoute->middleware([ApiCrossDomain::class]);
-        }
-    }
-
-    static function databaseQuery($sql){
-        return DB::select($sql);
-    }
-
-    static function getTablePrefix(){
-        $driver = config('database.default');
-        $table_prefix=config('database.connections.'.$driver.'.prefix');
-        return $table_prefix;
-    }
-
-    static function getRootPath()
-    {
-        return base_path()."/";
-    }
-
-    static function getRuntimePath()
-    {
-        return storage_path()."/";
-    }
-
-    static function setLang($locale){
-        Lang::setLocale($locale);
-    }
-
-    static function getLang($lang){
-        return trans($lang);
-    }
-
-    static function handleResponseJson($res){
-        return $res;
-    }
-
-
-}

+ 0 - 71
vendor/hg/apidoc/src/providers/ThinkPHP5Service.php

@@ -1,71 +0,0 @@
-<?php
-
-namespace hg\apidoc\providers;
-
-use think\facade\App;
-use think\facade\Route;
-use think\facade\Request;
-use think\facade\Lang;
-use think\Db;
-use Exception;
-
-class ThinkPHP5Service
-{
-    use BaseService;
-
-    public function run(){
-        $this->initConfig();
-        self::registerApidocRoutes();
-    }
-
-    static function getApidocConfig()
-    {
-        $config = config("apidoc.");
-        if (!(!empty($config['auto_url']) && !empty($config['auto_url']['filter_keys']))){
-            $config['auto_url']['filter_keys'] = ['app','controller'];
-        }
-        return $config;
-    }
-
-    static function registerRoute($route){
-        $config = self::getApidocConfig();
-        $registerRoute = Route::rule($route['uri'], $route['callback'],$route['method']);
-        if (!empty($config['allowCrossDomain'])) {
-            $registerRoute->allowCrossDomain();
-        }
-    }
-
-    static function databaseQuery($sql){
-        return Db::query($sql);
-    }
-
-    static function getTablePrefix(){
-        $driver = config('database.default');
-        $table_prefix=config('database.connections.'.$driver.'.prefix');
-        return $table_prefix;
-    }
-
-    static function getRootPath()
-    {
-        return App::getRootPath();
-    }
-
-    static function getRuntimePath()
-    {
-        return App::getRuntimePath();
-    }
-
-    static function setLang($locale){
-        Lang::setLangCookieVar($locale);
-    }
-
-    static function getLang($lang){
-        return Lang::get($lang);
-    }
-
-    static function handleResponseJson($res){
-        return json($res);
-    }
-
-
-}

+ 0 - 78
vendor/hg/apidoc/src/providers/ThinkPHPService.php

@@ -1,78 +0,0 @@
-<?php
-
-namespace hg\apidoc\providers;
-
-use hg\apidoc\middleware\ThinkPHPMiddleware;
-use think\facade\App;
-use think\facade\Route;
-use think\facade\Request;
-use think\facade\Lang;
-use think\facade\Db;
-
-class ThinkPHPService extends \think\Service
-{
-    use BaseService;
-
-    static function getApidocConfig()
-    {
-        $config = config("apidoc");
-        if (!(!empty($config['auto_url']) && !empty($config['auto_url']['filter_keys']))){
-            $config['auto_url']['filter_keys'] = ['app','controller'];
-        }
-        return $config;
-    }
-
-    public function register()
-    {
-        $config = static::getApidocConfig();
-        $this->initConfig();
-        $this->registerRoutes(function () use($config){
-            self::registerApidocRoutes(function ($route)use ($config){
-                $registerRoute = Route::rule($route['uri'], $route['callback'],$route['method']);
-                $registerRoute->middleware([ThinkPHPMiddleware::class]);
-                if (!empty($config['allowCrossDomain'])) {
-                    $registerRoute->allowCrossDomain();
-                }
-            });
-        });
-    }
-
-    static function registerRoute($route){
-
-    }
-
-    static function databaseQuery($sql){
-        return Db::query($sql);
-    }
-
-    static function getTablePrefix(){
-        $driver = config('database.default');
-        $table_prefix=config('database.connections.'.$driver.'.prefix');
-        return $table_prefix;
-    }
-
-    static function getRootPath()
-    {
-        return App::getRootPath();
-    }
-
-    static function getRuntimePath()
-    {
-        return App::getRuntimePath();
-    }
-
-    static function setLang($locale){
-        \think\facade\App::loadLangPack($locale);
-        Lang::setLangSet($locale);
-    }
-
-    static function getLang($lang){
-        return Lang::get($lang);
-    }
-
-    static function handleResponseJson($res){
-        return json($res);
-    }
-
-
-}

+ 0 - 22
vendor/hg/apidoc/src/utils/ApiCrossDomain.php

@@ -1,22 +0,0 @@
-<?php
-declare(strict_types = 1);
-namespace hg\apidoc\utils;
-use \Illuminate\Http\Request;
-class ApiCrossDomain
-{
-
-    public function handle (Request $request, \Closure $next){
-
-        $response = $next($request);
-        $origin = $request->server('HTTP_ORIGIN') ? $request->server('HTTP_ORIGIN') : '';
-        $response->header('Access-Control-Allow-Origin', $origin);
-        $response->header('Access-Control-Allow-Headers', 'Origin, Content-Type, Cookie, X-CSRF-TOKEN, Accept, Authorization, X-XSRF-TOKEN');
-        $response->header('Access-Control-Expose-Headers', 'Authorization, authenticated');
-        $response->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, OPTIONS');
-        $response->header('Access-Control-Allow-Credentials', 'true');
-        return $response;
-
-    }
-
-
-}

+ 0 - 298
vendor/hg/apidoc/src/utils/Cache.php

@@ -1,298 +0,0 @@
-<?php
-
-declare (strict_types = 1);
-
-namespace hg\apidoc\utils;
-
-use FilesystemIterator;
-
-/**
- * 文件缓存类
- */
-class Cache
-{
-    /**
-     * 缓存写入次数
-     * @var integer
-     */
-    protected $writeTimes = 0;
-
-    /**
-     * 缓存读取次数
-     * @var integer
-     */
-    protected $readTimes = 0;
-
-    /**
-     * 配置参数
-     * @var array
-     */
-    protected $options = [
-        'expire'        => 0,
-        'cache_subdir'  => true,
-        'prefix'        => '',
-        'path'          => '',
-        'hash_type'     => 'md5',
-        'data_compress' => false,
-        'serialize'     => [],
-    ];
-
-    /**
-     * 架构函数
-     * @param array $options 参数
-     */
-    public function __construct( array $options = [])
-    {
-        if (!empty($options)) {
-            $this->options = array_merge($this->options, $options);
-        }
-
-        if (empty($this->options['path'])) {
-            $this->options['path'] = APIDOC_STORAGE_PATH .'\\'. 'apidoc';
-        }
-
-        if (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) {
-            $this->options['path'] .= DIRECTORY_SEPARATOR;
-        }
-    }
-
-    /**
-     * 取得变量的存储文件名
-     * @access public
-     * @param string $name 缓存变量名
-     * @return string
-     */
-    public function getCacheKey(string $name): string
-    {
-        $name = $name."_".hash($this->options['hash_type'], $name);
-
-        if ($this->options['prefix']) {
-            $name = $this->options['prefix'] . DIRECTORY_SEPARATOR . $name;
-        }
-
-        return $this->options['path'] . $name . '.php';
-    }
-
-    /**
-     * 序列化数据
-     * @access protected
-     * @param mixed $data 缓存数据
-     * @return string
-     */
-    protected function serialize($data): string
-    {
-        if (is_numeric($data)) {
-            return (string) $data;
-        }
-
-        $serialize = $this->options['serialize'][0] ?? "serialize";
-
-        return $serialize($data);
-    }
-
-
-    /**
-     * 反序列化数据
-     * @access protected
-     * @param string $data 缓存数据
-     * @return mixed
-     */
-    protected function unserialize($data)
-    {
-        if (is_numeric($data)) {
-            return $data;
-        }
-
-        $unserialize = $this->options['serialize'][1] ?? "unserialize";
-
-        return $unserialize($data);
-    }
-
-
-    /**
-     * 获取有效期
-     * @access protected
-     * @param integer|DateTimeInterface|DateInterval $expire 有效期
-     * @return int
-     */
-    protected function getExpireTime($expire): int
-    {
-        if ($expire instanceof DateTimeInterface) {
-            $expire = $expire->getTimestamp() - time();
-        } elseif ($expire instanceof DateInterval) {
-            $expire = DateTime::createFromFormat('U', (string) time())
-                    ->add($expire)
-                    ->format('U') - time();
-        }
-
-        return (int) $expire;
-    }
-
-    /**
-     * 获取缓存数据
-     * @param string $name 缓存标识名
-     * @return array|null
-     */
-    protected function getRaw(string $name)
-    {
-        $filename = $this->getCacheKey($name);
-
-        if (!is_file($filename)) {
-            return;
-        }
-
-        $content = @file_get_contents($filename);
-
-        if (false !== $content) {
-            $expire = (int) substr($content, 8, 12);
-            $createTime = filemtime($filename);
-            if (0 != $expire && time() - $expire > $createTime) {
-                //缓存过期删除缓存文件
-                DirAndFile::unlink($item->getPathname());
-                return;
-            }
-
-            $content = substr($content, 32);
-
-            if ($this->options['data_compress'] && function_exists('gzcompress')) {
-                //启用数据压缩
-                $content = gzuncompress($content);
-            }
-
-            return is_string($content) ? ['content' => $content, 'expire' => $expire,'create_time'=>$createTime] : null;
-        }
-    }
-
-    /**
-     * 判断缓存是否存在
-     * @access public
-     * @param string $name 缓存变量名
-     * @return bool
-     */
-    public function has($name): bool
-    {
-        return $this->getRaw($name) !== null;
-    }
-
-    /**
-     * 读取缓存
-     * @access public
-     * @param string $name    缓存变量名
-     * @param mixed  $default 默认值
-     * @return mixed
-     */
-    public function get($name, $default = null)
-    {
-        $this->readTimes++;
-
-        $raw = $this->getRaw($name);
-
-        return is_null($raw) ? $default : $this->unserialize($raw['content']);
-    }
-
-    /**
-     * 写入缓存
-     * @access public
-     * @param string        $name   缓存变量名
-     * @param mixed         $value  存储数据
-     * @param int|\DateTime $expire 有效时间 0为永久
-     * @return bool
-     */
-    public function set($name, $value, $expire = null): bool
-    {
-        $this->writeTimes++;
-
-        if (is_null($expire)) {
-            $expire = $this->options['expire'];
-        }
-
-        $expire   = $this->getExpireTime($expire);
-        $filename = $this->getCacheKey($name);
-
-        $dir = dirname($filename);
-
-        if (!is_dir($dir)) {
-            try {
-                mkdir($dir, 0755, true);
-            } catch (\Exception $e) {
-                // 创建失败
-            }
-        }
-
-        $data = $this->serialize($value);
-
-        if ($this->options['data_compress'] && function_exists('gzcompress')) {
-            //数据压缩
-            $data = gzcompress($data, 3);
-        }
-
-        $data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
-        $result = file_put_contents($filename, $data);
-
-        if ($result) {
-            clearstatcache();
-            return true;
-        }
-
-        return false;
-    }
-
-
-
-    /**
-     * 删除缓存
-     * @access public
-     * @param string $name 缓存变量名
-     * @return bool
-     */
-    public function delete($name): bool
-    {
-        $this->writeTimes++;
-
-        return DirAndFile::unlink($this->getCacheKey($name));
-    }
-
-    /**
-     * 清除缓存
-     * @access public
-     * @return bool
-     */
-    public function clear(): bool
-    {
-        $this->writeTimes++;
-
-        $dirname = $this->options['path'] . $this->options['prefix'];
-
-        $this->rmdir($dirname);
-
-        return true;
-    }
-
-
-    /**
-     * 删除文件夹
-     * @param $dirname
-     * @return bool
-     */
-    private function rmdir($dirname)
-    {
-        if (!is_dir($dirname)) {
-            return false;
-        }
-
-        $items = new FilesystemIterator($dirname);
-
-        foreach ($items as $item) {
-            if ($item->isDir() && !$item->isLink()) {
-                $this->rmdir($item->getPathname());
-            } else {
-                DirAndFile::unlink($item->getPathname());
-            }
-        }
-
-        @rmdir($dirname);
-
-        return true;
-    }
-
-}

+ 0 - 89
vendor/hg/apidoc/src/utils/ConfigProvider.php

@@ -1,89 +0,0 @@
-<?php
-
-namespace hg\apidoc\utils;
-
-use hg\apidoc\exception\ErrorException;
-
-class ConfigProvider
-{
-
-    protected static  $defaultConfig = [
-        'cache'=>[
-            'folder'=>'apidoc'
-        ]
-    ];
-    protected static $config = [];
-
-
-    public static function get($field="",$isFilter=false){
-
-        if (!empty(static::$config)) {
-            $config = static::$config;
-        }else{
-            throw new ErrorException('ConfigProvider get error');
-        }
-        if ($isFilter){
-            $config = static::handleConfig($config);
-        }
-
-        return Helper::getObjectFindByField($config,$field);
-    }
-
-    public static function set($config){
-        if (!(!empty($config['cache']) && !empty($config['cache']['folder']))){
-            if (!empty($config['cache'])){
-                $config['cache']['folder'] =static::$defaultConfig['cache']['folder'];
-            }
-        }
-        static::$config = $config;
-    }
-
-    public static function getFeConfig(){
-        $config = static::$config;
-
-        $feConfig = [
-            'title'  =>!empty($config['title'])?Lang::getLang($config['title'] ):'',
-            'desc' =>!empty($config['title'])?Lang::getLang($config['desc']):'',
-            'apps'=>!empty($config['apps'])?$config['apps']:[],
-            'cache'=>!empty($config['cache'])?$config['cache']:[],
-            'params'=>!empty($config['params'])?$config['params']:[],
-            'responses'=>!empty($config['responses'])?$config['responses']:[],
-            'generator'=>!empty($config['generator'])?$config['generator']:[],
-            'code_template'=>!empty($config['code_template'])?$config['code_template']:[],
-        ];
-        if (!empty($feConfig['apps']) && count($feConfig['apps'])){
-            // 清除apps配置中的password
-            $feConfig['apps'] = Helper::handleAppsConfig($feConfig['apps'],true);
-        }
-
-        if (!empty($feConfig['params']) && !empty($feConfig['params']['header'])){
-            $feConfig['params']['header'] = Lang::getArrayLang($feConfig['params']['header'],"desc");
-        }
-        if (!empty($feConfig['params']) && !empty($feConfig['params']['query'])){
-            $feConfig['params']['query'] = Lang::getArrayLang($feConfig['params']['query'],"desc");
-        }
-        if (!empty($feConfig['params']) && !empty($feConfig['params']['body'])){
-            $feConfig['params']['body'] = Lang::getArrayLang($feConfig['params']['body'],"desc");
-        }
-        if (!empty($feConfig['responses']) && !empty($feConfig['responses']['success'])){
-            $feConfig['responses']['success'] = Lang::getArrayLang($feConfig['responses']['success'],"desc");
-        }
-        if (!empty($feConfig['responses']) && !empty($feConfig['responses']['error'])){
-            $feConfig['responses']['error'] = Lang::getArrayLang($feConfig['responses']['error'],"desc");
-        }
-        if (!empty($feConfig['generator'])){
-            $generatorList = [];
-            $generators= Lang::getArrayLang($feConfig['generator'],"title");
-            foreach ($generators as $item) {
-                if (!empty($item['form']) && !empty($item['form']['items']) && count($item['form']['items'])){
-                    $item['form']['items'] = Lang::getArrayLang( $item['form']['items'],"title");
-                }
-                $generatorList[]=$item;
-            }
-            $feConfig['generator'] = $generatorList;
-        }
-        return $feConfig;
-    }
-
-
-}

+ 0 - 238
vendor/hg/apidoc/src/utils/DirAndFile.php

@@ -1,238 +0,0 @@
-<?php
-
-namespace hg\apidoc\utils;
-
-class DirAndFile
-{
-
-
-    public static function getDirTree($path){
-        $arr = [];
-        if(is_dir($path)){
-            $dir = scandir($path);
-            foreach ($dir as $value){
-                $sub_path =static::formatPath($path .'/'.$value,"/");
-                if($value == '.' || $value == '..'){
-                    continue;
-                }else if(is_dir($sub_path)){
-                    $item = [
-                        'name'=>$value,
-                        'path'=>$sub_path,
-                    ];
-                    $children = static::getDirTree($sub_path);
-                    if (count($children)){
-                        $item['children'] = $children;
-                    }
-                    $arr[] = $item;
-                }
-            }
-        }
-        return $arr;
-    }
-
-    public static function getClassList($dir){
-        if ($handle = opendir($dir)) {
-            $file_list=[];
-            while (false !== ($file = readdir($handle))) {
-                if($file=='..' || $file=='.') continue;
-                $filePath = static::formatPath($dir.'/'.$file,"/");
-                if(is_file($filePath)) {
-                    if ('php' !== pathinfo($filePath, \PATHINFO_EXTENSION)) {
-                        continue;
-                    }
-                    $classes = self::findClasses($filePath);
-                    if (!empty($classes) && count($classes)){
-                        $file_list[] = [
-                            'name'=>$classes[0],
-                            'path'=>$filePath
-                        ];
-                    }else{
-                        $file_list=[];
-                    }
-                    continue;
-                }
-                $file_list[$file] = static::getClassList($filePath);
-                foreach($file_list[$file] as $infile) {
-                    $file_list[] = $infile;
-                }
-                unset($file_list[$file]);
-            }
-            closedir($handle);
-            return $file_list;
-        }
-        return [];
-    }
-
-    public static function formatPath($path,$type="/"){
-        if ($type==="/"){
-            $path = str_replace("\\","/",$path);
-        }else{
-            $path = str_replace("/","\\",$path);
-            $path = str_replace("\\\\","\\",$path);
-            $endStr = substr($path, -1);
-            if ($endStr=='\\'){
-                $path = substr($path,0,strlen($path)-1);
-            }
-        }
-        return $path;
-    }
-
-    private static function findClasses($path)
-    {
-        $contents = file_get_contents($path);
-        $tokens = token_get_all($contents);
-
-        $nsTokens = [\T_STRING => true, \T_NS_SEPARATOR => true];
-        if (\defined('T_NAME_QUALIFIED')) {
-            $nsTokens[T_NAME_QUALIFIED] = true;
-        }
-
-        $classes = [];
-
-        $namespace = '';
-        for ($i = 0; isset($tokens[$i]); ++$i) {
-            $token = $tokens[$i];
-
-            if (!isset($token[1])) {
-                continue;
-            }
-
-            $class = '';
-
-            switch ($token[0]) {
-                case \T_NAMESPACE:
-                    $namespace = '';
-                    // If there is a namespace, extract it
-                    while (isset($tokens[++$i][1])) {
-                        if (isset($nsTokens[$tokens[$i][0]])) {
-                            $namespace .= $tokens[$i][1];
-                        }
-                    }
-                    $namespace .= '\\';
-                    break;
-                case \T_CLASS:
-                case \T_INTERFACE:
-                case \T_TRAIT:
-                    // Skip usage of ::class constant
-                    $isClassConstant = false;
-                    for ($j = $i - 1; $j > 0; --$j) {
-                        if (!isset($tokens[$j][1])) {
-                            break;
-                        }
-
-                        if (\T_DOUBLE_COLON === $tokens[$j][0]) {
-                            $isClassConstant = true;
-                            break;
-                        } elseif (!\in_array($tokens[$j][0], [\T_WHITESPACE, \T_DOC_COMMENT, \T_COMMENT])) {
-                            break;
-                        }
-                    }
-
-                    if ($isClassConstant) {
-                        break;
-                    }
-
-                    // Find the classname
-                    while (isset($tokens[++$i][1])) {
-                        $t = $tokens[$i];
-                        if (\T_STRING === $t[0]) {
-                            $class .= $t[1];
-                        } elseif ('' !== $class && \T_WHITESPACE === $t[0]) {
-                            break;
-                        }
-                    }
-
-                    $classes[] = ltrim($namespace.$class, '\\');
-                    break;
-                default:
-                    break;
-            }
-        }
-
-        return $classes;
-    }
-
-
-    /**
-     * 读取文件内容
-     * @param $fileName
-     * @return false|string
-     */
-    public static function getFileContent(string $fileName): string
-    {
-        $content = "";
-        if (file_exists($fileName)) {
-            $handle  = fopen($fileName, "r");
-            $content = fread($handle, filesize($fileName));
-            fclose($handle);
-        }
-        return $content;
-    }
-
-    /**
-     * 保存文件
-     * @param $path
-     * @param $str_tmp
-     * @return bool
-     */
-    public static function createFile(string $path, string $str_tmp): bool
-    {
-        $pathArr = explode("/", $path);
-        unset($pathArr[count($pathArr) - 1]);
-        $dir = implode("/", $pathArr);
-        if (!file_exists($dir)) {
-            mkdir($dir, 0775, true);
-        }
-        $fp = fopen($path, "w") or die("Unable to open file!");
-        fwrite($fp, $str_tmp); //存入内容
-        fclose($fp);
-        return true;
-    }
-
-    /**
-     * 判断文件是否存在后,删除
-     * @access private
-     * @param string $path
-     * @return bool
-     */
-    public static function unlink(string $path): bool
-    {
-        try {
-            return is_file($path) && unlink($path);
-        } catch (\Exception $e) {
-            return false;
-        }
-    }
-
-    public static function checkFileExist(string $path)
-    {
-        try {
-            return $path;
-        } catch (\Exception $e) {
-            return $e;
-        }
-    }
-
-    public static function deleteDir($path) {
-        if (!is_dir($path)) {
-            return false;
-        }
-        $open = opendir($path);
-        if (!$open) {
-            return false;
-        }
-        while (($v = readdir($open)) !== false) {
-            if ('.' == $v || '..' == $v) {
-                continue;
-            }
-            $item = $path . '/' . $v;
-            if (is_file($item)) {
-                unlink($item);
-                continue;
-            }
-           static::deleteDir($item);
-        }
-        closedir($open);
-        return rmdir($path);
-    }
-}

+ 0 - 54
vendor/hg/apidoc/src/utils/Lang.php

@@ -1,54 +0,0 @@
-<?php
-declare(strict_types = 1);
-
-namespace hg\apidoc\utils;
-
-use hg\apidoc\exception\ErrorException;
-
-class Lang
-{
-
-    /**
-     * 获取多语言变量值
-     * @param $string
-     * @return mixed
-     */
-    public static function getLang($string) {
-        if (!$string){
-            return $string;
-        }
-        $config = ConfigProvider::get();
-        $langGetFunction = $config["lang_get_function"];
-        if (empty($langGetFunction)){
-            return $string;
-        }
-        if (strpos($string, 'lang(') !== false) {
-            if (preg_match('#lang\((.*)\)#s', $string, $key) !== false){
-                $langKey = $key && count($key)>1 ? trim($key[1]):"";
-                if (!empty($langKey)){
-                    return $langGetFunction($langKey);
-                }
-            }
-        }
-        return $string;
-    }
-
-    /**
-     * 二维数组设置指定字段的多语言
-     * @param $array
-     * @param $field
-     * @return array
-     */
-    public static function getArrayLang($array,$field){
-        $data = [];
-        if (!empty($array) && is_array($array)){
-            foreach ($array as $item){
-                $item[$field] = static::getLang($item[$field]);
-                $data[]=$item;
-            }
-        }
-        return $data;
-    }
-
-
-}

+ 0 - 46
vendor/hg/apidoc/src/utils/Request.php

@@ -1,46 +0,0 @@
-<?php
-
-namespace hg\apidoc\utils;
-use Exception;
-class Request
-{
-    protected $get = [];
-
-    protected $post = [];
-
-    protected $method = "GET";
-
-    public function __construct()
-    {
-        $this->get = $_GET;
-        $this->post = $_POST;
-        $this->method = !empty($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:"";
-    }
-
-    public function get(){
-        return $this->get;
-    }
-
-    public function post(){
-        return $this->post;
-    }
-
-    public function input(){
-        $input = file_get_contents('php://input');
-        $inputObj = json_decode($input);
-        return Helper::objectToArray($inputObj);
-    }
-
-    public function param(){
-        $config = ConfigProvider::get();
-        if (!empty($config['request_params'])){
-            return $config['request_params'];
-        }
-        $method = !empty($this->method)?$this->method:"GET";
-        if ($method == "GET"){
-            return $this->get;
-        }
-        return $this->input();
-    }
-
-}

+ 3 - 0
vendor/symfony/class-loader/.gitignore

@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml

+ 145 - 0
vendor/symfony/class-loader/ApcClassLoader.php

@@ -0,0 +1,145 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader;
+
+@trigger_error('The '.__NAMESPACE__.'\ApcClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use `composer install --apcu-autoloader` instead.', \E_USER_DEPRECATED);
+
+/**
+ * ApcClassLoader implements a wrapping autoloader cached in APC for PHP 5.3.
+ *
+ * It expects an object implementing a findFile method to find the file. This
+ * allows using it as a wrapper around the other loaders of the component (the
+ * ClassLoader for instance) but also around any other autoloaders following
+ * this convention (the Composer one for instance).
+ *
+ *     // with a Symfony autoloader
+ *     use Symfony\Component\ClassLoader\ClassLoader;
+ *
+ *     $loader = new ClassLoader();
+ *     $loader->addPrefix('Symfony\Component', __DIR__.'/component');
+ *     $loader->addPrefix('Symfony',           __DIR__.'/framework');
+ *
+ *     // or with a Composer autoloader
+ *     use Composer\Autoload\ClassLoader;
+ *
+ *     $loader = new ClassLoader();
+ *     $loader->add('Symfony\Component', __DIR__.'/component');
+ *     $loader->add('Symfony',           __DIR__.'/framework');
+ *
+ *     $cachedLoader = new ApcClassLoader('my_prefix', $loader);
+ *
+ *     // activate the cached autoloader
+ *     $cachedLoader->register();
+ *
+ *     // eventually deactivate the non-cached loader if it was registered previously
+ *     // to be sure to use the cached one.
+ *     $loader->unregister();
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Kris Wallsmith <kris@symfony.com>
+ *
+ * @deprecated since version 3.3, to be removed in 4.0. Use `composer install --apcu-autoloader` instead.
+ */
+class ApcClassLoader
+{
+    private $prefix;
+
+    /**
+     * A class loader object that implements the findFile() method.
+     *
+     * @var object
+     */
+    protected $decorated;
+
+    /**
+     * @param string $prefix    The APC namespace prefix to use
+     * @param object $decorated A class loader object that implements the findFile() method
+     *
+     * @throws \RuntimeException
+     * @throws \InvalidArgumentException
+     */
+    public function __construct($prefix, $decorated)
+    {
+        if (!\function_exists('apcu_fetch')) {
+            throw new \RuntimeException('Unable to use ApcClassLoader as APC is not installed.');
+        }
+
+        if (!method_exists($decorated, 'findFile')) {
+            throw new \InvalidArgumentException('The class finder must implement a "findFile" method.');
+        }
+
+        $this->prefix = $prefix;
+        $this->decorated = $decorated;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register([$this, 'loadClass'], true, $prepend);
+    }
+
+    /**
+     * Unregisters this instance as an autoloader.
+     */
+    public function unregister()
+    {
+        spl_autoload_unregister([$this, 'loadClass']);
+    }
+
+    /**
+     * Loads the given class or interface.
+     *
+     * @param string $class The name of the class
+     *
+     * @return bool|null True, if loaded
+     */
+    public function loadClass($class)
+    {
+        if ($file = $this->findFile($class)) {
+            require $file;
+
+            return true;
+        }
+
+        return null;
+    }
+
+    /**
+     * Finds a file by class name while caching lookups to APC.
+     *
+     * @param string $class A class name to resolve to file
+     *
+     * @return string|null
+     */
+    public function findFile($class)
+    {
+        $file = apcu_fetch($this->prefix.$class, $success);
+
+        if (!$success) {
+            apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class) ?: null);
+        }
+
+        return $file;
+    }
+
+    /**
+     * Passes through all unknown calls onto the decorated object.
+     */
+    public function __call($method, $args)
+    {
+        return \call_user_func_array([$this->decorated, $method], $args);
+    }
+}

+ 41 - 0
vendor/symfony/class-loader/CHANGELOG.md

@@ -0,0 +1,41 @@
+CHANGELOG
+=========
+
+3.3.0
+-----
+
+ * deprecated the component: use Composer instead
+
+3.0.0
+-----
+
+ * The DebugClassLoader class has been removed
+ * The DebugUniversalClassLoader class has been removed
+ * The UniversalClassLoader class has been removed
+ * The ApcUniversalClassLoader class has been removed
+
+2.4.0
+-----
+
+ * deprecated the UniversalClassLoader in favor of the ClassLoader class instead
+ * deprecated the ApcUniversalClassLoader in favor of the ApcClassLoader class instead
+ * deprecated the DebugUniversalClassLoader in favor of the DebugClassLoader class from the Debug component
+ * deprecated the DebugClassLoader as it has been moved to the Debug component instead
+
+2.3.0
+-----
+
+ * added a WinCacheClassLoader for WinCache
+
+2.1.0
+-----
+
+ * added a DebugClassLoader able to wrap any autoloader providing a findFile
+   method
+ * added a new ApcClassLoader and XcacheClassLoader using composition to wrap
+   other loaders
+ * added a new ClassLoader which does not distinguish between namespaced and
+   pear-like classes (as the PEAR convention is a subset of PSR-0) and
+   supports using Composer's namespace maps
+ * added a class map generator
+ * added support for loading globally-installed PEAR packages

+ 453 - 0
vendor/symfony/class-loader/ClassCollectionLoader.php

@@ -0,0 +1,453 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader;
+
+if (\PHP_VERSION_ID >= 70000) {
+    @trigger_error('The '.__NAMESPACE__.'\ClassCollectionLoader class is deprecated since Symfony 3.3 and will be removed in 4.0.', \E_USER_DEPRECATED);
+}
+
+/**
+ * ClassCollectionLoader.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @deprecated since version 3.3, to be removed in 4.0.
+ */
+class ClassCollectionLoader
+{
+    private static $loaded;
+    private static $seen;
+    private static $useTokenizer = true;
+
+    /**
+     * Loads a list of classes and caches them in one big file.
+     *
+     * @param array  $classes    An array of classes to load
+     * @param string $cacheDir   A cache directory
+     * @param string $name       The cache name prefix
+     * @param bool   $autoReload Whether to flush the cache when the cache is stale or not
+     * @param bool   $adaptive   Whether to remove already declared classes or not
+     * @param string $extension  File extension of the resulting file
+     *
+     * @throws \InvalidArgumentException When class can't be loaded
+     */
+    public static function load($classes, $cacheDir, $name, $autoReload, $adaptive = false, $extension = '.php')
+    {
+        // each $name can only be loaded once per PHP process
+        if (isset(self::$loaded[$name])) {
+            return;
+        }
+
+        self::$loaded[$name] = true;
+
+        if ($adaptive) {
+            $declared = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
+
+            // don't include already declared classes
+            $classes = array_diff($classes, $declared);
+
+            // the cache is different depending on which classes are already declared
+            $name .= '-'.substr(hash('sha256', implode('|', $classes)), 0, 5);
+        }
+
+        $classes = array_unique($classes);
+
+        // cache the core classes
+        if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
+            throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s".', $cacheDir));
+        }
+        $cacheDir = rtrim(realpath($cacheDir) ?: $cacheDir, '/'.\DIRECTORY_SEPARATOR);
+        $cache = $cacheDir.'/'.$name.$extension;
+
+        // auto-reload
+        $reload = false;
+        if ($autoReload) {
+            $metadata = $cache.'.meta';
+            if (!is_file($metadata) || !is_file($cache)) {
+                $reload = true;
+            } else {
+                $time = filemtime($cache);
+                $meta = unserialize(file_get_contents($metadata));
+
+                sort($meta[1]);
+                sort($classes);
+
+                if ($meta[1] != $classes) {
+                    $reload = true;
+                } else {
+                    foreach ($meta[0] as $resource) {
+                        if (!is_file($resource) || filemtime($resource) > $time) {
+                            $reload = true;
+
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!$reload && file_exists($cache)) {
+            require_once $cache;
+
+            return;
+        }
+        if (!$adaptive) {
+            $declared = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
+        }
+
+        $files = self::inline($classes, $cache, $declared);
+
+        if ($autoReload) {
+            // save the resources
+            self::writeCacheFile($metadata, serialize([array_values($files), $classes]));
+        }
+    }
+
+    /**
+     * Generates a file where classes and their parents are inlined.
+     *
+     * @param array  $classes  An array of classes to load
+     * @param string $cache    The file where classes are inlined
+     * @param array  $excluded An array of classes that won't be inlined
+     *
+     * @return array The source map of inlined classes, with classes as keys and files as values
+     *
+     * @throws \RuntimeException When class can't be loaded
+     */
+    public static function inline($classes, $cache, array $excluded)
+    {
+        $declared = [];
+        foreach (self::getOrderedClasses($excluded) as $class) {
+            $declared[$class->getName()] = true;
+        }
+
+        // cache the core classes
+        $cacheDir = \dirname($cache);
+        if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
+            throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s".', $cacheDir));
+        }
+
+        $spacesRegex = '(?:\s*+(?:(?:\#|//)[^\n]*+\n|/\*(?:(?<!\*/).)++)?+)*+';
+        $dontInlineRegex = <<<REGEX
+            '(?:
+               ^<\?php\s.declare.\(.strict_types.=.1.\).;
+               | \b__halt_compiler.\(.\)
+               | \b__(?:DIR|FILE)__\b
+            )'isx
+REGEX;
+        $dontInlineRegex = str_replace('.', $spacesRegex, $dontInlineRegex);
+
+        $cacheDir = explode('/', str_replace(\DIRECTORY_SEPARATOR, '/', $cacheDir));
+        $files = [];
+        $content = '';
+        foreach (self::getOrderedClasses($classes) as $class) {
+            if (isset($declared[$class->getName()])) {
+                continue;
+            }
+            $declared[$class->getName()] = true;
+
+            $files[$class->getName()] = $file = $class->getFileName();
+            $c = file_get_contents($file);
+
+            if (preg_match($dontInlineRegex, $c)) {
+                $file = explode('/', str_replace(\DIRECTORY_SEPARATOR, '/', $file));
+
+                for ($i = 0; isset($file[$i], $cacheDir[$i]); ++$i) {
+                    if ($file[$i] !== $cacheDir[$i]) {
+                        break;
+                    }
+                }
+                if (1 >= $i) {
+                    $file = var_export(implode('/', $file), true);
+                } else {
+                    $file = \array_slice($file, $i);
+                    $file = str_repeat('../', \count($cacheDir) - $i).implode('/', $file);
+                    $file = '__DIR__.'.var_export('/'.$file, true);
+                }
+
+                $c = "\nnamespace {require $file;}";
+            } else {
+                $c = preg_replace(['/^\s*<\?php/', '/\?>\s*$/'], '', $c);
+
+                // fakes namespace declaration for global code
+                if (!$class->inNamespace()) {
+                    $c = "\nnamespace\n{\n".$c."\n}\n";
+                }
+
+                $c = self::fixNamespaceDeclarations('<?php '.$c);
+                $c = preg_replace('/^\s*<\?php/', '', $c);
+            }
+
+            $content .= $c;
+        }
+        self::writeCacheFile($cache, '<?php '.$content);
+
+        return $files;
+    }
+
+    /**
+     * Adds brackets around each namespace if it's not already the case.
+     *
+     * @param string $source Namespace string
+     *
+     * @return string Namespaces with brackets
+     */
+    public static function fixNamespaceDeclarations($source)
+    {
+        if (!\function_exists('token_get_all') || !self::$useTokenizer) {
+            if (preg_match('/(^|\s)namespace(.*?)\s*;/', $source)) {
+                $source = preg_replace('/(^|\s)namespace(.*?)\s*;/', "$1namespace$2\n{", $source)."}\n";
+            }
+
+            return $source;
+        }
+
+        $rawChunk = '';
+        $output = '';
+        $inNamespace = false;
+        $tokens = token_get_all($source);
+
+        $nsTokens = [\T_WHITESPACE => true, \T_NS_SEPARATOR => true, \T_STRING => true];
+        if (\defined('T_NAME_QUALIFIED')) {
+            $nsTokens[T_NAME_QUALIFIED] = true;
+        }
+
+        for ($i = 0; isset($tokens[$i]); ++$i) {
+            $token = $tokens[$i];
+            if (!isset($token[1]) || 'b"' === $token) {
+                $rawChunk .= $token;
+            } elseif (\in_array($token[0], [\T_COMMENT, \T_DOC_COMMENT])) {
+                // strip comments
+                continue;
+            } elseif (\T_NAMESPACE === $token[0]) {
+                if ($inNamespace) {
+                    $rawChunk .= "}\n";
+                }
+                $rawChunk .= $token[1];
+
+                // namespace name and whitespaces
+                while (isset($tokens[++$i][1], $nsTokens[$tokens[$i][0]])) {
+                    $rawChunk .= $tokens[$i][1];
+                }
+                if ('{' === $tokens[$i]) {
+                    $inNamespace = false;
+                    --$i;
+                } else {
+                    $rawChunk = rtrim($rawChunk)."\n{";
+                    $inNamespace = true;
+                }
+            } elseif (\T_START_HEREDOC === $token[0]) {
+                $output .= self::compressCode($rawChunk).$token[1];
+                do {
+                    $token = $tokens[++$i];
+                    $output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token;
+                } while (\T_END_HEREDOC !== $token[0]);
+                $output .= "\n";
+                $rawChunk = '';
+            } elseif (\T_CONSTANT_ENCAPSED_STRING === $token[0]) {
+                $output .= self::compressCode($rawChunk).$token[1];
+                $rawChunk = '';
+            } else {
+                $rawChunk .= $token[1];
+            }
+        }
+
+        if ($inNamespace) {
+            $rawChunk .= "}\n";
+        }
+
+        $output .= self::compressCode($rawChunk);
+
+        if (\PHP_VERSION_ID >= 70000) {
+            // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
+            unset($tokens, $rawChunk);
+            gc_mem_caches();
+        }
+
+        return $output;
+    }
+
+    /**
+     * This method is only useful for testing.
+     */
+    public static function enableTokenizer($bool)
+    {
+        self::$useTokenizer = (bool) $bool;
+    }
+
+    /**
+     * Strips leading & trailing ws, multiple EOL, multiple ws.
+     *
+     * @param string $code Original PHP code
+     *
+     * @return string compressed code
+     */
+    private static function compressCode($code)
+    {
+        return preg_replace(
+            ['/^\s+/m', '/\s+$/m', '/([\n\r]+ *[\n\r]+)+/', '/[ \t]+/'],
+            ['', '', "\n", ' '],
+            $code
+        );
+    }
+
+    /**
+     * Writes a cache file.
+     *
+     * @param string $file    Filename
+     * @param string $content Temporary file content
+     *
+     * @throws \RuntimeException when a cache file cannot be written
+     */
+    private static function writeCacheFile($file, $content)
+    {
+        $dir = \dirname($file);
+        if (!is_writable($dir)) {
+            throw new \RuntimeException(sprintf('Cache directory "%s" is not writable.', $dir));
+        }
+
+        $tmpFile = tempnam($dir, basename($file));
+
+        if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
+            @chmod($file, 0666 & ~umask());
+
+            return;
+        }
+
+        throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file));
+    }
+
+    /**
+     * Gets an ordered array of passed classes including all their dependencies.
+     *
+     * @return \ReflectionClass[] An array of sorted \ReflectionClass instances (dependencies added if needed)
+     *
+     * @throws \InvalidArgumentException When a class can't be loaded
+     */
+    private static function getOrderedClasses(array $classes)
+    {
+        $map = [];
+        self::$seen = [];
+        foreach ($classes as $class) {
+            try {
+                $reflectionClass = new \ReflectionClass($class);
+            } catch (\ReflectionException $e) {
+                throw new \InvalidArgumentException(sprintf('Unable to load class "%s".', $class));
+            }
+
+            $map = array_merge($map, self::getClassHierarchy($reflectionClass));
+        }
+
+        return $map;
+    }
+
+    private static function getClassHierarchy(\ReflectionClass $class)
+    {
+        if (isset(self::$seen[$class->getName()])) {
+            return [];
+        }
+
+        self::$seen[$class->getName()] = true;
+
+        $classes = [$class];
+        $parent = $class;
+        while (($parent = $parent->getParentClass()) && $parent->isUserDefined() && !isset(self::$seen[$parent->getName()])) {
+            self::$seen[$parent->getName()] = true;
+
+            array_unshift($classes, $parent);
+        }
+
+        $traits = [];
+
+        foreach ($classes as $c) {
+            foreach (self::resolveDependencies(self::computeTraitDeps($c), $c) as $trait) {
+                if ($trait !== $c) {
+                    $traits[] = $trait;
+                }
+            }
+        }
+
+        return array_merge(self::getInterfaces($class), $traits, $classes);
+    }
+
+    private static function getInterfaces(\ReflectionClass $class)
+    {
+        $classes = [];
+
+        foreach ($class->getInterfaces() as $interface) {
+            $classes = array_merge($classes, self::getInterfaces($interface));
+        }
+
+        if ($class->isUserDefined() && $class->isInterface() && !isset(self::$seen[$class->getName()])) {
+            self::$seen[$class->getName()] = true;
+
+            $classes[] = $class;
+        }
+
+        return $classes;
+    }
+
+    private static function computeTraitDeps(\ReflectionClass $class)
+    {
+        $traits = $class->getTraits();
+        $deps = [$class->getName() => $traits];
+        while ($trait = array_pop($traits)) {
+            if ($trait->isUserDefined() && !isset(self::$seen[$trait->getName()])) {
+                self::$seen[$trait->getName()] = true;
+                $traitDeps = $trait->getTraits();
+                $deps[$trait->getName()] = $traitDeps;
+                $traits = array_merge($traits, $traitDeps);
+            }
+        }
+
+        return $deps;
+    }
+
+    /**
+     * Dependencies resolution.
+     *
+     * This function does not check for circular dependencies as it should never
+     * occur with PHP traits.
+     *
+     * @param array            $tree       The dependency tree
+     * @param \ReflectionClass $node       The node
+     * @param \ArrayObject     $resolved   An array of already resolved dependencies
+     * @param \ArrayObject     $unresolved An array of dependencies to be resolved
+     *
+     * @return \ArrayObject The dependencies for the given node
+     *
+     * @throws \RuntimeException if a circular dependency is detected
+     */
+    private static function resolveDependencies(array $tree, $node, \ArrayObject $resolved = null, \ArrayObject $unresolved = null)
+    {
+        if (null === $resolved) {
+            $resolved = new \ArrayObject();
+        }
+        if (null === $unresolved) {
+            $unresolved = new \ArrayObject();
+        }
+        $nodeName = $node->getName();
+
+        if (isset($tree[$nodeName])) {
+            $unresolved[$nodeName] = $node;
+            foreach ($tree[$nodeName] as $dependency) {
+                if (!$resolved->offsetExists($dependency->getName())) {
+                    self::resolveDependencies($tree, $dependency, $resolved, $unresolved);
+                }
+            }
+            $resolved[$nodeName] = $node;
+            unset($unresolved[$nodeName]);
+        }
+
+        return $resolved;
+    }
+}

+ 211 - 0
vendor/symfony/class-loader/ClassLoader.php

@@ -0,0 +1,211 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader;
+
+@trigger_error('The '.__NAMESPACE__.'\ClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use Composer instead.', \E_USER_DEPRECATED);
+
+/**
+ * ClassLoader implements an PSR-0 class loader.
+ *
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
+ *
+ *     $loader = new ClassLoader();
+ *
+ *     // register classes with namespaces
+ *     $loader->addPrefix('Symfony\Component', __DIR__.'/component');
+ *     $loader->addPrefix('Symfony',           __DIR__.'/framework');
+ *
+ *     // activate the autoloader
+ *     $loader->register();
+ *
+ *     // to enable searching the include path (e.g. for PEAR packages)
+ *     $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @deprecated since version 3.3, to be removed in 4.0.
+ */
+class ClassLoader
+{
+    private $prefixes = [];
+    private $fallbackDirs = [];
+    private $useIncludePath = false;
+
+    /**
+     * Returns prefixes.
+     *
+     * @return array
+     */
+    public function getPrefixes()
+    {
+        return $this->prefixes;
+    }
+
+    /**
+     * Returns fallback directories.
+     *
+     * @return array
+     */
+    public function getFallbackDirs()
+    {
+        return $this->fallbackDirs;
+    }
+
+    /**
+     * Adds prefixes.
+     *
+     * @param array $prefixes Prefixes to add
+     */
+    public function addPrefixes(array $prefixes)
+    {
+        foreach ($prefixes as $prefix => $path) {
+            $this->addPrefix($prefix, $path);
+        }
+    }
+
+    /**
+     * Registers a set of classes.
+     *
+     * @param string       $prefix The classes prefix
+     * @param array|string $paths  The location(s) of the classes
+     */
+    public function addPrefix($prefix, $paths)
+    {
+        if (!$prefix) {
+            foreach ((array) $paths as $path) {
+                $this->fallbackDirs[] = $path;
+            }
+
+            return;
+        }
+        if (isset($this->prefixes[$prefix])) {
+            if (\is_array($paths)) {
+                $this->prefixes[$prefix] = array_unique(array_merge(
+                    $this->prefixes[$prefix],
+                    $paths
+                ));
+            } elseif (!\in_array($paths, $this->prefixes[$prefix])) {
+                $this->prefixes[$prefix][] = $paths;
+            }
+        } else {
+            $this->prefixes[$prefix] = array_unique((array) $paths);
+        }
+    }
+
+    /**
+     * Turns on searching the include for class files.
+     *
+     * @param bool $useIncludePath
+     */
+    public function setUseIncludePath($useIncludePath)
+    {
+        $this->useIncludePath = (bool) $useIncludePath;
+    }
+
+    /**
+     * Can be used to check if the autoloader uses the include path to check
+     * for classes.
+     *
+     * @return bool
+     */
+    public function getUseIncludePath()
+    {
+        return $this->useIncludePath;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register([$this, 'loadClass'], true, $prepend);
+    }
+
+    /**
+     * Unregisters this instance as an autoloader.
+     */
+    public function unregister()
+    {
+        spl_autoload_unregister([$this, 'loadClass']);
+    }
+
+    /**
+     * Loads the given class or interface.
+     *
+     * @param string $class The name of the class
+     *
+     * @return bool|null True, if loaded
+     */
+    public function loadClass($class)
+    {
+        if ($file = $this->findFile($class)) {
+            require $file;
+
+            return true;
+        }
+
+        return null;
+    }
+
+    /**
+     * Finds the path to the file where the class is defined.
+     *
+     * @param string $class The name of the class
+     *
+     * @return string|null The path, if found
+     */
+    public function findFile($class)
+    {
+        if (false !== $pos = strrpos($class, '\\')) {
+            // namespaced class name
+            $classPath = str_replace('\\', \DIRECTORY_SEPARATOR, substr($class, 0, $pos)).\DIRECTORY_SEPARATOR;
+            $className = substr($class, $pos + 1);
+        } else {
+            // PEAR-like class name
+            $classPath = null;
+            $className = $class;
+        }
+
+        $classPath .= str_replace('_', \DIRECTORY_SEPARATOR, $className).'.php';
+
+        foreach ($this->prefixes as $prefix => $dirs) {
+            if ($class === strstr($class, $prefix)) {
+                foreach ($dirs as $dir) {
+                    if (file_exists($dir.\DIRECTORY_SEPARATOR.$classPath)) {
+                        return $dir.\DIRECTORY_SEPARATOR.$classPath;
+                    }
+                }
+            }
+        }
+
+        foreach ($this->fallbackDirs as $dir) {
+            if (file_exists($dir.\DIRECTORY_SEPARATOR.$classPath)) {
+                return $dir.\DIRECTORY_SEPARATOR.$classPath;
+            }
+        }
+
+        if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
+            return $file;
+        }
+
+        return null;
+    }
+}

+ 165 - 0
vendor/symfony/class-loader/ClassMapGenerator.php

@@ -0,0 +1,165 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader;
+
+@trigger_error('The '.__NAMESPACE__.'\ClassMapGenerator class is deprecated since Symfony 3.3 and will be removed in 4.0. Use Composer instead.', \E_USER_DEPRECATED);
+
+/**
+ * ClassMapGenerator.
+ *
+ * @author Gyula Sallai <salla016@gmail.com>
+ *
+ * @deprecated since version 3.3, to be removed in 4.0.
+ */
+class ClassMapGenerator
+{
+    /**
+     * Generate a class map file.
+     *
+     * @param array|string $dirs Directories or a single path to search in
+     * @param string       $file The name of the class map file
+     */
+    public static function dump($dirs, $file)
+    {
+        $dirs = (array) $dirs;
+        $maps = [];
+
+        foreach ($dirs as $dir) {
+            $maps = array_merge($maps, static::createMap($dir));
+        }
+
+        file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
+    }
+
+    /**
+     * Iterate over all files in the given directory searching for classes.
+     *
+     * @param \Iterator|string $dir The directory to search in or an iterator
+     *
+     * @return array A class map array
+     */
+    public static function createMap($dir)
+    {
+        if (\is_string($dir)) {
+            $dir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
+        }
+
+        $map = [];
+
+        foreach ($dir as $file) {
+            if (!$file->isFile()) {
+                continue;
+            }
+
+            $path = $file->getRealPath() ?: $file->getPathname();
+
+            if ('php' !== pathinfo($path, \PATHINFO_EXTENSION)) {
+                continue;
+            }
+
+            $classes = self::findClasses($path);
+
+            if (\PHP_VERSION_ID >= 70000) {
+                // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
+                gc_mem_caches();
+            }
+
+            foreach ($classes as $class) {
+                $map[$class] = $path;
+            }
+        }
+
+        return $map;
+    }
+
+    /**
+     * Extract the classes in the given file.
+     *
+     * @param string $path The file to check
+     *
+     * @return array The found classes
+     */
+    private static function findClasses($path)
+    {
+        $contents = file_get_contents($path);
+        $tokens = token_get_all($contents);
+
+        $nsTokens = [\T_STRING => true, \T_NS_SEPARATOR => true];
+        if (\defined('T_NAME_QUALIFIED')) {
+            $nsTokens[T_NAME_QUALIFIED] = true;
+        }
+
+        $classes = [];
+
+        $namespace = '';
+        for ($i = 0; isset($tokens[$i]); ++$i) {
+            $token = $tokens[$i];
+
+            if (!isset($token[1])) {
+                continue;
+            }
+
+            $class = '';
+
+            switch ($token[0]) {
+                case \T_NAMESPACE:
+                    $namespace = '';
+                    // If there is a namespace, extract it
+                    while (isset($tokens[++$i][1])) {
+                        if (isset($nsTokens[$tokens[$i][0]])) {
+                            $namespace .= $tokens[$i][1];
+                        }
+                    }
+                    $namespace .= '\\';
+                    break;
+                case \T_CLASS:
+                case \T_INTERFACE:
+                case \T_TRAIT:
+                    // Skip usage of ::class constant
+                    $isClassConstant = false;
+                    for ($j = $i - 1; $j > 0; --$j) {
+                        if (!isset($tokens[$j][1])) {
+                            break;
+                        }
+
+                        if (\T_DOUBLE_COLON === $tokens[$j][0]) {
+                            $isClassConstant = true;
+                            break;
+                        } elseif (!\in_array($tokens[$j][0], [\T_WHITESPACE, \T_DOC_COMMENT, \T_COMMENT])) {
+                            break;
+                        }
+                    }
+
+                    if ($isClassConstant) {
+                        break;
+                    }
+
+                    // Find the classname
+                    while (isset($tokens[++$i][1])) {
+                        $t = $tokens[$i];
+                        if (\T_STRING === $t[0]) {
+                            $class .= $t[1];
+                        } elseif ('' !== $class && \T_WHITESPACE === $t[0]) {
+                            break;
+                        }
+                    }
+
+                    $classes[] = ltrim($namespace.$class, '\\');
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        return $classes;
+    }
+}

+ 19 - 0
vendor/symfony/class-loader/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2004-2020 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 68 - 0
vendor/symfony/class-loader/MapClassLoader.php

@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader;
+
+@trigger_error('The '.__NAMESPACE__.'\MapClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use Composer instead.', \E_USER_DEPRECATED);
+
+/**
+ * A class loader that uses a mapping file to look up paths.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @deprecated since version 3.3, to be removed in 4.0.
+ */
+class MapClassLoader
+{
+    private $map = [];
+
+    /**
+     * @param array $map A map where keys are classes and values the absolute file path
+     */
+    public function __construct(array $map)
+    {
+        $this->map = $map;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register([$this, 'loadClass'], true, $prepend);
+    }
+
+    /**
+     * Loads the given class or interface.
+     *
+     * @param string $class The name of the class
+     */
+    public function loadClass($class)
+    {
+        if (isset($this->map[$class])) {
+            require $this->map[$class];
+        }
+    }
+
+    /**
+     * Finds the path to the file where the class is defined.
+     *
+     * @param string $class The name of the class
+     *
+     * @return string|null The path, if found
+     */
+    public function findFile($class)
+    {
+        return isset($this->map[$class]) ? $this->map[$class] : null;
+    }
+}

+ 96 - 0
vendor/symfony/class-loader/Psr4ClassLoader.php

@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader;
+
+@trigger_error('The '.__NAMESPACE__.'\Psr4ClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use Composer instead.', \E_USER_DEPRECATED);
+
+/**
+ * A PSR-4 compatible class loader.
+ *
+ * See http://www.php-fig.org/psr/psr-4/
+ *
+ * @author Alexander M. Turek <me@derrabus.de>
+ *
+ * @deprecated since version 3.3, to be removed in 4.0.
+ */
+class Psr4ClassLoader
+{
+    private $prefixes = [];
+
+    /**
+     * @param string $prefix
+     * @param string $baseDir
+     */
+    public function addPrefix($prefix, $baseDir)
+    {
+        $prefix = trim($prefix, '\\').'\\';
+        $baseDir = rtrim($baseDir, \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
+        $this->prefixes[] = [$prefix, $baseDir];
+    }
+
+    /**
+     * @param string $class
+     *
+     * @return string|null
+     */
+    public function findFile($class)
+    {
+        $class = ltrim($class, '\\');
+
+        foreach ($this->prefixes as list($currentPrefix, $currentBaseDir)) {
+            if (0 === strpos($class, $currentPrefix)) {
+                $classWithoutPrefix = substr($class, \strlen($currentPrefix));
+                $file = $currentBaseDir.str_replace('\\', \DIRECTORY_SEPARATOR, $classWithoutPrefix).'.php';
+                if (file_exists($file)) {
+                    return $file;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @param string $class
+     *
+     * @return bool
+     */
+    public function loadClass($class)
+    {
+        $file = $this->findFile($class);
+        if (null !== $file) {
+            require $file;
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param bool $prepend
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register([$this, 'loadClass'], true, $prepend);
+    }
+
+    /**
+     * Removes this instance from the registered autoloaders.
+     */
+    public function unregister()
+    {
+        spl_autoload_unregister([$this, 'loadClass']);
+    }
+}

+ 14 - 0
vendor/symfony/class-loader/README.md

@@ -0,0 +1,14 @@
+ClassLoader Component
+=====================
+
+The ClassLoader component provides tools to autoload your classes and cache
+their locations for performance.
+
+Resources
+---------
+
+  * [Documentation](https://symfony.com/doc/current/components/class_loader.html)
+  * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+  * [Report issues](https://github.com/symfony/symfony/issues) and
+    [send Pull Requests](https://github.com/symfony/symfony/pulls)
+    in the [main Symfony repository](https://github.com/symfony/symfony)

+ 200 - 0
vendor/symfony/class-loader/Tests/ApcClassLoaderTest.php

@@ -0,0 +1,200 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\ClassLoader\ApcClassLoader;
+use Symfony\Component\ClassLoader\ClassLoader;
+
+/**
+ * @group legacy
+ */
+class ApcClassLoaderTest extends TestCase
+{
+    protected function setUp()
+    {
+        if (!(filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) && filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) {
+            $this->markTestSkipped('The apc extension is not enabled.');
+        } else {
+            apcu_clear_cache();
+        }
+    }
+
+    protected function tearDown()
+    {
+        if (filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) && filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
+            apcu_clear_cache();
+        }
+    }
+
+    public function testConstructor()
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Apc\Namespaced', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+
+        $loader = new ApcClassLoader('test.prefix.', $loader);
+
+        $this->assertEquals($loader->findFile('\Apc\Namespaced\FooBar'), apcu_fetch('test.prefix.\Apc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument');
+    }
+
+    /**
+     * @dataProvider getLoadClassTests
+     */
+    public function testLoadClass($className, $testClassName, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Apc\Namespaced', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Apc_Pearlike_', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+
+        $loader = new ApcClassLoader('test.prefix.', $loader);
+        $loader->loadClass($testClassName);
+        $this->assertTrue(class_exists($className), $message);
+    }
+
+    public function getLoadClassTests()
+    {
+        return [
+           ['\\Apc\\Namespaced\\Foo', 'Apc\\Namespaced\\Foo',   '->loadClass() loads Apc\Namespaced\Foo class'],
+           ['Apc_Pearlike_Foo',    'Apc_Pearlike_Foo',      '->loadClass() loads Apc_Pearlike_Foo class'],
+        ];
+    }
+
+    /**
+     * @dataProvider getLoadClassFromFallbackTests
+     */
+    public function testLoadClassFromFallback($className, $testClassName, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Apc\Namespaced', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Apc_Pearlike_', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('', [__DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/fallback']);
+
+        $loader = new ApcClassLoader('test.prefix.fallback', $loader);
+        $loader->loadClass($testClassName);
+
+        $this->assertTrue(class_exists($className), $message);
+    }
+
+    public function getLoadClassFromFallbackTests()
+    {
+        return [
+           ['\\Apc\\Namespaced\\Baz',    'Apc\\Namespaced\\Baz',    '->loadClass() loads Apc\Namespaced\Baz class'],
+           ['Apc_Pearlike_Baz',       'Apc_Pearlike_Baz',       '->loadClass() loads Apc_Pearlike_Baz class'],
+           ['\\Apc\\Namespaced\\FooBar', 'Apc\\Namespaced\\FooBar', '->loadClass() loads Apc\Namespaced\Baz class from fallback dir'],
+           ['Apc_Pearlike_FooBar',    'Apc_Pearlike_FooBar',    '->loadClass() loads Apc_Pearlike_Baz class from fallback dir'],
+       ];
+    }
+
+    /**
+     * @dataProvider getLoadClassNamespaceCollisionTests
+     */
+    public function testLoadClassNamespaceCollision($namespaces, $className, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefixes($namespaces);
+
+        $loader = new ApcClassLoader('test.prefix.collision.', $loader);
+        $loader->loadClass($className);
+
+        $this->assertTrue(class_exists($className), $message);
+    }
+
+    public function getLoadClassNamespaceCollisionTests()
+    {
+        return [
+           [
+               [
+                   'Apc\\NamespaceCollision\\A' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+               ],
+               'Apc\NamespaceCollision\A\Foo',
+               '->loadClass() loads NamespaceCollision\A\Foo from alpha.',
+           ],
+           [
+               [
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+                   'Apc\\NamespaceCollision\\A' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+               ],
+               'Apc\NamespaceCollision\A\Bar',
+               '->loadClass() loads NamespaceCollision\A\Bar from alpha.',
+           ],
+           [
+               [
+                   'Apc\\NamespaceCollision\\A' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+               ],
+               'Apc\NamespaceCollision\A\B\Foo',
+               '->loadClass() loads NamespaceCollision\A\B\Foo from beta.',
+           ],
+           [
+               [
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+                   'Apc\\NamespaceCollision\\A' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+               ],
+               'Apc\NamespaceCollision\A\B\Bar',
+               '->loadClass() loads NamespaceCollision\A\B\Bar from beta.',
+           ],
+        ];
+    }
+
+    /**
+     * @dataProvider getLoadClassPrefixCollisionTests
+     */
+    public function testLoadClassPrefixCollision($prefixes, $className, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefixes($prefixes);
+
+        $loader = new ApcClassLoader('test.prefix.collision.', $loader);
+        $loader->loadClass($className);
+
+        $this->assertTrue(class_exists($className), $message);
+    }
+
+    public function getLoadClassPrefixCollisionTests()
+    {
+        return [
+           [
+               [
+                   'ApcPrefixCollision_A_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+                   'ApcPrefixCollision_A_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+               ],
+               'ApcPrefixCollision_A_Foo',
+               '->loadClass() loads ApcPrefixCollision_A_Foo from alpha.',
+           ],
+           [
+               [
+                   'ApcPrefixCollision_A_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+                   'ApcPrefixCollision_A_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+               ],
+               'ApcPrefixCollision_A_Bar',
+               '->loadClass() loads ApcPrefixCollision_A_Bar from alpha.',
+           ],
+           [
+               [
+                   'ApcPrefixCollision_A_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+                   'ApcPrefixCollision_A_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+               ],
+               'ApcPrefixCollision_A_B_Foo',
+               '->loadClass() loads ApcPrefixCollision_A_B_Foo from beta.',
+           ],
+           [
+               [
+                   'ApcPrefixCollision_A_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+                   'ApcPrefixCollision_A_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+               ],
+               'ApcPrefixCollision_A_B_Bar',
+               '->loadClass() loads ApcPrefixCollision_A_B_Bar from beta.',
+           ],
+        ];
+    }
+}

+ 317 - 0
vendor/symfony/class-loader/Tests/ClassCollectionLoaderTest.php

@@ -0,0 +1,317 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\ClassLoader\ClassCollectionLoader;
+use Symfony\Component\ClassLoader\Tests\Fixtures\DeclaredClass;
+use Symfony\Component\ClassLoader\Tests\Fixtures\WarmedClass;
+
+require_once __DIR__.'/Fixtures/ClassesWithParents/GInterface.php';
+require_once __DIR__.'/Fixtures/ClassesWithParents/CInterface.php';
+require_once __DIR__.'/Fixtures/ClassesWithParents/B.php';
+require_once __DIR__.'/Fixtures/ClassesWithParents/A.php';
+
+/**
+ * @group legacy
+ */
+class ClassCollectionLoaderTest extends TestCase
+{
+    public function testTraitDependencies()
+    {
+        require_once __DIR__.'/Fixtures/deps/traits.php';
+
+        $r = new \ReflectionClass('Symfony\Component\ClassLoader\ClassCollectionLoader');
+        $m = $r->getMethod('getOrderedClasses');
+        $m->setAccessible(true);
+
+        $ordered = $m->invoke(null, ['CTFoo']);
+
+        $this->assertEquals(
+            ['TD', 'TC', 'TB', 'TA', 'TZ', 'CTFoo'],
+            array_map(function ($class) { return $class->getName(); }, $ordered)
+        );
+
+        $ordered = $m->invoke(null, ['CTBar']);
+
+        $this->assertEquals(
+            ['TD', 'TZ', 'TC', 'TB', 'TA', 'CTBar'],
+            array_map(function ($class) { return $class->getName(); }, $ordered)
+        );
+    }
+
+    /**
+     * @dataProvider getDifferentOrders
+     */
+    public function testClassReordering(array $classes)
+    {
+        $expected = [
+            'ClassesWithParents\\GInterface',
+            'ClassesWithParents\\CInterface',
+            'ClassesWithParents\\B',
+            'ClassesWithParents\\A',
+        ];
+
+        $r = new \ReflectionClass('Symfony\Component\ClassLoader\ClassCollectionLoader');
+        $m = $r->getMethod('getOrderedClasses');
+        $m->setAccessible(true);
+
+        $ordered = $m->invoke(null, $classes);
+
+        $this->assertEquals($expected, array_map(function ($class) { return $class->getName(); }, $ordered));
+    }
+
+    public function getDifferentOrders()
+    {
+        return [
+            [[
+                'ClassesWithParents\\A',
+                'ClassesWithParents\\CInterface',
+                'ClassesWithParents\\GInterface',
+                'ClassesWithParents\\B',
+            ]],
+            [[
+                'ClassesWithParents\\B',
+                'ClassesWithParents\\A',
+                'ClassesWithParents\\CInterface',
+            ]],
+            [[
+                'ClassesWithParents\\CInterface',
+                'ClassesWithParents\\B',
+                'ClassesWithParents\\A',
+            ]],
+            [[
+                'ClassesWithParents\\A',
+            ]],
+        ];
+    }
+
+    /**
+     * @dataProvider getDifferentOrdersForTraits
+     */
+    public function testClassWithTraitsReordering(array $classes)
+    {
+        require_once __DIR__.'/Fixtures/ClassesWithParents/ATrait.php';
+        require_once __DIR__.'/Fixtures/ClassesWithParents/BTrait.php';
+        require_once __DIR__.'/Fixtures/ClassesWithParents/CTrait.php';
+        require_once __DIR__.'/Fixtures/ClassesWithParents/D.php';
+        require_once __DIR__.'/Fixtures/ClassesWithParents/E.php';
+
+        $expected = [
+            'ClassesWithParents\\GInterface',
+            'ClassesWithParents\\CInterface',
+            'ClassesWithParents\\ATrait',
+            'ClassesWithParents\\BTrait',
+            'ClassesWithParents\\CTrait',
+            'ClassesWithParents\\B',
+            'ClassesWithParents\\A',
+            'ClassesWithParents\\D',
+            'ClassesWithParents\\E',
+        ];
+
+        $r = new \ReflectionClass('Symfony\Component\ClassLoader\ClassCollectionLoader');
+        $m = $r->getMethod('getOrderedClasses');
+        $m->setAccessible(true);
+
+        $ordered = $m->invoke(null, $classes);
+
+        $this->assertEquals($expected, array_map(function ($class) { return $class->getName(); }, $ordered));
+    }
+
+    public function getDifferentOrdersForTraits()
+    {
+        return [
+            [[
+                'ClassesWithParents\\E',
+                'ClassesWithParents\\ATrait',
+            ]],
+            [[
+                'ClassesWithParents\\E',
+            ]],
+        ];
+    }
+
+    public function testFixClassWithTraitsOrdering()
+    {
+        require_once __DIR__.'/Fixtures/ClassesWithParents/CTrait.php';
+        require_once __DIR__.'/Fixtures/ClassesWithParents/F.php';
+        require_once __DIR__.'/Fixtures/ClassesWithParents/G.php';
+
+        $classes = [
+            'ClassesWithParents\\F',
+            'ClassesWithParents\\G',
+        ];
+
+        $expected = [
+            'ClassesWithParents\\CTrait',
+            'ClassesWithParents\\F',
+            'ClassesWithParents\\G',
+        ];
+
+        $r = new \ReflectionClass('Symfony\Component\ClassLoader\ClassCollectionLoader');
+        $m = $r->getMethod('getOrderedClasses');
+        $m->setAccessible(true);
+
+        $ordered = $m->invoke(null, $classes);
+
+        $this->assertEquals($expected, array_map(function ($class) { return $class->getName(); }, $ordered));
+    }
+
+    /**
+     * @dataProvider getFixNamespaceDeclarationsData
+     */
+    public function testFixNamespaceDeclarations($source, $expected)
+    {
+        $this->assertEquals('<?php '.$expected, ClassCollectionLoader::fixNamespaceDeclarations('<?php '.$source));
+    }
+
+    public function getFixNamespaceDeclarationsData()
+    {
+        return [
+            ["namespace;\nclass Foo {}\n", "namespace\n{\nclass Foo {}\n}"],
+            ["namespace Foo;\nclass Foo {}\n", "namespace Foo\n{\nclass Foo {}\n}"],
+            ["namespace   Bar ;\nclass Foo {}\n", "namespace Bar\n{\nclass Foo {}\n}"],
+            ["namespace Foo\Bar;\nclass Foo {}\n", "namespace Foo\Bar\n{\nclass Foo {}\n}"],
+            ["namespace Foo\Bar\Bar\n{\nclass Foo {}\n}\n", "namespace Foo\Bar\Bar\n{\nclass Foo {}\n}"],
+            ["namespace\n{\nclass Foo {}\n}\n", "namespace\n{\nclass Foo {}\n}"],
+        ];
+    }
+
+    /**
+     * @dataProvider getFixNamespaceDeclarationsDataWithoutTokenizer
+     */
+    public function testFixNamespaceDeclarationsWithoutTokenizer($source, $expected)
+    {
+        ClassCollectionLoader::enableTokenizer(false);
+        $this->assertEquals('<?php '.$expected, ClassCollectionLoader::fixNamespaceDeclarations('<?php '.$source));
+        ClassCollectionLoader::enableTokenizer(true);
+    }
+
+    public function getFixNamespaceDeclarationsDataWithoutTokenizer()
+    {
+        return [
+            ["namespace;\nclass Foo {}\n", "namespace\n{\nclass Foo {}\n}\n"],
+            ["namespace Foo;\nclass Foo {}\n", "namespace Foo\n{\nclass Foo {}\n}\n"],
+            ["namespace   Bar ;\nclass Foo {}\n", "namespace   Bar\n{\nclass Foo {}\n}\n"],
+            ["namespace Foo\Bar;\nclass Foo {}\n", "namespace Foo\Bar\n{\nclass Foo {}\n}\n"],
+            ["namespace Foo\Bar\Bar\n{\nclass Foo {}\n}\n", "namespace Foo\Bar\Bar\n{\nclass Foo {}\n}\n"],
+            ["\nnamespace\n{\nclass Foo {}\n\$namespace=123;}\n", "\nnamespace\n{\nclass Foo {}\n\$namespace=123;}\n"],
+        ];
+    }
+
+    public function testUnableToLoadClassException()
+    {
+        $this->expectException('InvalidArgumentException');
+        if (is_file($file = sys_get_temp_dir().'/foo.php')) {
+            unlink($file);
+        }
+
+        ClassCollectionLoader::load(['SomeNotExistingClass'], sys_get_temp_dir(), 'foo', false);
+    }
+
+    public function testCommentStripping()
+    {
+        if (is_file($file = __DIR__.'/bar.php')) {
+            unlink($file);
+        }
+        spl_autoload_register($r = function ($class) {
+            if (0 === strpos($class, 'Namespaced') || 0 === strpos($class, 'Pearlike_')) {
+                @require_once __DIR__.'/Fixtures/'.str_replace(['\\', '_'], '/', $class).'.php';
+            }
+        });
+
+        $strictTypes = \defined('HHVM_VERSION') ? '' : "\nnamespace {require __DIR__.'/Fixtures/Namespaced/WithStrictTypes.php';}";
+
+        ClassCollectionLoader::load(
+            ['Namespaced\\WithComments', 'Pearlike_WithComments', 'Namespaced\\WithDirMagic', 'Namespaced\\WithFileMagic', 'Namespaced\\WithHaltCompiler', $strictTypes ? 'Namespaced\\WithStrictTypes' : 'Namespaced\\WithComments'],
+            __DIR__,
+            'bar',
+            false
+        );
+
+        spl_autoload_unregister($r);
+
+        $this->assertEquals(<<<'EOF'
+namespace Namespaced
+{
+class WithComments
+{
+public static $loaded = true;
+}
+$string ='string should not be   modified {$string}';
+$heredoc = (<<<HD
+
+
+Heredoc should not be   modified {$string}
+
+
+HD
+);
+$nowdoc =<<<'ND'
+
+
+Nowdoc should not be   modified {$string}
+
+
+ND
+;
+}
+namespace
+{
+class Pearlike_WithComments
+{
+public static $loaded = true;
+}
+}
+namespace {require __DIR__.'/Fixtures/Namespaced/WithDirMagic.php';}
+namespace {require __DIR__.'/Fixtures/Namespaced/WithFileMagic.php';}
+namespace {require __DIR__.'/Fixtures/Namespaced/WithHaltCompiler.php';}
+EOF
+            .$strictTypes,
+            str_replace(["<?php \n", '\\\\'], ['', '/'], file_get_contents($file))
+        );
+
+        unlink($file);
+    }
+
+    public function testInline()
+    {
+        $this->assertTrue(class_exists(WarmedClass::class, true));
+
+        @unlink($cache = sys_get_temp_dir().'/inline.php');
+
+        $classes = [WarmedClass::class];
+        $excluded = [DeclaredClass::class];
+
+        ClassCollectionLoader::inline($classes, $cache, $excluded);
+
+        $this->assertSame(<<<'EOTXT'
+<?php 
+namespace Symfony\Component\ClassLoader\Tests\Fixtures
+{
+interface WarmedInterface
+{
+}
+}
+namespace Symfony\Component\ClassLoader\Tests\Fixtures
+{
+class WarmedClass extends DeclaredClass implements WarmedInterface
+{
+}
+}
+EOTXT
+            , file_get_contents($cache)
+        );
+
+        unlink($cache);
+    }
+}

+ 238 - 0
vendor/symfony/class-loader/Tests/ClassLoaderTest.php

@@ -0,0 +1,238 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\ClassLoader\ClassLoader;
+
+/**
+ * @group legacy
+ */
+class ClassLoaderTest extends TestCase
+{
+    public function testGetPrefixes()
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Foo', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Bar', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Bas', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $prefixes = $loader->getPrefixes();
+        $this->assertArrayHasKey('Foo', $prefixes);
+        $this->assertArrayNotHasKey('Foo1', $prefixes);
+        $this->assertArrayHasKey('Bar', $prefixes);
+        $this->assertArrayHasKey('Bas', $prefixes);
+    }
+
+    public function testGetFallbackDirs()
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix(null, __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix(null, __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $fallback_dirs = $loader->getFallbackDirs();
+        $this->assertCount(2, $fallback_dirs);
+    }
+
+    /**
+     * @dataProvider getLoadClassTests
+     */
+    public function testLoadClass($className, $testClassName, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Namespaced2\\', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Pearlike2_', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->loadClass($testClassName);
+        $this->assertTrue(class_exists($className), $message);
+    }
+
+    public function getLoadClassTests()
+    {
+        return [
+            ['\\Namespaced2\\Foo', 'Namespaced2\\Foo',   '->loadClass() loads Namespaced2\Foo class'],
+            ['\\Pearlike2_Foo',    'Pearlike2_Foo',      '->loadClass() loads Pearlike2_Foo class'],
+        ];
+    }
+
+    /**
+     * @dataProvider getLoadNonexistentClassTests
+     */
+    public function testLoadNonexistentClass($className, $testClassName, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Namespaced2\\', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Pearlike2_', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->loadClass($testClassName);
+        $this->assertFalse(class_exists($className), $message);
+    }
+
+    public function getLoadNonexistentClassTests()
+    {
+        return [
+            ['\\Pearlike3_Bar', '\\Pearlike3_Bar', '->loadClass() loads non existing Pearlike3_Bar class with a leading slash'],
+        ];
+    }
+
+    public function testAddPrefixSingle()
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Foo', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Foo', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $prefixes = $loader->getPrefixes();
+        $this->assertArrayHasKey('Foo', $prefixes);
+        $this->assertCount(1, $prefixes['Foo']);
+    }
+
+    public function testAddPrefixesSingle()
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefixes(['Foo' => ['foo', 'foo']]);
+        $loader->addPrefixes(['Foo' => ['foo']]);
+        $prefixes = $loader->getPrefixes();
+        $this->assertArrayHasKey('Foo', $prefixes);
+        $this->assertCount(1, $prefixes['Foo'], print_r($prefixes, true));
+    }
+
+    public function testAddPrefixMulti()
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Foo', 'foo');
+        $loader->addPrefix('Foo', 'bar');
+        $prefixes = $loader->getPrefixes();
+        $this->assertArrayHasKey('Foo', $prefixes);
+        $this->assertCount(2, $prefixes['Foo']);
+        $this->assertContains('foo', $prefixes['Foo']);
+        $this->assertContains('bar', $prefixes['Foo']);
+    }
+
+    public function testUseIncludePath()
+    {
+        $loader = new ClassLoader();
+        $this->assertFalse($loader->getUseIncludePath());
+
+        $this->assertNull($loader->findFile('Foo'));
+
+        $includePath = get_include_path();
+
+        $loader->setUseIncludePath(true);
+        $this->assertTrue($loader->getUseIncludePath());
+
+        set_include_path(__DIR__.'/Fixtures/includepath'.\PATH_SEPARATOR.$includePath);
+
+        $this->assertEquals(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'includepath'.\DIRECTORY_SEPARATOR.'Foo.php', $loader->findFile('Foo'));
+
+        set_include_path($includePath);
+    }
+
+    /**
+     * @dataProvider getLoadClassFromFallbackTests
+     */
+    public function testLoadClassFromFallback($className, $testClassName, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefix('Namespaced2\\', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('Pearlike2_', __DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
+        $loader->addPrefix('', [__DIR__.\DIRECTORY_SEPARATOR.'Fixtures/fallback']);
+        $loader->loadClass($testClassName);
+        $this->assertTrue(class_exists($className), $message);
+    }
+
+    public function getLoadClassFromFallbackTests()
+    {
+        return [
+            ['\\Namespaced2\\Baz',    'Namespaced2\\Baz',    '->loadClass() loads Namespaced2\Baz class'],
+            ['\\Pearlike2_Baz',       'Pearlike2_Baz',       '->loadClass() loads Pearlike2_Baz class'],
+            ['\\Namespaced2\\FooBar', 'Namespaced2\\FooBar', '->loadClass() loads Namespaced2\Baz class from fallback dir'],
+            ['\\Pearlike2_FooBar',    'Pearlike2_FooBar',    '->loadClass() loads Pearlike2_Baz class from fallback dir'],
+        ];
+    }
+
+    /**
+     * @dataProvider getLoadClassNamespaceCollisionTests
+     */
+    public function testLoadClassNamespaceCollision($namespaces, $className, $message)
+    {
+        $loader = new ClassLoader();
+        $loader->addPrefixes($namespaces);
+
+        $loader->loadClass($className);
+        $this->assertTrue(class_exists($className), $message);
+    }
+
+    public function getLoadClassNamespaceCollisionTests()
+    {
+        return [
+            [
+                [
+                    'NamespaceCollision\\C' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                    'NamespaceCollision\\C\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                ],
+                'NamespaceCollision\C\Foo',
+                '->loadClass() loads NamespaceCollision\C\Foo from alpha.',
+            ],
+            [
+                [
+                    'NamespaceCollision\\C\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                    'NamespaceCollision\\C' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                ],
+                'NamespaceCollision\C\Bar',
+                '->loadClass() loads NamespaceCollision\C\Bar from alpha.',
+            ],
+            [
+                [
+                    'NamespaceCollision\\C' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                    'NamespaceCollision\\C\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                ],
+                'NamespaceCollision\C\B\Foo',
+                '->loadClass() loads NamespaceCollision\C\B\Foo from beta.',
+            ],
+            [
+                [
+                    'NamespaceCollision\\C\\B' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                    'NamespaceCollision\\C' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                ],
+                'NamespaceCollision\C\B\Bar',
+                '->loadClass() loads NamespaceCollision\C\B\Bar from beta.',
+            ],
+            [
+                [
+                    'PrefixCollision_C_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                    'PrefixCollision_C_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                ],
+                'PrefixCollision_C_Foo',
+                '->loadClass() loads PrefixCollision_C_Foo from alpha.',
+            ],
+            [
+                [
+                    'PrefixCollision_C_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                    'PrefixCollision_C_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                ],
+                'PrefixCollision_C_Bar',
+                '->loadClass() loads PrefixCollision_C_Bar from alpha.',
+            ],
+            [
+                [
+                    'PrefixCollision_C_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                    'PrefixCollision_C_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                ],
+                'PrefixCollision_C_B_Foo',
+                '->loadClass() loads PrefixCollision_C_B_Foo from beta.',
+            ],
+            [
+                [
+                    'PrefixCollision_C_B_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/beta',
+                    'PrefixCollision_C_' => __DIR__.\DIRECTORY_SEPARATOR.'Fixtures/alpha',
+                ],
+                'PrefixCollision_C_B_Bar',
+                '->loadClass() loads PrefixCollision_C_B_Bar from beta.',
+            ],
+        ];
+    }
+}

+ 151 - 0
vendor/symfony/class-loader/Tests/ClassMapGeneratorTest.php

@@ -0,0 +1,151 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\ClassLoader\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\ClassLoader\ClassMapGenerator;
+
+/**
+ * @group legacy
+ */
+class ClassMapGeneratorTest extends TestCase
+{
+    /**
+     * @var string|null
+     */
+    private $workspace = null;
+
+    public function prepare_workspace()
+    {
+        $this->workspace = sys_get_temp_dir().'/'.microtime(true).'.'.mt_rand();
+        mkdir($this->workspace, 0777, true);
+        $this->workspace = realpath($this->workspace);
+    }
+
+    /**
+     * @param string $file
+     */
+    private function clean($file)
+    {
+        if (is_dir($file) && !is_link($file)) {
+            $dir = new \FilesystemIterator($file);
+            foreach ($dir as $childFile) {
+                $this->clean($childFile);
+            }
+
+            rmdir($file);
+        } else {
+            unlink($file);
+        }
+    }
+
+    /**
+     * @dataProvider getTestCreateMapTests
+     */
+    public function testDump($directory)
+    {
+        $this->prepare_workspace();
+
+        $file = $this->workspace.'/file';
+
+        $generator = new ClassMapGenerator();
+        $generator->dump($directory, $file);
+        $this->assertFileExists($file);
+
+        $this->clean($this->workspace);
+    }
+
+    /**
+     * @dataProvider getTestCreateMapTests
+     */
+    public function testCreateMap($directory, $expected)
+    {
+        $this->assertEqualsNormalized($expected, ClassMapGenerator::createMap($directory));
+    }
+
+    public function getTestCreateMapTests()
+    {
+        $data = [
+            [__DIR__.'/Fixtures/Namespaced', [
+                'Namespaced\\Bar' => realpath(__DIR__).'/Fixtures/Namespaced/Bar.php',
+                'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php',
+                'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php',
+                'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php',
+                'Namespaced\\WithStrictTypes' => realpath(__DIR__).'/Fixtures/Namespaced/WithStrictTypes.php',
+                'Namespaced\\WithHaltCompiler' => realpath(__DIR__).'/Fixtures/Namespaced/WithHaltCompiler.php',
+                'Namespaced\\WithDirMagic' => realpath(__DIR__).'/Fixtures/Namespaced/WithDirMagic.php',
+                'Namespaced\\WithFileMagic' => realpath(__DIR__).'/Fixtures/Namespaced/WithFileMagic.php',
+            ]],
+            [__DIR__.'/Fixtures/beta/NamespaceCollision', [
+                'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Bar.php',
+                'NamespaceCollision\\A\\B\\Foo' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Foo.php',
+                'NamespaceCollision\\C\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/C/B/Bar.php',
+                'NamespaceCollision\\C\\B\\Foo' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/C/B/Foo.php',
+            ]],
+            [__DIR__.'/Fixtures/Pearlike', [
+                'Pearlike_Foo' => realpath(__DIR__).'/Fixtures/Pearlike/Foo.php',
+                'Pearlike_Bar' => realpath(__DIR__).'/Fixtures/Pearlike/Bar.php',
+                'Pearlike_Baz' => realpath(__DIR__).'/Fixtures/Pearlike/Baz.php',
+                'Pearlike_WithComments' => realpath(__DIR__).'/Fixtures/Pearlike/WithComments.php',
+            ]],
+            [__DIR__.'/Fixtures/classmap', [
+                'Foo\\Bar\\A' => realpath(__DIR__).'/Fixtures/classmap/sameNsMultipleClasses.php',
+                'Foo\\Bar\\B' => realpath(__DIR__).'/Fixtures/classmap/sameNsMultipleClasses.php',
+                'A' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
+                'Alpha\\A' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
+                'Alpha\\B' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
+                'Beta\\A' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
+                'Beta\\B' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
+                'ClassMap\\SomeInterface' => realpath(__DIR__).'/Fixtures/classmap/SomeInterface.php',
+                'ClassMap\\SomeParent' => realpath(__DIR__).'/Fixtures/classmap/SomeParent.php',
+                'ClassMap\\SomeClass' => realpath(__DIR__).'/Fixtures/classmap/SomeClass.php',
+            ]],
+            [__DIR__.'/Fixtures/php5.4', [
+                'TFoo' => __DIR__.'/Fixtures/php5.4/traits.php',
+                'CFoo' => __DIR__.'/Fixtures/php5.4/traits.php',
+                'Foo\\TBar' => __DIR__.'/Fixtures/php5.4/traits.php',
+                'Foo\\IBar' => __DIR__.'/Fixtures/php5.4/traits.php',
+                'Foo\\TFooBar' => __DIR__.'/Fixtures/php5.4/traits.php',
+                'Foo\\CBar' => __DIR__.'/Fixtures/php5.4/traits.php',
+            ]],
+            [__DIR__.'/Fixtures/php5.5', [
+                'ClassCons\\Foo' => __DIR__.'/Fixtures/php5.5/class_cons.php',
+            ]],
+        ];
+
+        return $data;
+    }
+
+    public function testCreateMapFinderSupport()
+    {
+        $finder = new \Symfony\Component\Finder\Finder();
+        $finder->files()->in(__DIR__.'/Fixtures/beta/NamespaceCollision');
+
+        $this->assertEqualsNormalized([
+            'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Bar.php',
+            'NamespaceCollision\\A\\B\\Foo' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Foo.php',
+            'NamespaceCollision\\C\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/C/B/Bar.php',
+            'NamespaceCollision\\C\\B\\Foo' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/C/B/Foo.php',
+        ], ClassMapGenerator::createMap($finder));
+    }
+
+    protected function assertEqualsNormalized($expected, $actual, $message = '')
+    {
+        foreach ($expected as $ns => $path) {
+            $expected[$ns] = str_replace('\\', '/', $path);
+        }
+        foreach ($actual as $ns => $path) {
+            $actual[$ns] = str_replace('\\', '/', $path);
+        }
+        $this->assertEquals($expected, $actual, $message);
+    }
+}

+ 17 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/Bar.php

@@ -0,0 +1,17 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Apc\Namespaced;
+
+class Bar
+{
+    public static $loaded = true;
+}

+ 17 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/Baz.php

@@ -0,0 +1,17 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Apc\Namespaced;
+
+class Baz
+{
+    public static $loaded = true;
+}

+ 17 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/Foo.php

@@ -0,0 +1,17 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Apc\Namespaced;
+
+class Foo
+{
+    public static $loaded = true;
+}

+ 17 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/Namespaced/FooBar.php

@@ -0,0 +1,17 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Apc\Namespaced;
+
+class FooBar
+{
+    public static $loaded = true;
+}

+ 6 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/Pearlike/Bar.php

@@ -0,0 +1,6 @@
+<?php
+
+class Apc_Pearlike_Bar
+{
+    public static $loaded = true;
+}

+ 6 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/Pearlike/Baz.php

@@ -0,0 +1,6 @@
+<?php
+
+class Apc_Pearlike_Baz
+{
+    public static $loaded = true;
+}

+ 6 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/Pearlike/Foo.php

@@ -0,0 +1,6 @@
+<?php
+
+class Apc_Pearlike_Foo
+{
+    public static $loaded = true;
+}

+ 6 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Bar.php

@@ -0,0 +1,6 @@
+<?php
+
+class ApcPrefixCollision_A_Bar
+{
+    public static $loaded = true;
+}

+ 6 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Foo.php

@@ -0,0 +1,6 @@
+<?php
+
+class ApcPrefixCollision_A_Foo
+{
+    public static $loaded = true;
+}

+ 17 - 0
vendor/symfony/class-loader/Tests/Fixtures/Apc/alpha/Apc/NamespaceCollision/A/Bar.php

@@ -0,0 +1,17 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Apc\NamespaceCollision\A;
+
+class Bar
+{
+    public static $loaded = true;
+}

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff