20220406
This commit is contained in:
281
vendor/composer/InstalledVersions.php
vendored
Normal file
281
vendor/composer/InstalledVersions.php
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class InstalledVersions
|
||||
{
|
||||
private static $installed = array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2c373f1587474940063688399f43ef8f93fed848',
|
||||
'name' => 'topthink/think',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'phpmailer/phpmailer' =>
|
||||
array (
|
||||
'pretty_version' => 'v6.6.0',
|
||||
'version' => '6.6.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'e43bac82edc26ca04b36143a48bde1c051cfd5b1',
|
||||
),
|
||||
'tecnickcom/tcpdf' =>
|
||||
array (
|
||||
'pretty_version' => '6.4.4',
|
||||
'version' => '6.4.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '42cd0f9786af7e5db4fcedaa66f717b0d0032320',
|
||||
),
|
||||
'topthink/framework' =>
|
||||
array (
|
||||
'pretty_version' => 'v5.0.24',
|
||||
'version' => '5.0.24.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be',
|
||||
),
|
||||
'topthink/think' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2c373f1587474940063688399f43ef8f93fed848',
|
||||
),
|
||||
'topthink/think-captcha' =>
|
||||
array (
|
||||
'pretty_version' => 'v1.0.8',
|
||||
'version' => '1.0.8.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1d64363c814c92f6086c4fa5e3223fe7e23db09d',
|
||||
),
|
||||
'topthink/think-helper' =>
|
||||
array (
|
||||
'pretty_version' => 'v3.0.0',
|
||||
'version' => '3.0.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '8ba5f66e68106369fcc3211e7d2dbaf7bc9ce455',
|
||||
),
|
||||
'topthink/think-installer' =>
|
||||
array (
|
||||
'pretty_version' => 'v1.0.14',
|
||||
'version' => '1.0.14.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'eae1740ac264a55c06134b6685dfb9f837d004d1',
|
||||
),
|
||||
'topthink/think-queue' =>
|
||||
array (
|
||||
'pretty_version' => 'v1.1.4',
|
||||
'version' => '1.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'ad709611d516e13d6760234bc98e91faa901cae8',
|
||||
),
|
||||
'weiwei/api-doc' =>
|
||||
array (
|
||||
'pretty_version' => '1.6.2',
|
||||
'version' => '1.6.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '6c2c3c03ce1139275cc5a5057677175ed8691e19',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
return array_keys(self::$installed['versions']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function isInstalled($packageName)
|
||||
{
|
||||
return isset(self::$installed['versions'][$packageName]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints($constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset(self::$installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = self::$installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', self::$installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', self::$installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', self::$installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
if (!isset(self::$installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::$installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::$installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
if (!isset(self::$installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::$installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getRootPackage()
|
||||
{
|
||||
return self::$installed['root'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getRawData()
|
||||
{
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
}
|
||||
}
|
||||
96
vendor/composer/installed.php
vendored
Normal file
96
vendor/composer/installed.php
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php return array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2c373f1587474940063688399f43ef8f93fed848',
|
||||
'name' => 'topthink/think',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'phpmailer/phpmailer' =>
|
||||
array (
|
||||
'pretty_version' => 'v6.6.0',
|
||||
'version' => '6.6.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'e43bac82edc26ca04b36143a48bde1c051cfd5b1',
|
||||
),
|
||||
'tecnickcom/tcpdf' =>
|
||||
array (
|
||||
'pretty_version' => '6.4.4',
|
||||
'version' => '6.4.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '42cd0f9786af7e5db4fcedaa66f717b0d0032320',
|
||||
),
|
||||
'topthink/framework' =>
|
||||
array (
|
||||
'pretty_version' => 'v5.0.24',
|
||||
'version' => '5.0.24.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be',
|
||||
),
|
||||
'topthink/think' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2c373f1587474940063688399f43ef8f93fed848',
|
||||
),
|
||||
'topthink/think-captcha' =>
|
||||
array (
|
||||
'pretty_version' => 'v1.0.8',
|
||||
'version' => '1.0.8.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '1d64363c814c92f6086c4fa5e3223fe7e23db09d',
|
||||
),
|
||||
'topthink/think-helper' =>
|
||||
array (
|
||||
'pretty_version' => 'v3.0.0',
|
||||
'version' => '3.0.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '8ba5f66e68106369fcc3211e7d2dbaf7bc9ce455',
|
||||
),
|
||||
'topthink/think-installer' =>
|
||||
array (
|
||||
'pretty_version' => 'v1.0.14',
|
||||
'version' => '1.0.14.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'eae1740ac264a55c06134b6685dfb9f837d004d1',
|
||||
),
|
||||
'topthink/think-queue' =>
|
||||
array (
|
||||
'pretty_version' => 'v1.1.4',
|
||||
'version' => '1.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'ad709611d516e13d6760234bc98e91faa901cae8',
|
||||
),
|
||||
'weiwei/api-doc' =>
|
||||
array (
|
||||
'pretty_version' => '1.6.2',
|
||||
'version' => '1.6.2.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '6c2c3c03ce1139275cc5a5057677175ed8691e19',
|
||||
),
|
||||
),
|
||||
);
|
||||
26
vendor/composer/platform_check.php
vendored
Normal file
26
vendor/composer/platform_check.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 50500)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.5.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
19
vendor/doctrine/annotations/LICENSE
vendored
Normal file
19
vendor/doctrine/annotations/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2013 Doctrine Project
|
||||
|
||||
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.
|
||||
18
vendor/doctrine/annotations/README.md
vendored
Normal file
18
vendor/doctrine/annotations/README.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Doctrine Annotations
|
||||
|
||||
[](https://github.com/doctrine/persistence/actions)
|
||||
[](https://www.versioneye.com/package/php--doctrine--annotations)
|
||||
[](https://www.versioneye.com/php/doctrine:annotations/references)
|
||||
[](https://packagist.org/packages/doctrine/annotations)
|
||||
[](https://packagist.org/packages/doctrine/annotations)
|
||||
|
||||
Docblock Annotations Parser library (extracted from [Doctrine Common](https://github.com/doctrine/common)).
|
||||
|
||||
## Documentation
|
||||
|
||||
See the [doctrine-project website](https://www.doctrine-project.org/projects/doctrine-annotations/en/latest/index.html).
|
||||
|
||||
## Contributing
|
||||
|
||||
When making a pull request, make sure your changes follow the
|
||||
[Coding Standard Guidelines](https://www.doctrine-project.org/projects/doctrine-coding-standard/en/current/reference/index.html#introduction).
|
||||
44
vendor/doctrine/annotations/composer.json
vendored
Normal file
44
vendor/doctrine/annotations/composer.json
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"type": "library",
|
||||
"description": "Docblock Annotations Parser",
|
||||
"keywords": ["annotations", "docblock", "parser"],
|
||||
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
|
||||
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
|
||||
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
|
||||
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
|
||||
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"ext-tokenizer": "*",
|
||||
"doctrine/lexer": "1.*",
|
||||
"psr/cache": "^1 || ^2 || ^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "^1.11 || ^2.0",
|
||||
"doctrine/coding-standard": "^6.0 || ^8.1",
|
||||
"phpstan/phpstan": "^0.12.20",
|
||||
"phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5",
|
||||
"symfony/cache": "^4.4 || ^5.2"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Performance\\Common\\Annotations\\": "tests/Doctrine/Performance/Common/Annotations",
|
||||
"Doctrine\\Tests\\Common\\Annotations\\": "tests/Doctrine/Tests/Common/Annotations"
|
||||
},
|
||||
"files": [
|
||||
"tests/Doctrine/Tests/Common/Annotations/Fixtures/functions.php",
|
||||
"tests/Doctrine/Tests/Common/Annotations/Fixtures/SingleClassLOC1000.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
252
vendor/doctrine/annotations/docs/en/annotations.rst
vendored
Normal file
252
vendor/doctrine/annotations/docs/en/annotations.rst
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
Handling Annotations
|
||||
====================
|
||||
|
||||
There are several different approaches to handling annotations in PHP.
|
||||
Doctrine Annotations maps docblock annotations to PHP classes. Because
|
||||
not all docblock annotations are used for metadata purposes a filter is
|
||||
applied to ignore or skip classes that are not Doctrine annotations.
|
||||
|
||||
Take a look at the following code snippet:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyProject\Entities;
|
||||
|
||||
use Doctrine\ORM\Mapping AS ORM;
|
||||
use Symfony\Component\Validator\Constraints AS Assert;
|
||||
|
||||
/**
|
||||
* @author Benjamin Eberlei
|
||||
* @ORM\Entity
|
||||
* @MyProject\Annotations\Foobarable
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @ORM\Id @ORM\Column @ORM\GeneratedValue
|
||||
* @dummy
|
||||
* @var int
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
* @Assert\NotEmpty
|
||||
* @Assert\Email
|
||||
* @var string
|
||||
*/
|
||||
private $email;
|
||||
}
|
||||
|
||||
In this snippet you can see a variety of different docblock annotations:
|
||||
|
||||
- Documentation annotations such as ``@var`` and ``@author``. These
|
||||
annotations are ignored and never considered for throwing an
|
||||
exception due to wrongly used annotations.
|
||||
- Annotations imported through use statements. The statement ``use
|
||||
Doctrine\ORM\Mapping AS ORM`` makes all classes under that namespace
|
||||
available as ``@ORM\ClassName``. Same goes for the import of
|
||||
``@Assert``.
|
||||
- The ``@dummy`` annotation. It is not a documentation annotation and
|
||||
not ignored. For Doctrine Annotations it is not entirely clear how
|
||||
to handle this annotation. Depending on the configuration an exception
|
||||
(unknown annotation) will be thrown when parsing this annotation.
|
||||
- The fully qualified annotation ``@MyProject\Annotations\Foobarable``.
|
||||
This is transformed directly into the given class name.
|
||||
|
||||
How are these annotations loaded? From looking at the code you could
|
||||
guess that the ORM Mapping, Assert Validation and the fully qualified
|
||||
annotation can just be loaded using
|
||||
the defined PHP autoloaders. This is not the case however: For error
|
||||
handling reasons every check for class existence inside the
|
||||
``AnnotationReader`` sets the second parameter $autoload
|
||||
of ``class_exists($name, $autoload)`` to false. To work flawlessly the
|
||||
``AnnotationReader`` requires silent autoloaders which many autoloaders are
|
||||
not. Silent autoloading is NOT part of the `PSR-0 specification
|
||||
<https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md>`_
|
||||
for autoloading.
|
||||
|
||||
This is why Doctrine Annotations uses its own autoloading mechanism
|
||||
through a global registry. If you are wondering about the annotation
|
||||
registry being global, there is no other way to solve the architectural
|
||||
problems of autoloading annotation classes in a straightforward fashion.
|
||||
Additionally if you think about PHP autoloading then you recognize it is
|
||||
a global as well.
|
||||
|
||||
To anticipate the configuration section, making the above PHP class work
|
||||
with Doctrine Annotations requires this setup:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
|
||||
AnnotationRegistry::registerFile("/path/to/doctrine/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php");
|
||||
AnnotationRegistry::registerAutoloadNamespace("Symfony\Component\Validator\Constraint", "/path/to/symfony/src");
|
||||
AnnotationRegistry::registerAutoloadNamespace("MyProject\Annotations", "/path/to/myproject/src");
|
||||
|
||||
$reader = new AnnotationReader();
|
||||
AnnotationReader::addGlobalIgnoredName('dummy');
|
||||
|
||||
The second block with the annotation registry calls registers all the
|
||||
three different annotation namespaces that are used.
|
||||
Doctrine Annotations saves all its annotations in a single file, that is
|
||||
why ``AnnotationRegistry#registerFile`` is used in contrast to
|
||||
``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0
|
||||
compatible loading mechanism for class to file names.
|
||||
|
||||
In the third block, we create the actual ``AnnotationReader`` instance.
|
||||
Note that we also add ``dummy`` to the global list of ignored
|
||||
annotations for which we do not throw exceptions. Setting this is
|
||||
necessary in our example case, otherwise ``@dummy`` would trigger an
|
||||
exception to be thrown during the parsing of the docblock of
|
||||
``MyProject\Entities\User#id``.
|
||||
|
||||
Setup and Configuration
|
||||
-----------------------
|
||||
|
||||
To use the annotations library is simple, you just need to create a new
|
||||
``AnnotationReader`` instance:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
|
||||
This creates a simple annotation reader with no caching other than in
|
||||
memory (in php arrays). Since parsing docblocks can be expensive you
|
||||
should cache this process by using a caching reader.
|
||||
|
||||
To cache annotations, you can create a ``Doctrine\Common\Annotations\PsrCachedReader``.
|
||||
This reader decorates the original reader and stores all annotations in a PSR-6
|
||||
cache:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Annotations\PsrCachedReader;
|
||||
|
||||
$cache = ... // instantiate a PSR-6 Cache pool
|
||||
|
||||
$reader = new PsrCachedReader(
|
||||
new AnnotationReader(),
|
||||
$cache,
|
||||
$debug = true
|
||||
);
|
||||
|
||||
The ``debug`` flag is used here as well to invalidate the cache files
|
||||
when the PHP class with annotations changed and should be used during
|
||||
development.
|
||||
|
||||
.. warning ::
|
||||
|
||||
The ``AnnotationReader`` works and caches under the
|
||||
assumption that all annotations of a doc-block are processed at
|
||||
once. That means that annotation classes that do not exist and
|
||||
aren't loaded and cannot be autoloaded (using the
|
||||
AnnotationRegistry) would never be visible and not accessible if a
|
||||
cache is used unless the cache is cleared and the annotations
|
||||
requested again, this time with all annotations defined.
|
||||
|
||||
By default the annotation reader returns a list of annotations with
|
||||
numeric indexes. If you want your annotations to be indexed by their
|
||||
class name you can wrap the reader in an ``IndexedReader``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Annotations\IndexedReader;
|
||||
|
||||
$reader = new IndexedReader(new AnnotationReader());
|
||||
|
||||
.. warning::
|
||||
|
||||
You should never wrap the indexed reader inside a cached reader,
|
||||
only the other way around. This way you can re-use the cache with
|
||||
indexed or numeric keys, otherwise your code may experience failures
|
||||
due to caching in a numerical or indexed format.
|
||||
|
||||
Registering Annotations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As explained in the introduction, Doctrine Annotations uses its own
|
||||
autoloading mechanism to determine if a given annotation has a
|
||||
corresponding PHP class that can be autoloaded. For annotation
|
||||
autoloading you have to configure the
|
||||
``Doctrine\Common\Annotations\AnnotationRegistry``. There are three
|
||||
different mechanisms to configure annotation autoloading:
|
||||
|
||||
- Calling ``AnnotationRegistry#registerFile($file)`` to register a file
|
||||
that contains one or more annotation classes.
|
||||
- Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs =
|
||||
null)`` to register that the given namespace contains annotations and
|
||||
that their base directory is located at the given $dirs or in the
|
||||
include path if ``NULL`` is passed. The given directories should *NOT*
|
||||
be the directory where classes of the namespace are in, but the base
|
||||
directory of the root namespace. The AnnotationRegistry uses a
|
||||
namespace to directory separator approach to resolve the correct path.
|
||||
- Calling ``AnnotationRegistry#registerLoader($callable)`` to register
|
||||
an autoloader callback. The callback accepts the class as first and
|
||||
only parameter and has to return ``true`` if the corresponding file
|
||||
was found and included.
|
||||
|
||||
.. note::
|
||||
|
||||
Loaders have to fail silently, if a class is not found even if it
|
||||
matches for example the namespace prefix of that loader. Never is a
|
||||
loader to throw a warning or exception if the loading failed
|
||||
otherwise parsing doc block annotations will become a huge pain.
|
||||
|
||||
A sample loader callback could look like:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
use Symfony\Component\ClassLoader\UniversalClassLoader;
|
||||
|
||||
AnnotationRegistry::registerLoader(function($class) {
|
||||
$file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php";
|
||||
|
||||
if (file_exists("/my/base/path/" . $file)) {
|
||||
// file_exists() makes sure that the loader fails silently
|
||||
require "/my/base/path/" . $file;
|
||||
}
|
||||
});
|
||||
|
||||
$loader = new UniversalClassLoader();
|
||||
AnnotationRegistry::registerLoader(array($loader, "loadClass"));
|
||||
|
||||
|
||||
Ignoring missing exceptions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default an exception is thrown from the ``AnnotationReader`` if an
|
||||
annotation was found that:
|
||||
|
||||
- is not part of the list of ignored "documentation annotations";
|
||||
- was not imported through a use statement;
|
||||
- is not a fully qualified class that exists.
|
||||
|
||||
You can disable this behavior for specific names if your docblocks do
|
||||
not follow strict requirements:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
AnnotationReader::addGlobalIgnoredName('foo');
|
||||
|
||||
PHP Imports
|
||||
~~~~~~~~~~~
|
||||
|
||||
By default the annotation reader parses the use-statement of a php file
|
||||
to gain access to the import rules and register them for the annotation
|
||||
processing. Only if you are using PHP Imports can you validate the
|
||||
correct usage of annotations and throw exceptions if you misspelled an
|
||||
annotation. This mechanism is enabled by default.
|
||||
|
||||
To ease the upgrade path, we still allow you to disable this mechanism.
|
||||
Note however that we will remove this in future versions:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
$reader->setEnabledPhpImports(false);
|
||||
443
vendor/doctrine/annotations/docs/en/custom.rst
vendored
Normal file
443
vendor/doctrine/annotations/docs/en/custom.rst
vendored
Normal file
@@ -0,0 +1,443 @@
|
||||
Custom Annotation Classes
|
||||
=========================
|
||||
|
||||
If you want to define your own annotations, you just have to group them
|
||||
in a namespace and register this namespace in the ``AnnotationRegistry``.
|
||||
Annotation classes have to contain a class-level docblock with the text
|
||||
``@Annotation``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Annotations;
|
||||
|
||||
/** @Annotation */
|
||||
class Bar
|
||||
{
|
||||
// some code
|
||||
}
|
||||
|
||||
Inject annotation values
|
||||
------------------------
|
||||
|
||||
The annotation parser checks if the annotation constructor has arguments,
|
||||
if so then it will pass the value array, otherwise it will try to inject
|
||||
values into public properties directly:
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*
|
||||
* Some Annotation using a constructor
|
||||
*/
|
||||
class Bar
|
||||
{
|
||||
private $foo;
|
||||
|
||||
public function __construct(array $values)
|
||||
{
|
||||
$this->foo = $values['foo'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*
|
||||
* Some Annotation without a constructor
|
||||
*/
|
||||
class Foo
|
||||
{
|
||||
public $bar;
|
||||
}
|
||||
|
||||
Optional: Constructors with Named Parameters
|
||||
--------------------------------------------
|
||||
|
||||
Starting with Annotations v1.11 a new annotation instantiation strategy
|
||||
is available that aims at compatibility of Annotation classes with the PHP 8
|
||||
attribute feature. You need to declare a constructor with regular parameter
|
||||
names that match the named arguments in the annotation syntax.
|
||||
|
||||
To enable this feature, you can tag your annotation class with
|
||||
``@NamedArgumentConstructor`` (available from v1.12) or implement the
|
||||
``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation`` interface
|
||||
(available from v1.11 and deprecated as of v1.12).
|
||||
When using the ``@NamedArgumentConstructor`` tag, the first argument of the
|
||||
constructor is considered as the default one.
|
||||
|
||||
|
||||
Usage with the ``@NamedArgumentContrustor`` tag
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor
|
||||
*/
|
||||
class Bar implements NamedArgumentConstructorAnnotation
|
||||
{
|
||||
private $foo;
|
||||
|
||||
public function __construct(string $foo)
|
||||
{
|
||||
$this->foo = $foo;
|
||||
}
|
||||
}
|
||||
|
||||
/** Usable with @Bar(foo="baz") */
|
||||
/** Usable with @Bar("baz") */
|
||||
|
||||
In combination with PHP 8's constructor property promotion feature
|
||||
you can simplify this to:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor
|
||||
*/
|
||||
class Bar implements NamedArgumentConstructorAnnotation
|
||||
{
|
||||
public function __construct(private string $foo) {}
|
||||
}
|
||||
|
||||
|
||||
Usage with the
|
||||
``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation``
|
||||
interface (v1.11, deprecated as of v1.12):
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Annotations;
|
||||
|
||||
use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation;
|
||||
|
||||
/** @Annotation */
|
||||
class Bar implements NamedArgumentConstructorAnnotation
|
||||
{
|
||||
private $foo;
|
||||
|
||||
public function __construct(private string $foo) {}
|
||||
}
|
||||
|
||||
/** Usable with @Bar(foo="baz") */
|
||||
|
||||
Annotation Target
|
||||
-----------------
|
||||
|
||||
``@Target`` indicates the kinds of class elements to which an annotation
|
||||
type is applicable. Then you could define one or more targets:
|
||||
|
||||
- ``CLASS`` Allowed in class docblocks
|
||||
- ``PROPERTY`` Allowed in property docblocks
|
||||
- ``METHOD`` Allowed in the method docblocks
|
||||
- ``FUNCTION`` Allowed in function dockblocks
|
||||
- ``ALL`` Allowed in class, property, method and function docblocks
|
||||
- ``ANNOTATION`` Allowed inside other annotations
|
||||
|
||||
If the annotations is not allowed in the current context, an
|
||||
``AnnotationException`` is thrown.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target({"METHOD","PROPERTY"})
|
||||
*/
|
||||
class Bar
|
||||
{
|
||||
// some code
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
class Foo
|
||||
{
|
||||
// some code
|
||||
}
|
||||
|
||||
Attribute types
|
||||
---------------
|
||||
|
||||
The annotation parser checks the given parameters using the phpdoc
|
||||
annotation ``@var``, The data type could be validated using the ``@var``
|
||||
annotation on the annotation properties or using the ``@Attributes`` and
|
||||
``@Attribute`` annotations.
|
||||
|
||||
If the data type does not match you get an ``AnnotationException``
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target({"METHOD","PROPERTY"})
|
||||
*/
|
||||
class Bar
|
||||
{
|
||||
/** @var mixed */
|
||||
public $mixed;
|
||||
|
||||
/** @var boolean */
|
||||
public $boolean;
|
||||
|
||||
/** @var bool */
|
||||
public $bool;
|
||||
|
||||
/** @var float */
|
||||
public $float;
|
||||
|
||||
/** @var string */
|
||||
public $string;
|
||||
|
||||
/** @var integer */
|
||||
public $integer;
|
||||
|
||||
/** @var array */
|
||||
public $array;
|
||||
|
||||
/** @var SomeAnnotationClass */
|
||||
public $annotation;
|
||||
|
||||
/** @var array<integer> */
|
||||
public $arrayOfIntegers;
|
||||
|
||||
/** @var array<SomeAnnotationClass> */
|
||||
public $arrayOfAnnotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target({"METHOD","PROPERTY"})
|
||||
* @Attributes({
|
||||
* @Attribute("stringProperty", type = "string"),
|
||||
* @Attribute("annotProperty", type = "SomeAnnotationClass"),
|
||||
* })
|
||||
*/
|
||||
class Foo
|
||||
{
|
||||
public function __construct(array $values)
|
||||
{
|
||||
$this->stringProperty = $values['stringProperty'];
|
||||
$this->annotProperty = $values['annotProperty'];
|
||||
}
|
||||
|
||||
// some code
|
||||
}
|
||||
|
||||
Annotation Required
|
||||
-------------------
|
||||
|
||||
``@Required`` indicates that the field must be specified when the
|
||||
annotation is used. If it is not used you get an ``AnnotationException``
|
||||
stating that this value can not be null.
|
||||
|
||||
Declaring a required field:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("ALL")
|
||||
*/
|
||||
class Foo
|
||||
{
|
||||
/** @Required */
|
||||
public $requiredField;
|
||||
}
|
||||
|
||||
Usage:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
/** @Foo(requiredField="value") */
|
||||
public $direction; // Valid
|
||||
|
||||
/** @Foo */
|
||||
public $direction; // Required field missing, throws an AnnotationException
|
||||
|
||||
|
||||
Enumerated values
|
||||
-----------------
|
||||
|
||||
- An annotation property marked with ``@Enum`` is a field that accepts a
|
||||
fixed set of scalar values.
|
||||
- You should use ``@Enum`` fields any time you need to represent fixed
|
||||
values.
|
||||
- The annotation parser checks the given value and throws an
|
||||
``AnnotationException`` if the value does not match.
|
||||
|
||||
|
||||
Declaring an enumerated property:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("ALL")
|
||||
*/
|
||||
class Direction
|
||||
{
|
||||
/**
|
||||
* @Enum({"NORTH", "SOUTH", "EAST", "WEST"})
|
||||
*/
|
||||
public $value;
|
||||
}
|
||||
|
||||
Annotation usage:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
/** @Direction("NORTH") */
|
||||
public $direction; // Valid value
|
||||
|
||||
/** @Direction("NORTHEAST") */
|
||||
public $direction; // Invalid value, throws an AnnotationException
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
The use of constants and class constants is available on the annotations
|
||||
parser.
|
||||
|
||||
The following usages are allowed:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Entity;
|
||||
|
||||
use MyCompany\Annotations\Foo;
|
||||
use MyCompany\Annotations\Bar;
|
||||
use MyCompany\Entity\SomeClass;
|
||||
|
||||
/**
|
||||
* @Foo(PHP_EOL)
|
||||
* @Bar(Bar::FOO)
|
||||
* @Foo({SomeClass::FOO, SomeClass::BAR})
|
||||
* @Bar({SomeClass::FOO_KEY = SomeClass::BAR_VALUE})
|
||||
*/
|
||||
class User
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Be careful with constants and the cache !
|
||||
|
||||
.. note::
|
||||
|
||||
The cached reader will not re-evaluate each time an annotation is
|
||||
loaded from cache. When a constant is changed the cache must be
|
||||
cleaned.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Using the library API is simple. Using the annotations described in the
|
||||
previous section, you can now annotate other classes with your
|
||||
annotations:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace MyCompany\Entity;
|
||||
|
||||
use MyCompany\Annotations\Foo;
|
||||
use MyCompany\Annotations\Bar;
|
||||
|
||||
/**
|
||||
* @Foo(bar="foo")
|
||||
* @Bar(foo="bar")
|
||||
*/
|
||||
class User
|
||||
{
|
||||
}
|
||||
|
||||
Now we can write a script to get the annotations above:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$reflClass = new ReflectionClass('MyCompany\Entity\User');
|
||||
$classAnnotations = $reader->getClassAnnotations($reflClass);
|
||||
|
||||
foreach ($classAnnotations AS $annot) {
|
||||
if ($annot instanceof \MyCompany\Annotations\Foo) {
|
||||
echo $annot->bar; // prints "foo";
|
||||
} else if ($annot instanceof \MyCompany\Annotations\Bar) {
|
||||
echo $annot->foo; // prints "bar";
|
||||
}
|
||||
}
|
||||
|
||||
You have a complete API for retrieving annotation class instances from a
|
||||
class, property or method docblock:
|
||||
|
||||
|
||||
Reader API
|
||||
~~~~~~~~~~
|
||||
|
||||
Access all annotations of a class
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getClassAnnotations(\ReflectionClass $class);
|
||||
|
||||
Access one annotation of a class
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getClassAnnotation(\ReflectionClass $class, $annotationName);
|
||||
|
||||
Access all annotations of a method
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getMethodAnnotations(\ReflectionMethod $method);
|
||||
|
||||
Access one annotation of a method
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getMethodAnnotation(\ReflectionMethod $method, $annotationName);
|
||||
|
||||
Access all annotations of a property
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getPropertyAnnotations(\ReflectionProperty $property);
|
||||
|
||||
Access one annotation of a property
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName);
|
||||
|
||||
Access all annotations of a function
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getFunctionAnnotations(\ReflectionFunction $property);
|
||||
|
||||
Access one annotation of a function
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getFunctionAnnotation(\ReflectionFunction $property, $annotationName);
|
||||
101
vendor/doctrine/annotations/docs/en/index.rst
vendored
Normal file
101
vendor/doctrine/annotations/docs/en/index.rst
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
Doctrine Annotations allows to implement custom annotation
|
||||
functionality for PHP classes and functions.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
class Foo
|
||||
{
|
||||
/**
|
||||
* @MyAnnotation(myProperty="value")
|
||||
*/
|
||||
private $bar;
|
||||
}
|
||||
|
||||
Annotations aren't implemented in PHP itself which is why this component
|
||||
offers a way to use the PHP doc-blocks as a place for the well known
|
||||
annotation syntax using the ``@`` char.
|
||||
|
||||
Annotations in Doctrine are used for the ORM configuration to build the
|
||||
class mapping, but it can be used in other projects for other purposes
|
||||
too.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
You can install the Annotation component with composer:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ composer require doctrine/annotations
|
||||
|
||||
Create an annotation class
|
||||
==========================
|
||||
|
||||
An annotation class is a representation of the later used annotation
|
||||
configuration in classes. The annotation class of the previous example
|
||||
looks like this:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
final class MyAnnotation
|
||||
{
|
||||
public $myProperty;
|
||||
}
|
||||
|
||||
The annotation class is declared as an annotation by ``@Annotation``.
|
||||
|
||||
:ref:`Read more about custom annotations. <custom>`
|
||||
|
||||
Reading annotations
|
||||
===================
|
||||
|
||||
The access to the annotations happens by reflection of the class or function
|
||||
containing them. There are multiple reader-classes implementing the
|
||||
``Doctrine\Common\Annotations\Reader`` interface, that can access the
|
||||
annotations of a class. A common one is
|
||||
``Doctrine\Common\Annotations\AnnotationReader``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
|
||||
// Deprecated and will be removed in 2.0 but currently needed
|
||||
AnnotationRegistry::registerLoader('class_exists');
|
||||
|
||||
$reflectionClass = new ReflectionClass(Foo::class);
|
||||
$property = $reflectionClass->getProperty('bar');
|
||||
|
||||
$reader = new AnnotationReader();
|
||||
$myAnnotation = $reader->getPropertyAnnotation(
|
||||
$property,
|
||||
MyAnnotation::class
|
||||
);
|
||||
|
||||
echo $myAnnotation->myProperty; // result: "value"
|
||||
|
||||
Note that ``AnnotationRegistry::registerLoader('class_exists')`` only works
|
||||
if you already have an autoloader configured (i.e. composer autoloader).
|
||||
Otherwise, :ref:`please take a look to the other annotation autoload mechanisms <annotations>`.
|
||||
|
||||
A reader has multiple methods to access the annotations of a class or
|
||||
function.
|
||||
|
||||
:ref:`Read more about handling annotations. <annotations>`
|
||||
|
||||
IDE Support
|
||||
-----------
|
||||
|
||||
Some IDEs already provide support for annotations:
|
||||
|
||||
- Eclipse via the `Symfony2 Plugin <https://github.com/pulse00/Symfony-2-Eclipse-Plugin>`_
|
||||
- PhpStorm via the `PHP Annotations Plugin <https://plugins.jetbrains.com/plugin/7320-php-annotations>`_ or the `Symfony Plugin <https://plugins.jetbrains.com/plugin/7219-symfony-support>`_
|
||||
|
||||
.. _Read more about handling annotations.: annotations
|
||||
.. _Read more about custom annotations.: custom
|
||||
6
vendor/doctrine/annotations/docs/en/sidebar.rst
vendored
Normal file
6
vendor/doctrine/annotations/docs/en/sidebar.rst
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
|
||||
index
|
||||
annotations
|
||||
custom
|
||||
59
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php
vendored
Normal file
59
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use BadMethodCallException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Annotations class.
|
||||
*/
|
||||
class Annotation
|
||||
{
|
||||
/**
|
||||
* Value property. Common among all derived classes.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data Key-value for properties to be defined in this class.
|
||||
*/
|
||||
final public function __construct(array $data)
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler for unknown property accessor in Annotation class.
|
||||
*
|
||||
* @param string $name Unknown property name.
|
||||
*
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
throw new BadMethodCallException(
|
||||
sprintf("Unknown property '%s' on annotation '%s'.", $name, static::class)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler for unknown property mutator in Annotation class.
|
||||
*
|
||||
* @param string $name Unknown property name.
|
||||
* @param mixed $value Property value.
|
||||
*
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
throw new BadMethodCallException(
|
||||
sprintf("Unknown property '%s' on annotation '%s'.", $name, static::class)
|
||||
);
|
||||
}
|
||||
}
|
||||
21
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php
vendored
Normal file
21
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* Annotation that can be used to signal to the parser
|
||||
* to check the attribute type during the parsing process.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
final class Attribute
|
||||
{
|
||||
/** @var string */
|
||||
public $name;
|
||||
|
||||
/** @var string */
|
||||
public $type;
|
||||
|
||||
/** @var bool */
|
||||
public $required = false;
|
||||
}
|
||||
15
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php
vendored
Normal file
15
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* Annotation that can be used to signal to the parser
|
||||
* to check the types of all declared attributes during the parsing process.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
final class Attributes
|
||||
{
|
||||
/** @var array<Attribute> */
|
||||
public $value;
|
||||
}
|
||||
69
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php
vendored
Normal file
69
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function in_array;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Annotation that can be used to signal to the parser
|
||||
* to check the available values during the parsing process.
|
||||
*
|
||||
* @Annotation
|
||||
* @Attributes({
|
||||
* @Attribute("value", required = true, type = "array"),
|
||||
* @Attribute("literal", required = false, type = "array")
|
||||
* })
|
||||
*/
|
||||
final class Enum
|
||||
{
|
||||
/** @phpstan-var list<scalar> */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* Literal target declaration.
|
||||
*
|
||||
* @var mixed[]
|
||||
*/
|
||||
public $literal;
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @phpstan-param array{literal?: mixed[], value: list<scalar>} $values
|
||||
*/
|
||||
public function __construct(array $values)
|
||||
{
|
||||
if (! isset($values['literal'])) {
|
||||
$values['literal'] = [];
|
||||
}
|
||||
|
||||
foreach ($values['value'] as $var) {
|
||||
if (! is_scalar($var)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'@Enum supports only scalar values "%s" given.',
|
||||
is_object($var) ? get_class($var) : gettype($var)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($values['literal'] as $key => $var) {
|
||||
if (! in_array($key, $values['value'])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Undefined enumerator value "%s" for literal "%s".',
|
||||
$key,
|
||||
$var
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$this->value = $values['value'];
|
||||
$this->literal = $values['literal'];
|
||||
}
|
||||
}
|
||||
43
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php
vendored
Normal file
43
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function json_encode;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Annotation that can be used to signal to the parser to ignore specific
|
||||
* annotations during the parsing process.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
final class IgnoreAnnotation
|
||||
{
|
||||
/** @phpstan-var list<string> */
|
||||
public $names;
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @phpstan-param array{value: string|list<string>} $values
|
||||
*/
|
||||
public function __construct(array $values)
|
||||
{
|
||||
if (is_string($values['value'])) {
|
||||
$values['value'] = [$values['value']];
|
||||
}
|
||||
|
||||
if (! is_array($values['value'])) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'@IgnoreAnnotation expects either a string name, or an array of strings, but got %s.',
|
||||
json_encode($values['value'])
|
||||
));
|
||||
}
|
||||
|
||||
$this->names = $values['value'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that the annotated class should be constructed with a named argument call.
|
||||
*
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class NamedArgumentConstructor
|
||||
{
|
||||
}
|
||||
13
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.php
vendored
Normal file
13
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* Annotation that can be used to signal to the parser
|
||||
* to check if that attribute is required during the parsing process.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
final class Required
|
||||
{
|
||||
}
|
||||
101
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php
vendored
Normal file
101
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function array_keys;
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Annotation that can be used to signal to the parser
|
||||
* to check the annotation target during the parsing process.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
final class Target
|
||||
{
|
||||
public const TARGET_CLASS = 1;
|
||||
public const TARGET_METHOD = 2;
|
||||
public const TARGET_PROPERTY = 4;
|
||||
public const TARGET_ANNOTATION = 8;
|
||||
public const TARGET_FUNCTION = 16;
|
||||
public const TARGET_ALL = 31;
|
||||
|
||||
/** @var array<string, int> */
|
||||
private static $map = [
|
||||
'ALL' => self::TARGET_ALL,
|
||||
'CLASS' => self::TARGET_CLASS,
|
||||
'METHOD' => self::TARGET_METHOD,
|
||||
'PROPERTY' => self::TARGET_PROPERTY,
|
||||
'FUNCTION' => self::TARGET_FUNCTION,
|
||||
'ANNOTATION' => self::TARGET_ANNOTATION,
|
||||
];
|
||||
|
||||
/** @phpstan-var list<string> */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* Targets as bitmask.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $targets;
|
||||
|
||||
/**
|
||||
* Literal target declaration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $literal;
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @phpstan-param array{value?: string|list<string>} $values
|
||||
*/
|
||||
public function __construct(array $values)
|
||||
{
|
||||
if (! isset($values['value'])) {
|
||||
$values['value'] = null;
|
||||
}
|
||||
|
||||
if (is_string($values['value'])) {
|
||||
$values['value'] = [$values['value']];
|
||||
}
|
||||
|
||||
if (! is_array($values['value'])) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'@Target expects either a string value, or an array of strings, "%s" given.',
|
||||
is_object($values['value']) ? get_class($values['value']) : gettype($values['value'])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$bitmask = 0;
|
||||
foreach ($values['value'] as $literal) {
|
||||
if (! isset(self::$map[$literal])) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Invalid Target "%s". Available targets: [%s]',
|
||||
$literal,
|
||||
implode(', ', array_keys(self::$map))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$bitmask |= self::$map[$literal];
|
||||
}
|
||||
|
||||
$this->targets = $bitmask;
|
||||
$this->value = $values['value'];
|
||||
$this->literal = implode(', ', $this->value);
|
||||
}
|
||||
}
|
||||
171
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php
vendored
Normal file
171
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use Exception;
|
||||
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Description of AnnotationException
|
||||
*/
|
||||
class AnnotationException extends Exception
|
||||
{
|
||||
/**
|
||||
* Creates a new AnnotationException describing a Syntax error.
|
||||
*
|
||||
* @param string $message Exception message
|
||||
*
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function syntaxError($message)
|
||||
{
|
||||
return new self('[Syntax Error] ' . $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AnnotationException describing a Semantical error.
|
||||
*
|
||||
* @param string $message Exception message
|
||||
*
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function semanticalError($message)
|
||||
{
|
||||
return new self('[Semantical Error] ' . $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AnnotationException describing an error which occurred during
|
||||
* the creation of the annotation.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function creationError($message)
|
||||
{
|
||||
return new self('[Creation Error] ' . $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AnnotationException describing a type error.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function typeError($message)
|
||||
{
|
||||
return new self('[Type Error] ' . $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AnnotationException describing a constant semantical error.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @param string $context
|
||||
*
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function semanticalErrorConstants($identifier, $context = null)
|
||||
{
|
||||
return self::semanticalError(sprintf(
|
||||
"Couldn't find constant %s%s.",
|
||||
$identifier,
|
||||
$context ? ', ' . $context : ''
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AnnotationException describing an type error of an attribute.
|
||||
*
|
||||
* @param string $attributeName
|
||||
* @param string $annotationName
|
||||
* @param string $context
|
||||
* @param string $expected
|
||||
* @param mixed $actual
|
||||
*
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function attributeTypeError($attributeName, $annotationName, $context, $expected, $actual)
|
||||
{
|
||||
return self::typeError(sprintf(
|
||||
'Attribute "%s" of @%s declared on %s expects %s, but got %s.',
|
||||
$attributeName,
|
||||
$annotationName,
|
||||
$context,
|
||||
$expected,
|
||||
is_object($actual) ? 'an instance of ' . get_class($actual) : gettype($actual)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AnnotationException describing an required error of an attribute.
|
||||
*
|
||||
* @param string $attributeName
|
||||
* @param string $annotationName
|
||||
* @param string $context
|
||||
* @param string $expected
|
||||
*
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function requiredError($attributeName, $annotationName, $context, $expected)
|
||||
{
|
||||
return self::typeError(sprintf(
|
||||
'Attribute "%s" of @%s declared on %s expects %s. This value should not be null.',
|
||||
$attributeName,
|
||||
$annotationName,
|
||||
$context,
|
||||
$expected
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AnnotationException describing a invalid enummerator.
|
||||
*
|
||||
* @param string $attributeName
|
||||
* @param string $annotationName
|
||||
* @param string $context
|
||||
* @param mixed $given
|
||||
*
|
||||
* @return AnnotationException
|
||||
*
|
||||
* @phpstan-param list<string> $available
|
||||
*/
|
||||
public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
|
||||
{
|
||||
return new self(sprintf(
|
||||
'[Enum Error] Attribute "%s" of @%s declared on %s accepts only [%s], but got %s.',
|
||||
$attributeName,
|
||||
$annotationName,
|
||||
$context,
|
||||
implode(', ', $available),
|
||||
is_object($given) ? get_class($given) : $given
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function optimizerPlusSaveComments()
|
||||
{
|
||||
return new self(
|
||||
'You have to enable opcache.save_comments=1 or zend_optimizerplus.save_comments=1.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function optimizerPlusLoadComments()
|
||||
{
|
||||
return new self(
|
||||
'You have to enable opcache.load_comments=1 or zend_optimizerplus.load_comments=1.'
|
||||
);
|
||||
}
|
||||
}
|
||||
389
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php
vendored
Normal file
389
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php
vendored
Normal file
@@ -0,0 +1,389 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation;
|
||||
use Doctrine\Common\Annotations\Annotation\Target;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function array_merge;
|
||||
use function class_exists;
|
||||
use function extension_loaded;
|
||||
use function ini_get;
|
||||
|
||||
/**
|
||||
* A reader for docblock annotations.
|
||||
*/
|
||||
class AnnotationReader implements Reader
|
||||
{
|
||||
/**
|
||||
* Global map for imports.
|
||||
*
|
||||
* @var array<string, class-string>
|
||||
*/
|
||||
private static $globalImports = [
|
||||
'ignoreannotation' => Annotation\IgnoreAnnotation::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* A list with annotations that are not causing exceptions when not resolved to an annotation class.
|
||||
*
|
||||
* The names are case sensitive.
|
||||
*
|
||||
* @var array<string, true>
|
||||
*/
|
||||
private static $globalIgnoredNames = ImplicitlyIgnoredAnnotationNames::LIST;
|
||||
|
||||
/**
|
||||
* A list with annotations that are not causing exceptions when not resolved to an annotation class.
|
||||
*
|
||||
* The names are case sensitive.
|
||||
*
|
||||
* @var array<string, true>
|
||||
*/
|
||||
private static $globalIgnoredNamespaces = [];
|
||||
|
||||
/**
|
||||
* Add a new annotation to the globally ignored annotation names with regard to exception handling.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public static function addGlobalIgnoredName($name)
|
||||
{
|
||||
self::$globalIgnoredNames[$name] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new annotation to the globally ignored annotation namespaces with regard to exception handling.
|
||||
*
|
||||
* @param string $namespace
|
||||
*/
|
||||
public static function addGlobalIgnoredNamespace($namespace)
|
||||
{
|
||||
self::$globalIgnoredNamespaces[$namespace] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotations parser.
|
||||
*
|
||||
* @var DocParser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* Annotations parser used to collect parsing metadata.
|
||||
*
|
||||
* @var DocParser
|
||||
*/
|
||||
private $preParser;
|
||||
|
||||
/**
|
||||
* PHP parser used to collect imports.
|
||||
*
|
||||
* @var PhpParser
|
||||
*/
|
||||
private $phpParser;
|
||||
|
||||
/**
|
||||
* In-memory cache mechanism to store imported annotations per class.
|
||||
*
|
||||
* @psalm-var array<'class'|'function', array<string, array<string, class-string>>>
|
||||
*/
|
||||
private $imports = [];
|
||||
|
||||
/**
|
||||
* In-memory cache mechanism to store ignored annotations per class.
|
||||
*
|
||||
* @psalm-var array<'class'|'function', array<string, array<string, true>>>
|
||||
*/
|
||||
private $ignoredAnnotationNames = [];
|
||||
|
||||
/**
|
||||
* Initializes a new AnnotationReader.
|
||||
*
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function __construct(?DocParser $parser = null)
|
||||
{
|
||||
if (
|
||||
extension_loaded('Zend Optimizer+') && (ini_get('zend_optimizerplus.save_comments') === '0' ||
|
||||
ini_get('opcache.save_comments') === '0')
|
||||
) {
|
||||
throw AnnotationException::optimizerPlusSaveComments();
|
||||
}
|
||||
|
||||
if (extension_loaded('Zend OPcache') && ini_get('opcache.save_comments') === 0) {
|
||||
throw AnnotationException::optimizerPlusSaveComments();
|
||||
}
|
||||
|
||||
// Make sure that the IgnoreAnnotation annotation is loaded
|
||||
class_exists(IgnoreAnnotation::class);
|
||||
|
||||
$this->parser = $parser ?: new DocParser();
|
||||
|
||||
$this->preParser = new DocParser();
|
||||
|
||||
$this->preParser->setImports(self::$globalImports);
|
||||
$this->preParser->setIgnoreNotImportedAnnotations(true);
|
||||
$this->preParser->setIgnoredAnnotationNames(self::$globalIgnoredNames);
|
||||
|
||||
$this->phpParser = new PhpParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotations(ReflectionClass $class)
|
||||
{
|
||||
$this->parser->setTarget(Target::TARGET_CLASS);
|
||||
$this->parser->setImports($this->getImports($class));
|
||||
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
|
||||
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
|
||||
|
||||
return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotationName)
|
||||
{
|
||||
$annotations = $this->getClassAnnotations($class);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if ($annotation instanceof $annotationName) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotations(ReflectionProperty $property)
|
||||
{
|
||||
$class = $property->getDeclaringClass();
|
||||
$context = 'property ' . $class->getName() . '::$' . $property->getName();
|
||||
|
||||
$this->parser->setTarget(Target::TARGET_PROPERTY);
|
||||
$this->parser->setImports($this->getPropertyImports($property));
|
||||
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
|
||||
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
|
||||
|
||||
return $this->parser->parse($property->getDocComment(), $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
|
||||
{
|
||||
$annotations = $this->getPropertyAnnotations($property);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if ($annotation instanceof $annotationName) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotations(ReflectionMethod $method)
|
||||
{
|
||||
$class = $method->getDeclaringClass();
|
||||
$context = 'method ' . $class->getName() . '::' . $method->getName() . '()';
|
||||
|
||||
$this->parser->setTarget(Target::TARGET_METHOD);
|
||||
$this->parser->setImports($this->getMethodImports($method));
|
||||
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
|
||||
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
|
||||
|
||||
return $this->parser->parse($method->getDocComment(), $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
|
||||
{
|
||||
$annotations = $this->getMethodAnnotations($method);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if ($annotation instanceof $annotationName) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the annotations applied to a function.
|
||||
*
|
||||
* @phpstan-return list<object> An array of Annotations.
|
||||
*/
|
||||
public function getFunctionAnnotations(ReflectionFunction $function): array
|
||||
{
|
||||
$context = 'function ' . $function->getName();
|
||||
|
||||
$this->parser->setTarget(Target::TARGET_FUNCTION);
|
||||
$this->parser->setImports($this->getImports($function));
|
||||
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($function));
|
||||
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
|
||||
|
||||
return $this->parser->parse($function->getDocComment(), $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function annotation.
|
||||
*
|
||||
* @return object|null The Annotation or NULL, if the requested annotation does not exist.
|
||||
*/
|
||||
public function getFunctionAnnotation(ReflectionFunction $function, string $annotationName)
|
||||
{
|
||||
$annotations = $this->getFunctionAnnotations($function);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if ($annotation instanceof $annotationName) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ignored annotations for the given class or function.
|
||||
*
|
||||
* @param ReflectionClass|ReflectionFunction $reflection
|
||||
*
|
||||
* @return array<string, true>
|
||||
*/
|
||||
private function getIgnoredAnnotationNames($reflection): array
|
||||
{
|
||||
$type = $reflection instanceof ReflectionClass ? 'class' : 'function';
|
||||
$name = $reflection->getName();
|
||||
|
||||
if (isset($this->ignoredAnnotationNames[$type][$name])) {
|
||||
return $this->ignoredAnnotationNames[$type][$name];
|
||||
}
|
||||
|
||||
$this->collectParsingMetadata($reflection);
|
||||
|
||||
return $this->ignoredAnnotationNames[$type][$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves imports for a class or a function.
|
||||
*
|
||||
* @param ReflectionClass|ReflectionFunction $reflection
|
||||
*
|
||||
* @return array<string, class-string>
|
||||
*/
|
||||
private function getImports($reflection): array
|
||||
{
|
||||
$type = $reflection instanceof ReflectionClass ? 'class' : 'function';
|
||||
$name = $reflection->getName();
|
||||
|
||||
if (isset($this->imports[$type][$name])) {
|
||||
return $this->imports[$type][$name];
|
||||
}
|
||||
|
||||
$this->collectParsingMetadata($reflection);
|
||||
|
||||
return $this->imports[$type][$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves imports for methods.
|
||||
*
|
||||
* @return array<string, class-string>
|
||||
*/
|
||||
private function getMethodImports(ReflectionMethod $method)
|
||||
{
|
||||
$class = $method->getDeclaringClass();
|
||||
$classImports = $this->getImports($class);
|
||||
|
||||
$traitImports = [];
|
||||
|
||||
foreach ($class->getTraits() as $trait) {
|
||||
if (
|
||||
! $trait->hasMethod($method->getName())
|
||||
|| $trait->getFileName() !== $method->getFileName()
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$traitImports = array_merge($traitImports, $this->phpParser->parseUseStatements($trait));
|
||||
}
|
||||
|
||||
return array_merge($classImports, $traitImports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves imports for properties.
|
||||
*
|
||||
* @return array<string, class-string>
|
||||
*/
|
||||
private function getPropertyImports(ReflectionProperty $property)
|
||||
{
|
||||
$class = $property->getDeclaringClass();
|
||||
$classImports = $this->getImports($class);
|
||||
|
||||
$traitImports = [];
|
||||
|
||||
foreach ($class->getTraits() as $trait) {
|
||||
if (! $trait->hasProperty($property->getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$traitImports = array_merge($traitImports, $this->phpParser->parseUseStatements($trait));
|
||||
}
|
||||
|
||||
return array_merge($classImports, $traitImports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects parsing metadata for a given class or function.
|
||||
*
|
||||
* @param ReflectionClass|ReflectionFunction $reflection
|
||||
*/
|
||||
private function collectParsingMetadata($reflection): void
|
||||
{
|
||||
$type = $reflection instanceof ReflectionClass ? 'class' : 'function';
|
||||
$name = $reflection->getName();
|
||||
|
||||
$ignoredAnnotationNames = self::$globalIgnoredNames;
|
||||
$annotations = $this->preParser->parse($reflection->getDocComment(), $type . ' ' . $name);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if (! ($annotation instanceof IgnoreAnnotation)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($annotation->names as $annot) {
|
||||
$ignoredAnnotationNames[$annot] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->imports[$type][$name] = array_merge(
|
||||
self::$globalImports,
|
||||
$this->phpParser->parseUseStatements($reflection),
|
||||
[
|
||||
'__NAMESPACE__' => $reflection->getNamespaceName(),
|
||||
'self' => $name,
|
||||
]
|
||||
);
|
||||
|
||||
$this->ignoredAnnotationNames[$type][$name] = $ignoredAnnotationNames;
|
||||
}
|
||||
}
|
||||
190
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php
vendored
Normal file
190
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_merge;
|
||||
use function class_exists;
|
||||
use function in_array;
|
||||
use function is_file;
|
||||
use function str_replace;
|
||||
use function stream_resolve_include_path;
|
||||
use function strpos;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
final class AnnotationRegistry
|
||||
{
|
||||
/**
|
||||
* A map of namespaces to use for autoloading purposes based on a PSR-0 convention.
|
||||
*
|
||||
* Contains the namespace as key and an array of directories as value. If the value is NULL
|
||||
* the include path is used for checking for the corresponding file.
|
||||
*
|
||||
* This autoloading mechanism does not utilize the PHP autoloading but implements autoloading on its own.
|
||||
*
|
||||
* @var string[][]|string[]|null[]
|
||||
*/
|
||||
private static $autoloadNamespaces = [];
|
||||
|
||||
/**
|
||||
* A map of autoloader callables.
|
||||
*
|
||||
* @var callable[]
|
||||
*/
|
||||
private static $loaders = [];
|
||||
|
||||
/**
|
||||
* An array of classes which cannot be found
|
||||
*
|
||||
* @var null[] indexed by class name
|
||||
*/
|
||||
private static $failedToAutoload = [];
|
||||
|
||||
/**
|
||||
* Whenever registerFile() was used. Disables use of standard autoloader.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $registerFileUsed = false;
|
||||
|
||||
public static function reset(): void
|
||||
{
|
||||
self::$autoloadNamespaces = [];
|
||||
self::$loaders = [];
|
||||
self::$failedToAutoload = [];
|
||||
self::$registerFileUsed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers file.
|
||||
*
|
||||
* @deprecated This method is deprecated and will be removed in
|
||||
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
|
||||
*/
|
||||
public static function registerFile(string $file): void
|
||||
{
|
||||
self::$registerFileUsed = true;
|
||||
|
||||
require_once $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a namespace with one or many directories to look for files or null for the include path.
|
||||
*
|
||||
* Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
|
||||
*
|
||||
* @deprecated This method is deprecated and will be removed in
|
||||
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
|
||||
*
|
||||
* @phpstan-param string|list<string>|null $dirs
|
||||
*/
|
||||
public static function registerAutoloadNamespace(string $namespace, $dirs = null): void
|
||||
{
|
||||
self::$autoloadNamespaces[$namespace] = $dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple namespaces.
|
||||
*
|
||||
* Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
|
||||
*
|
||||
* @deprecated This method is deprecated and will be removed in
|
||||
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
|
||||
*
|
||||
* @param string[][]|string[]|null[] $namespaces indexed by namespace name
|
||||
*/
|
||||
public static function registerAutoloadNamespaces(array $namespaces): void
|
||||
{
|
||||
self::$autoloadNamespaces = array_merge(self::$autoloadNamespaces, $namespaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an autoloading callable for annotations, much like spl_autoload_register().
|
||||
*
|
||||
* NOTE: These class loaders HAVE to be silent when a class was not found!
|
||||
* IMPORTANT: Loaders have to return true if they loaded a class that could contain the searched annotation class.
|
||||
*
|
||||
* @deprecated This method is deprecated and will be removed in
|
||||
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
|
||||
*/
|
||||
public static function registerLoader(callable $callable): void
|
||||
{
|
||||
// Reset our static cache now that we have a new loader to work with
|
||||
self::$failedToAutoload = [];
|
||||
self::$loaders[] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an autoloading callable for annotations, if it is not already registered
|
||||
*
|
||||
* @deprecated This method is deprecated and will be removed in
|
||||
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
|
||||
*/
|
||||
public static function registerUniqueLoader(callable $callable): void
|
||||
{
|
||||
if (in_array($callable, self::$loaders, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::registerLoader($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Autoloads an annotation class silently.
|
||||
*/
|
||||
public static function loadAnnotationClass(string $class): bool
|
||||
{
|
||||
if (class_exists($class, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (array_key_exists($class, self::$failedToAutoload)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (self::$autoloadNamespaces as $namespace => $dirs) {
|
||||
if (strpos($class, $namespace) !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
|
||||
|
||||
if ($dirs === null) {
|
||||
$path = stream_resolve_include_path($file);
|
||||
if ($path) {
|
||||
require $path;
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
foreach ((array) $dirs as $dir) {
|
||||
if (is_file($dir . DIRECTORY_SEPARATOR . $file)) {
|
||||
require $dir . DIRECTORY_SEPARATOR . $file;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (self::$loaders as $loader) {
|
||||
if ($loader($class) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
self::$loaders === [] &&
|
||||
self::$autoloadNamespaces === [] &&
|
||||
self::$registerFileUsed === false &&
|
||||
class_exists($class)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self::$failedToAutoload[$class] = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
268
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php
vendored
Normal file
268
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function filemtime;
|
||||
use function max;
|
||||
use function time;
|
||||
|
||||
/**
|
||||
* A cache aware annotation reader.
|
||||
*
|
||||
* @deprecated the CachedReader is deprecated and will be removed
|
||||
* in version 2.0.0 of doctrine/annotations. Please use the
|
||||
* {@see \Doctrine\Common\Annotations\PsrCachedReader} instead.
|
||||
*/
|
||||
final class CachedReader implements Reader
|
||||
{
|
||||
/** @var Reader */
|
||||
private $delegate;
|
||||
|
||||
/** @var Cache */
|
||||
private $cache;
|
||||
|
||||
/** @var bool */
|
||||
private $debug;
|
||||
|
||||
/** @var array<string, array<object>> */
|
||||
private $loadedAnnotations = [];
|
||||
|
||||
/** @var int[] */
|
||||
private $loadedFilemtimes = [];
|
||||
|
||||
/**
|
||||
* @param bool $debug
|
||||
*/
|
||||
public function __construct(Reader $reader, Cache $cache, $debug = false)
|
||||
{
|
||||
$this->delegate = $reader;
|
||||
$this->cache = $cache;
|
||||
$this->debug = (bool) $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotations(ReflectionClass $class)
|
||||
{
|
||||
$cacheKey = $class->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$cacheKey])) {
|
||||
return $this->loadedAnnotations[$cacheKey];
|
||||
}
|
||||
|
||||
$annots = $this->fetchFromCache($cacheKey, $class);
|
||||
if ($annots === false) {
|
||||
$annots = $this->delegate->getClassAnnotations($class);
|
||||
$this->saveToCache($cacheKey, $annots);
|
||||
}
|
||||
|
||||
return $this->loadedAnnotations[$cacheKey] = $annots;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotationName)
|
||||
{
|
||||
foreach ($this->getClassAnnotations($class) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotations(ReflectionProperty $property)
|
||||
{
|
||||
$class = $property->getDeclaringClass();
|
||||
$cacheKey = $class->getName() . '$' . $property->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$cacheKey])) {
|
||||
return $this->loadedAnnotations[$cacheKey];
|
||||
}
|
||||
|
||||
$annots = $this->fetchFromCache($cacheKey, $class);
|
||||
if ($annots === false) {
|
||||
$annots = $this->delegate->getPropertyAnnotations($property);
|
||||
$this->saveToCache($cacheKey, $annots);
|
||||
}
|
||||
|
||||
return $this->loadedAnnotations[$cacheKey] = $annots;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
|
||||
{
|
||||
foreach ($this->getPropertyAnnotations($property) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotations(ReflectionMethod $method)
|
||||
{
|
||||
$class = $method->getDeclaringClass();
|
||||
$cacheKey = $class->getName() . '#' . $method->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$cacheKey])) {
|
||||
return $this->loadedAnnotations[$cacheKey];
|
||||
}
|
||||
|
||||
$annots = $this->fetchFromCache($cacheKey, $class);
|
||||
if ($annots === false) {
|
||||
$annots = $this->delegate->getMethodAnnotations($method);
|
||||
$this->saveToCache($cacheKey, $annots);
|
||||
}
|
||||
|
||||
return $this->loadedAnnotations[$cacheKey] = $annots;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
|
||||
{
|
||||
foreach ($this->getMethodAnnotations($method) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears loaded annotations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearLoadedAnnotations()
|
||||
{
|
||||
$this->loadedAnnotations = [];
|
||||
$this->loadedFilemtimes = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a value from the cache.
|
||||
*
|
||||
* @param string $cacheKey The cache key.
|
||||
*
|
||||
* @return mixed The cached value or false when the value is not in cache.
|
||||
*/
|
||||
private function fetchFromCache($cacheKey, ReflectionClass $class)
|
||||
{
|
||||
$data = $this->cache->fetch($cacheKey);
|
||||
if ($data !== false) {
|
||||
if (! $this->debug || $this->isCacheFresh($cacheKey, $class)) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a value to the cache.
|
||||
*
|
||||
* @param string $cacheKey The cache key.
|
||||
* @param mixed $value The value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function saveToCache($cacheKey, $value)
|
||||
{
|
||||
$this->cache->save($cacheKey, $value);
|
||||
if (! $this->debug) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cache->save('[C]' . $cacheKey, time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cache is fresh.
|
||||
*
|
||||
* @param string $cacheKey
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isCacheFresh($cacheKey, ReflectionClass $class)
|
||||
{
|
||||
$lastModification = $this->getLastModification($class);
|
||||
if ($lastModification === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->cache->fetch('[C]' . $cacheKey) >= $lastModification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time the class was last modified, testing traits and parents
|
||||
*/
|
||||
private function getLastModification(ReflectionClass $class): int
|
||||
{
|
||||
$filename = $class->getFileName();
|
||||
|
||||
if (isset($this->loadedFilemtimes[$filename])) {
|
||||
return $this->loadedFilemtimes[$filename];
|
||||
}
|
||||
|
||||
$parent = $class->getParentClass();
|
||||
|
||||
$lastModification = max(array_merge(
|
||||
[$filename ? filemtime($filename) : 0],
|
||||
array_map(function (ReflectionClass $reflectionTrait): int {
|
||||
return $this->getTraitLastModificationTime($reflectionTrait);
|
||||
}, $class->getTraits()),
|
||||
array_map(function (ReflectionClass $class): int {
|
||||
return $this->getLastModification($class);
|
||||
}, $class->getInterfaces()),
|
||||
$parent ? [$this->getLastModification($parent)] : []
|
||||
));
|
||||
|
||||
assert($lastModification !== false);
|
||||
|
||||
return $this->loadedFilemtimes[$filename] = $lastModification;
|
||||
}
|
||||
|
||||
private function getTraitLastModificationTime(ReflectionClass $reflectionTrait): int
|
||||
{
|
||||
$fileName = $reflectionTrait->getFileName();
|
||||
|
||||
if (isset($this->loadedFilemtimes[$fileName])) {
|
||||
return $this->loadedFilemtimes[$fileName];
|
||||
}
|
||||
|
||||
$lastModificationTime = max(array_merge(
|
||||
[$fileName ? filemtime($fileName) : 0],
|
||||
array_map(function (ReflectionClass $reflectionTrait): int {
|
||||
return $this->getTraitLastModificationTime($reflectionTrait);
|
||||
}, $reflectionTrait->getTraits())
|
||||
));
|
||||
|
||||
assert($lastModificationTime !== false);
|
||||
|
||||
return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
|
||||
}
|
||||
}
|
||||
129
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php
vendored
Normal file
129
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use Doctrine\Common\Lexer\AbstractLexer;
|
||||
|
||||
use function ctype_alpha;
|
||||
use function is_numeric;
|
||||
use function str_replace;
|
||||
use function stripos;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Simple lexer for docblock annotations.
|
||||
*/
|
||||
final class DocLexer extends AbstractLexer
|
||||
{
|
||||
public const T_NONE = 1;
|
||||
public const T_INTEGER = 2;
|
||||
public const T_STRING = 3;
|
||||
public const T_FLOAT = 4;
|
||||
|
||||
// All tokens that are also identifiers should be >= 100
|
||||
public const T_IDENTIFIER = 100;
|
||||
public const T_AT = 101;
|
||||
public const T_CLOSE_CURLY_BRACES = 102;
|
||||
public const T_CLOSE_PARENTHESIS = 103;
|
||||
public const T_COMMA = 104;
|
||||
public const T_EQUALS = 105;
|
||||
public const T_FALSE = 106;
|
||||
public const T_NAMESPACE_SEPARATOR = 107;
|
||||
public const T_OPEN_CURLY_BRACES = 108;
|
||||
public const T_OPEN_PARENTHESIS = 109;
|
||||
public const T_TRUE = 110;
|
||||
public const T_NULL = 111;
|
||||
public const T_COLON = 112;
|
||||
public const T_MINUS = 113;
|
||||
|
||||
/** @var array<string, int> */
|
||||
protected $noCase = [
|
||||
'@' => self::T_AT,
|
||||
',' => self::T_COMMA,
|
||||
'(' => self::T_OPEN_PARENTHESIS,
|
||||
')' => self::T_CLOSE_PARENTHESIS,
|
||||
'{' => self::T_OPEN_CURLY_BRACES,
|
||||
'}' => self::T_CLOSE_CURLY_BRACES,
|
||||
'=' => self::T_EQUALS,
|
||||
':' => self::T_COLON,
|
||||
'-' => self::T_MINUS,
|
||||
'\\' => self::T_NAMESPACE_SEPARATOR,
|
||||
];
|
||||
|
||||
/** @var array<string, int> */
|
||||
protected $withCase = [
|
||||
'true' => self::T_TRUE,
|
||||
'false' => self::T_FALSE,
|
||||
'null' => self::T_NULL,
|
||||
];
|
||||
|
||||
/**
|
||||
* Whether the next token starts immediately, or if there were
|
||||
* non-captured symbols before that
|
||||
*/
|
||||
public function nextTokenIsAdjacent(): bool
|
||||
{
|
||||
return $this->token === null
|
||||
|| ($this->lookahead !== null
|
||||
&& ($this->lookahead['position'] - $this->token['position']) === strlen($this->token['value']));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCatchablePatterns()
|
||||
{
|
||||
return [
|
||||
'[a-z_\\\][a-z0-9_\:\\\]*[a-z_][a-z0-9_]*',
|
||||
'(?:[+-]?[0-9]+(?:[\.][0-9]+)*)(?:[eE][+-]?[0-9]+)?',
|
||||
'"(?:""|[^"])*+"',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNonCatchablePatterns()
|
||||
{
|
||||
return ['\s+', '\*+', '(.)'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getType(&$value)
|
||||
{
|
||||
$type = self::T_NONE;
|
||||
|
||||
if ($value[0] === '"') {
|
||||
$value = str_replace('""', '"', substr($value, 1, strlen($value) - 2));
|
||||
|
||||
return self::T_STRING;
|
||||
}
|
||||
|
||||
if (isset($this->noCase[$value])) {
|
||||
return $this->noCase[$value];
|
||||
}
|
||||
|
||||
if ($value[0] === '_' || $value[0] === '\\' || ctype_alpha($value[0])) {
|
||||
return self::T_IDENTIFIER;
|
||||
}
|
||||
|
||||
$lowerValue = strtolower($value);
|
||||
|
||||
if (isset($this->withCase[$lowerValue])) {
|
||||
return $this->withCase[$lowerValue];
|
||||
}
|
||||
|
||||
// Checking numeric value
|
||||
if (is_numeric($value)) {
|
||||
return strpos($value, '.') !== false || stripos($value, 'e') !== false
|
||||
? self::T_FLOAT : self::T_INTEGER;
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
1459
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
vendored
Normal file
1459
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
315
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.php
vendored
Normal file
315
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.php
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
use RuntimeException;
|
||||
|
||||
use function chmod;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function gettype;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function is_int;
|
||||
use function is_writable;
|
||||
use function mkdir;
|
||||
use function rename;
|
||||
use function rtrim;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
use function sprintf;
|
||||
use function strtr;
|
||||
use function tempnam;
|
||||
use function uniqid;
|
||||
use function unlink;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* File cache reader for annotations.
|
||||
*
|
||||
* @deprecated the FileCacheReader is deprecated and will be removed
|
||||
* in version 2.0.0 of doctrine/annotations. Please use the
|
||||
* {@see \Doctrine\Common\Annotations\PsrCachedReader} instead.
|
||||
*/
|
||||
class FileCacheReader implements Reader
|
||||
{
|
||||
/** @var Reader */
|
||||
private $reader;
|
||||
|
||||
/** @var string */
|
||||
private $dir;
|
||||
|
||||
/** @var bool */
|
||||
private $debug;
|
||||
|
||||
/** @phpstan-var array<string, list<object>> */
|
||||
private $loadedAnnotations = [];
|
||||
|
||||
/** @var array<string, string> */
|
||||
private $classNameHashes = [];
|
||||
|
||||
/** @var int */
|
||||
private $umask;
|
||||
|
||||
/**
|
||||
* @param string $cacheDir
|
||||
* @param bool $debug
|
||||
* @param int $umask
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002)
|
||||
{
|
||||
if (! is_int($umask)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The parameter umask must be an integer, was: %s',
|
||||
gettype($umask)
|
||||
));
|
||||
}
|
||||
|
||||
$this->reader = $reader;
|
||||
$this->umask = $umask;
|
||||
|
||||
if (! is_dir($cacheDir) && ! @mkdir($cacheDir, 0777 & (~$this->umask), true)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The directory "%s" does not exist and could not be created.',
|
||||
$cacheDir
|
||||
));
|
||||
}
|
||||
|
||||
$this->dir = rtrim($cacheDir, '\\/');
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotations(ReflectionClass $class)
|
||||
{
|
||||
if (! isset($this->classNameHashes[$class->name])) {
|
||||
$this->classNameHashes[$class->name] = sha1($class->name);
|
||||
}
|
||||
|
||||
$key = $this->classNameHashes[$class->name];
|
||||
|
||||
if (isset($this->loadedAnnotations[$key])) {
|
||||
return $this->loadedAnnotations[$key];
|
||||
}
|
||||
|
||||
$path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
|
||||
if (! is_file($path)) {
|
||||
$annot = $this->reader->getClassAnnotations($class);
|
||||
$this->saveCacheFile($path, $annot);
|
||||
|
||||
return $this->loadedAnnotations[$key] = $annot;
|
||||
}
|
||||
|
||||
$filename = $class->getFilename();
|
||||
if (
|
||||
$this->debug
|
||||
&& $filename !== false
|
||||
&& filemtime($path) < filemtime($filename)
|
||||
) {
|
||||
@unlink($path);
|
||||
|
||||
$annot = $this->reader->getClassAnnotations($class);
|
||||
$this->saveCacheFile($path, $annot);
|
||||
|
||||
return $this->loadedAnnotations[$key] = $annot;
|
||||
}
|
||||
|
||||
return $this->loadedAnnotations[$key] = include $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotations(ReflectionProperty $property)
|
||||
{
|
||||
$class = $property->getDeclaringClass();
|
||||
if (! isset($this->classNameHashes[$class->name])) {
|
||||
$this->classNameHashes[$class->name] = sha1($class->name);
|
||||
}
|
||||
|
||||
$key = $this->classNameHashes[$class->name] . '$' . $property->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$key])) {
|
||||
return $this->loadedAnnotations[$key];
|
||||
}
|
||||
|
||||
$path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
|
||||
if (! is_file($path)) {
|
||||
$annot = $this->reader->getPropertyAnnotations($property);
|
||||
$this->saveCacheFile($path, $annot);
|
||||
|
||||
return $this->loadedAnnotations[$key] = $annot;
|
||||
}
|
||||
|
||||
$filename = $class->getFilename();
|
||||
if (
|
||||
$this->debug
|
||||
&& $filename !== false
|
||||
&& filemtime($path) < filemtime($filename)
|
||||
) {
|
||||
@unlink($path);
|
||||
|
||||
$annot = $this->reader->getPropertyAnnotations($property);
|
||||
$this->saveCacheFile($path, $annot);
|
||||
|
||||
return $this->loadedAnnotations[$key] = $annot;
|
||||
}
|
||||
|
||||
return $this->loadedAnnotations[$key] = include $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotations(ReflectionMethod $method)
|
||||
{
|
||||
$class = $method->getDeclaringClass();
|
||||
if (! isset($this->classNameHashes[$class->name])) {
|
||||
$this->classNameHashes[$class->name] = sha1($class->name);
|
||||
}
|
||||
|
||||
$key = $this->classNameHashes[$class->name] . '#' . $method->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$key])) {
|
||||
return $this->loadedAnnotations[$key];
|
||||
}
|
||||
|
||||
$path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
|
||||
if (! is_file($path)) {
|
||||
$annot = $this->reader->getMethodAnnotations($method);
|
||||
$this->saveCacheFile($path, $annot);
|
||||
|
||||
return $this->loadedAnnotations[$key] = $annot;
|
||||
}
|
||||
|
||||
$filename = $class->getFilename();
|
||||
if (
|
||||
$this->debug
|
||||
&& $filename !== false
|
||||
&& filemtime($path) < filemtime($filename)
|
||||
) {
|
||||
@unlink($path);
|
||||
|
||||
$annot = $this->reader->getMethodAnnotations($method);
|
||||
$this->saveCacheFile($path, $annot);
|
||||
|
||||
return $this->loadedAnnotations[$key] = $annot;
|
||||
}
|
||||
|
||||
return $this->loadedAnnotations[$key] = include $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the cache file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function saveCacheFile($path, $data)
|
||||
{
|
||||
if (! is_writable($this->dir)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
<<<'EXCEPTION'
|
||||
The directory "%s" is not writable. Both the webserver and the console user need access.
|
||||
You can manage access rights for multiple users with "chmod +a".
|
||||
If your system does not support this, check out the acl package.,
|
||||
EXCEPTION
|
||||
,
|
||||
$this->dir
|
||||
));
|
||||
}
|
||||
|
||||
$tempfile = tempnam($this->dir, uniqid('', true));
|
||||
|
||||
if ($tempfile === false) {
|
||||
throw new RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir));
|
||||
}
|
||||
|
||||
@chmod($tempfile, 0666 & (~$this->umask));
|
||||
|
||||
$written = file_put_contents(
|
||||
$tempfile,
|
||||
'<?php return unserialize(' . var_export(serialize($data), true) . ');'
|
||||
);
|
||||
|
||||
if ($written === false) {
|
||||
throw new RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
|
||||
}
|
||||
|
||||
@chmod($tempfile, 0666 & (~$this->umask));
|
||||
|
||||
if (rename($tempfile, $path) === false) {
|
||||
@unlink($tempfile);
|
||||
|
||||
throw new RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotationName)
|
||||
{
|
||||
$annotations = $this->getClassAnnotations($class);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if ($annotation instanceof $annotationName) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
|
||||
{
|
||||
$annotations = $this->getMethodAnnotations($method);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if ($annotation instanceof $annotationName) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
|
||||
{
|
||||
$annotations = $this->getPropertyAnnotations($property);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
if ($annotation instanceof $annotationName) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears loaded annotations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearLoadedAnnotations()
|
||||
{
|
||||
$this->loadedAnnotations = [];
|
||||
}
|
||||
}
|
||||
177
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php
vendored
Normal file
177
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
/**
|
||||
* A list of annotations that are implicitly ignored during the parsing process.
|
||||
*
|
||||
* All names are case sensitive.
|
||||
*/
|
||||
final class ImplicitlyIgnoredAnnotationNames
|
||||
{
|
||||
private const Reserved = [
|
||||
'Annotation' => true,
|
||||
'Attribute' => true,
|
||||
'Attributes' => true,
|
||||
/* Can we enable this? 'Enum' => true, */
|
||||
'Required' => true,
|
||||
'Target' => true,
|
||||
'NamedArgumentConstructor' => true,
|
||||
];
|
||||
|
||||
private const WidelyUsedNonStandard = [
|
||||
'fix' => true,
|
||||
'fixme' => true,
|
||||
'override' => true,
|
||||
];
|
||||
|
||||
private const PhpDocumentor1 = [
|
||||
'abstract' => true,
|
||||
'access' => true,
|
||||
'code' => true,
|
||||
'deprec' => true,
|
||||
'endcode' => true,
|
||||
'exception' => true,
|
||||
'final' => true,
|
||||
'ingroup' => true,
|
||||
'inheritdoc' => true,
|
||||
'inheritDoc' => true,
|
||||
'magic' => true,
|
||||
'name' => true,
|
||||
'private' => true,
|
||||
'static' => true,
|
||||
'staticvar' => true,
|
||||
'staticVar' => true,
|
||||
'toc' => true,
|
||||
'tutorial' => true,
|
||||
'throw' => true,
|
||||
];
|
||||
|
||||
private const PhpDocumentor2 = [
|
||||
'api' => true,
|
||||
'author' => true,
|
||||
'category' => true,
|
||||
'copyright' => true,
|
||||
'deprecated' => true,
|
||||
'example' => true,
|
||||
'filesource' => true,
|
||||
'global' => true,
|
||||
'ignore' => true,
|
||||
/* Can we enable this? 'index' => true, */
|
||||
'internal' => true,
|
||||
'license' => true,
|
||||
'link' => true,
|
||||
'method' => true,
|
||||
'package' => true,
|
||||
'param' => true,
|
||||
'property' => true,
|
||||
'property-read' => true,
|
||||
'property-write' => true,
|
||||
'return' => true,
|
||||
'see' => true,
|
||||
'since' => true,
|
||||
'source' => true,
|
||||
'subpackage' => true,
|
||||
'throws' => true,
|
||||
'todo' => true,
|
||||
'TODO' => true,
|
||||
'usedby' => true,
|
||||
'uses' => true,
|
||||
'var' => true,
|
||||
'version' => true,
|
||||
];
|
||||
|
||||
private const PHPUnit = [
|
||||
'author' => true,
|
||||
'after' => true,
|
||||
'afterClass' => true,
|
||||
'backupGlobals' => true,
|
||||
'backupStaticAttributes' => true,
|
||||
'before' => true,
|
||||
'beforeClass' => true,
|
||||
'codeCoverageIgnore' => true,
|
||||
'codeCoverageIgnoreStart' => true,
|
||||
'codeCoverageIgnoreEnd' => true,
|
||||
'covers' => true,
|
||||
'coversDefaultClass' => true,
|
||||
'coversNothing' => true,
|
||||
'dataProvider' => true,
|
||||
'depends' => true,
|
||||
'doesNotPerformAssertions' => true,
|
||||
'expectedException' => true,
|
||||
'expectedExceptionCode' => true,
|
||||
'expectedExceptionMessage' => true,
|
||||
'expectedExceptionMessageRegExp' => true,
|
||||
'group' => true,
|
||||
'large' => true,
|
||||
'medium' => true,
|
||||
'preserveGlobalState' => true,
|
||||
'requires' => true,
|
||||
'runTestsInSeparateProcesses' => true,
|
||||
'runInSeparateProcess' => true,
|
||||
'small' => true,
|
||||
'test' => true,
|
||||
'testdox' => true,
|
||||
'testWith' => true,
|
||||
'ticket' => true,
|
||||
'uses' => true,
|
||||
];
|
||||
|
||||
private const PhpCheckStyle = ['SuppressWarnings' => true];
|
||||
|
||||
private const PhpStorm = ['noinspection' => true];
|
||||
|
||||
private const PEAR = ['package_version' => true];
|
||||
|
||||
private const PlainUML = [
|
||||
'startuml' => true,
|
||||
'enduml' => true,
|
||||
];
|
||||
|
||||
private const Symfony = ['experimental' => true];
|
||||
|
||||
private const PhpCodeSniffer = [
|
||||
'codingStandardsIgnoreStart' => true,
|
||||
'codingStandardsIgnoreEnd' => true,
|
||||
];
|
||||
|
||||
private const SlevomatCodingStandard = ['phpcsSuppress' => true];
|
||||
|
||||
private const Phan = ['suppress' => true];
|
||||
|
||||
private const Rector = ['noRector' => true];
|
||||
|
||||
private const StaticAnalysis = [
|
||||
// PHPStan, Psalm
|
||||
'extends' => true,
|
||||
'implements' => true,
|
||||
'template' => true,
|
||||
'use' => true,
|
||||
|
||||
// Psalm
|
||||
'pure' => true,
|
||||
'immutable' => true,
|
||||
];
|
||||
|
||||
public const LIST = self::Reserved
|
||||
+ self::WidelyUsedNonStandard
|
||||
+ self::PhpDocumentor1
|
||||
+ self::PhpDocumentor2
|
||||
+ self::PHPUnit
|
||||
+ self::PhpCheckStyle
|
||||
+ self::PhpStorm
|
||||
+ self::PEAR
|
||||
+ self::PlainUML
|
||||
+ self::Symfony
|
||||
+ self::SlevomatCodingStandard
|
||||
+ self::PhpCodeSniffer
|
||||
+ self::Phan
|
||||
+ self::Rector
|
||||
+ self::StaticAnalysis;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
}
|
||||
100
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php
vendored
Normal file
100
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function call_user_func_array;
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* Allows the reader to be used in-place of Doctrine's reader.
|
||||
*/
|
||||
class IndexedReader implements Reader
|
||||
{
|
||||
/** @var Reader */
|
||||
private $delegate;
|
||||
|
||||
public function __construct(Reader $reader)
|
||||
{
|
||||
$this->delegate = $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotations(ReflectionClass $class)
|
||||
{
|
||||
$annotations = [];
|
||||
foreach ($this->delegate->getClassAnnotations($class) as $annot) {
|
||||
$annotations[get_class($annot)] = $annot;
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotation)
|
||||
{
|
||||
return $this->delegate->getClassAnnotation($class, $annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotations(ReflectionMethod $method)
|
||||
{
|
||||
$annotations = [];
|
||||
foreach ($this->delegate->getMethodAnnotations($method) as $annot) {
|
||||
$annotations[get_class($annot)] = $annot;
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotation)
|
||||
{
|
||||
return $this->delegate->getMethodAnnotation($method, $annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotations(ReflectionProperty $property)
|
||||
{
|
||||
$annotations = [];
|
||||
foreach ($this->delegate->getPropertyAnnotations($property) as $annot) {
|
||||
$annotations[get_class($annot)] = $annot;
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotation)
|
||||
{
|
||||
return $this->delegate->getPropertyAnnotation($property, $annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxies all methods to the delegate.
|
||||
*
|
||||
* @param string $method
|
||||
* @param mixed[] $args
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array([$this->delegate, $method], $args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
/**
|
||||
* Marker interface for PHP7/PHP8 compatible support
|
||||
* for named arguments (and constructor property promotion).
|
||||
*
|
||||
* @deprecated Implementing this interface is deprecated
|
||||
* Use the Annotation @NamedArgumentConstructor instead
|
||||
*/
|
||||
interface NamedArgumentConstructorAnnotation
|
||||
{
|
||||
}
|
||||
92
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php
vendored
Normal file
92
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use SplFileObject;
|
||||
|
||||
use function is_file;
|
||||
use function method_exists;
|
||||
use function preg_quote;
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* Parses a file for namespaces/use/class declarations.
|
||||
*/
|
||||
final class PhpParser
|
||||
{
|
||||
/**
|
||||
* Parses a class.
|
||||
*
|
||||
* @deprecated use parseUseStatements instead
|
||||
*
|
||||
* @param ReflectionClass $class A <code>ReflectionClass</code> object.
|
||||
*
|
||||
* @return array<string, class-string> A list with use statements in the form (Alias => FQN).
|
||||
*/
|
||||
public function parseClass(ReflectionClass $class)
|
||||
{
|
||||
return $this->parseUseStatements($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a class or function for use statements.
|
||||
*
|
||||
* @param ReflectionClass|ReflectionFunction $reflection
|
||||
*
|
||||
* @psalm-return array<string, string> a list with use statements in the form (Alias => FQN).
|
||||
*/
|
||||
public function parseUseStatements($reflection): array
|
||||
{
|
||||
if (method_exists($reflection, 'getUseStatements')) {
|
||||
return $reflection->getUseStatements();
|
||||
}
|
||||
|
||||
$filename = $reflection->getFileName();
|
||||
|
||||
if ($filename === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$content = $this->getFileContent($filename, $reflection->getStartLine());
|
||||
|
||||
if ($content === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$namespace = preg_quote($reflection->getNamespaceName());
|
||||
$content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
|
||||
$tokenizer = new TokenParser('<?php ' . $content);
|
||||
|
||||
return $tokenizer->parseUseStatements($reflection->getNamespaceName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content of the file right up to the given line number.
|
||||
*
|
||||
* @param string $filename The name of the file to load.
|
||||
* @param int $lineNumber The number of lines to read from file.
|
||||
*
|
||||
* @return string|null The content of the file or null if the file does not exist.
|
||||
*/
|
||||
private function getFileContent($filename, $lineNumber)
|
||||
{
|
||||
if (! is_file($filename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$content = '';
|
||||
$lineCnt = 0;
|
||||
$file = new SplFileObject($filename);
|
||||
while (! $file->eof()) {
|
||||
if ($lineCnt++ === $lineNumber) {
|
||||
break;
|
||||
}
|
||||
|
||||
$content .= $file->fgets();
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
232
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php
vendored
Normal file
232
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
use Reflector;
|
||||
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function filemtime;
|
||||
use function max;
|
||||
use function rawurlencode;
|
||||
use function time;
|
||||
|
||||
/**
|
||||
* A cache aware annotation reader.
|
||||
*/
|
||||
final class PsrCachedReader implements Reader
|
||||
{
|
||||
/** @var Reader */
|
||||
private $delegate;
|
||||
|
||||
/** @var CacheItemPoolInterface */
|
||||
private $cache;
|
||||
|
||||
/** @var bool */
|
||||
private $debug;
|
||||
|
||||
/** @var array<string, array<object>> */
|
||||
private $loadedAnnotations = [];
|
||||
|
||||
/** @var int[] */
|
||||
private $loadedFilemtimes = [];
|
||||
|
||||
public function __construct(Reader $reader, CacheItemPoolInterface $cache, bool $debug = false)
|
||||
{
|
||||
$this->delegate = $reader;
|
||||
$this->cache = $cache;
|
||||
$this->debug = (bool) $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotations(ReflectionClass $class)
|
||||
{
|
||||
$cacheKey = $class->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$cacheKey])) {
|
||||
return $this->loadedAnnotations[$cacheKey];
|
||||
}
|
||||
|
||||
$annots = $this->fetchFromCache($cacheKey, $class, 'getClassAnnotations', $class);
|
||||
|
||||
return $this->loadedAnnotations[$cacheKey] = $annots;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotationName)
|
||||
{
|
||||
foreach ($this->getClassAnnotations($class) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotations(ReflectionProperty $property)
|
||||
{
|
||||
$class = $property->getDeclaringClass();
|
||||
$cacheKey = $class->getName() . '$' . $property->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$cacheKey])) {
|
||||
return $this->loadedAnnotations[$cacheKey];
|
||||
}
|
||||
|
||||
$annots = $this->fetchFromCache($cacheKey, $class, 'getPropertyAnnotations', $property);
|
||||
|
||||
return $this->loadedAnnotations[$cacheKey] = $annots;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
|
||||
{
|
||||
foreach ($this->getPropertyAnnotations($property) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotations(ReflectionMethod $method)
|
||||
{
|
||||
$class = $method->getDeclaringClass();
|
||||
$cacheKey = $class->getName() . '#' . $method->getName();
|
||||
|
||||
if (isset($this->loadedAnnotations[$cacheKey])) {
|
||||
return $this->loadedAnnotations[$cacheKey];
|
||||
}
|
||||
|
||||
$annots = $this->fetchFromCache($cacheKey, $class, 'getMethodAnnotations', $method);
|
||||
|
||||
return $this->loadedAnnotations[$cacheKey] = $annots;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
|
||||
{
|
||||
foreach ($this->getMethodAnnotations($method) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function clearLoadedAnnotations(): void
|
||||
{
|
||||
$this->loadedAnnotations = [];
|
||||
$this->loadedFilemtimes = [];
|
||||
}
|
||||
|
||||
/** @return mixed[] */
|
||||
private function fetchFromCache(
|
||||
string $cacheKey,
|
||||
ReflectionClass $class,
|
||||
string $method,
|
||||
Reflector $reflector
|
||||
): array {
|
||||
$cacheKey = rawurlencode($cacheKey);
|
||||
|
||||
$item = $this->cache->getItem($cacheKey);
|
||||
if (($this->debug && ! $this->refresh($cacheKey, $class)) || ! $item->isHit()) {
|
||||
$this->cache->save($item->set($this->delegate->{$method}($reflector)));
|
||||
}
|
||||
|
||||
return $item->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in debug mode to check if the cache is fresh.
|
||||
*
|
||||
* @return bool Returns true if the cache was fresh, or false if the class
|
||||
* being read was modified since writing to the cache.
|
||||
*/
|
||||
private function refresh(string $cacheKey, ReflectionClass $class): bool
|
||||
{
|
||||
$lastModification = $this->getLastModification($class);
|
||||
if ($lastModification === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$item = $this->cache->getItem('[C]' . $cacheKey);
|
||||
if ($item->isHit() && $item->get() >= $lastModification) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->cache->save($item->set(time()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time the class was last modified, testing traits and parents
|
||||
*/
|
||||
private function getLastModification(ReflectionClass $class): int
|
||||
{
|
||||
$filename = $class->getFileName();
|
||||
|
||||
if (isset($this->loadedFilemtimes[$filename])) {
|
||||
return $this->loadedFilemtimes[$filename];
|
||||
}
|
||||
|
||||
$parent = $class->getParentClass();
|
||||
|
||||
$lastModification = max(array_merge(
|
||||
[$filename ? filemtime($filename) : 0],
|
||||
array_map(function (ReflectionClass $reflectionTrait): int {
|
||||
return $this->getTraitLastModificationTime($reflectionTrait);
|
||||
}, $class->getTraits()),
|
||||
array_map(function (ReflectionClass $class): int {
|
||||
return $this->getLastModification($class);
|
||||
}, $class->getInterfaces()),
|
||||
$parent ? [$this->getLastModification($parent)] : []
|
||||
));
|
||||
|
||||
assert($lastModification !== false);
|
||||
|
||||
return $this->loadedFilemtimes[$filename] = $lastModification;
|
||||
}
|
||||
|
||||
private function getTraitLastModificationTime(ReflectionClass $reflectionTrait): int
|
||||
{
|
||||
$fileName = $reflectionTrait->getFileName();
|
||||
|
||||
if (isset($this->loadedFilemtimes[$fileName])) {
|
||||
return $this->loadedFilemtimes[$fileName];
|
||||
}
|
||||
|
||||
$lastModificationTime = max(array_merge(
|
||||
[$fileName ? filemtime($fileName) : 0],
|
||||
array_map(function (ReflectionClass $reflectionTrait): int {
|
||||
return $this->getTraitLastModificationTime($reflectionTrait);
|
||||
}, $reflectionTrait->getTraits())
|
||||
));
|
||||
|
||||
assert($lastModificationTime !== false);
|
||||
|
||||
return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
|
||||
}
|
||||
}
|
||||
80
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php
vendored
Normal file
80
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* Interface for annotation readers.
|
||||
*/
|
||||
interface Reader
|
||||
{
|
||||
/**
|
||||
* Gets the annotations applied to a class.
|
||||
*
|
||||
* @param ReflectionClass $class The ReflectionClass of the class from which
|
||||
* the class annotations should be read.
|
||||
*
|
||||
* @return array<object> An array of Annotations.
|
||||
*/
|
||||
public function getClassAnnotations(ReflectionClass $class);
|
||||
|
||||
/**
|
||||
* Gets a class annotation.
|
||||
*
|
||||
* @param ReflectionClass $class The ReflectionClass of the class from which
|
||||
* the class annotations should be read.
|
||||
* @param class-string<T> $annotationName The name of the annotation.
|
||||
*
|
||||
* @return T|null The Annotation or NULL, if the requested annotation does not exist.
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotationName);
|
||||
|
||||
/**
|
||||
* Gets the annotations applied to a method.
|
||||
*
|
||||
* @param ReflectionMethod $method The ReflectionMethod of the method from which
|
||||
* the annotations should be read.
|
||||
*
|
||||
* @return array<object> An array of Annotations.
|
||||
*/
|
||||
public function getMethodAnnotations(ReflectionMethod $method);
|
||||
|
||||
/**
|
||||
* Gets a method annotation.
|
||||
*
|
||||
* @param ReflectionMethod $method The ReflectionMethod to read the annotations from.
|
||||
* @param class-string<T> $annotationName The name of the annotation.
|
||||
*
|
||||
* @return T|null The Annotation or NULL, if the requested annotation does not exist.
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotationName);
|
||||
|
||||
/**
|
||||
* Gets the annotations applied to a property.
|
||||
*
|
||||
* @param ReflectionProperty $property The ReflectionProperty of the property
|
||||
* from which the annotations should be read.
|
||||
*
|
||||
* @return array<object> An array of Annotations.
|
||||
*/
|
||||
public function getPropertyAnnotations(ReflectionProperty $property);
|
||||
|
||||
/**
|
||||
* Gets a property annotation.
|
||||
*
|
||||
* @param ReflectionProperty $property The ReflectionProperty to read the annotations from.
|
||||
* @param class-string<T> $annotationName The name of the annotation.
|
||||
*
|
||||
* @return T|null The Annotation or NULL, if the requested annotation does not exist.
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName);
|
||||
}
|
||||
114
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php
vendored
Normal file
114
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* Simple Annotation Reader.
|
||||
*
|
||||
* This annotation reader is intended to be used in projects where you have
|
||||
* full-control over all annotations that are available.
|
||||
*
|
||||
* @deprecated Deprecated in favour of using AnnotationReader
|
||||
*/
|
||||
class SimpleAnnotationReader implements Reader
|
||||
{
|
||||
/** @var DocParser */
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* Initializes a new SimpleAnnotationReader.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->parser = new DocParser();
|
||||
$this->parser->setIgnoreNotImportedAnnotations(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a namespace in which we will look for annotations.
|
||||
*
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addNamespace($namespace)
|
||||
{
|
||||
$this->parser->addNamespace($namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotations(ReflectionClass $class)
|
||||
{
|
||||
return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotations(ReflectionMethod $method)
|
||||
{
|
||||
return $this->parser->parse(
|
||||
$method->getDocComment(),
|
||||
'method ' . $method->getDeclaringClass()->name . '::' . $method->getName() . '()'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotations(ReflectionProperty $property)
|
||||
{
|
||||
return $this->parser->parse(
|
||||
$property->getDocComment(),
|
||||
'property ' . $property->getDeclaringClass()->name . '::$' . $property->getName()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotationName)
|
||||
{
|
||||
foreach ($this->getClassAnnotations($class) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
|
||||
{
|
||||
foreach ($this->getMethodAnnotations($method) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
|
||||
{
|
||||
foreach ($this->getPropertyAnnotations($property) as $annot) {
|
||||
if ($annot instanceof $annotationName) {
|
||||
return $annot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
208
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php
vendored
Normal file
208
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function strtolower;
|
||||
use function token_get_all;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
use const T_AS;
|
||||
use const T_COMMENT;
|
||||
use const T_DOC_COMMENT;
|
||||
use const T_NAME_FULLY_QUALIFIED;
|
||||
use const T_NAME_QUALIFIED;
|
||||
use const T_NAMESPACE;
|
||||
use const T_NS_SEPARATOR;
|
||||
use const T_STRING;
|
||||
use const T_USE;
|
||||
use const T_WHITESPACE;
|
||||
|
||||
/**
|
||||
* Parses a file for namespaces/use/class declarations.
|
||||
*/
|
||||
class TokenParser
|
||||
{
|
||||
/**
|
||||
* The token list.
|
||||
*
|
||||
* @phpstan-var list<mixed[]>
|
||||
*/
|
||||
private $tokens;
|
||||
|
||||
/**
|
||||
* The number of tokens.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $numTokens;
|
||||
|
||||
/**
|
||||
* The current array pointer.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $pointer = 0;
|
||||
|
||||
/**
|
||||
* @param string $contents
|
||||
*/
|
||||
public function __construct($contents)
|
||||
{
|
||||
$this->tokens = token_get_all($contents);
|
||||
|
||||
// The PHP parser sets internal compiler globals for certain things. Annoyingly, the last docblock comment it
|
||||
// saw gets stored in doc_comment. When it comes to compile the next thing to be include()d this stored
|
||||
// doc_comment becomes owned by the first thing the compiler sees in the file that it considers might have a
|
||||
// docblock. If the first thing in the file is a class without a doc block this would cause calls to
|
||||
// getDocBlock() on said class to return our long lost doc_comment. Argh.
|
||||
// To workaround, cause the parser to parse an empty docblock. Sure getDocBlock() will return this, but at least
|
||||
// it's harmless to us.
|
||||
token_get_all("<?php\n/**\n *\n */");
|
||||
|
||||
$this->numTokens = count($this->tokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next non whitespace and non comment token.
|
||||
*
|
||||
* @param bool $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped.
|
||||
* If FALSE then only whitespace and normal comments are skipped.
|
||||
*
|
||||
* @return mixed[]|string|null The token if exists, null otherwise.
|
||||
*/
|
||||
public function next($docCommentIsComment = true)
|
||||
{
|
||||
for ($i = $this->pointer; $i < $this->numTokens; $i++) {
|
||||
$this->pointer++;
|
||||
if (
|
||||
$this->tokens[$i][0] === T_WHITESPACE ||
|
||||
$this->tokens[$i][0] === T_COMMENT ||
|
||||
($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->tokens[$i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single use statement.
|
||||
*
|
||||
* @return array<string, string> A list with all found class names for a use statement.
|
||||
*/
|
||||
public function parseUseStatement()
|
||||
{
|
||||
$groupRoot = '';
|
||||
$class = '';
|
||||
$alias = '';
|
||||
$statements = [];
|
||||
$explicitAlias = false;
|
||||
while (($token = $this->next())) {
|
||||
if (! $explicitAlias && $token[0] === T_STRING) {
|
||||
$class .= $token[1];
|
||||
$alias = $token[1];
|
||||
} elseif ($explicitAlias && $token[0] === T_STRING) {
|
||||
$alias = $token[1];
|
||||
} elseif (
|
||||
PHP_VERSION_ID >= 80000 &&
|
||||
($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
|
||||
) {
|
||||
$class .= $token[1];
|
||||
|
||||
$classSplit = explode('\\', $token[1]);
|
||||
$alias = $classSplit[count($classSplit) - 1];
|
||||
} elseif ($token[0] === T_NS_SEPARATOR) {
|
||||
$class .= '\\';
|
||||
$alias = '';
|
||||
} elseif ($token[0] === T_AS) {
|
||||
$explicitAlias = true;
|
||||
$alias = '';
|
||||
} elseif ($token === ',') {
|
||||
$statements[strtolower($alias)] = $groupRoot . $class;
|
||||
$class = '';
|
||||
$alias = '';
|
||||
$explicitAlias = false;
|
||||
} elseif ($token === ';') {
|
||||
$statements[strtolower($alias)] = $groupRoot . $class;
|
||||
break;
|
||||
} elseif ($token === '{') {
|
||||
$groupRoot = $class;
|
||||
$class = '';
|
||||
} elseif ($token === '}') {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all use statements.
|
||||
*
|
||||
* @param string $namespaceName The namespace name of the reflected class.
|
||||
*
|
||||
* @return array<string, string> A list with all found use statements.
|
||||
*/
|
||||
public function parseUseStatements($namespaceName)
|
||||
{
|
||||
$statements = [];
|
||||
while (($token = $this->next())) {
|
||||
if ($token[0] === T_USE) {
|
||||
$statements = array_merge($statements, $this->parseUseStatement());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($token[0] !== T_NAMESPACE || $this->parseNamespace() !== $namespaceName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get fresh array for new namespace. This is to prevent the parser to collect the use statements
|
||||
// for a previous namespace with the same name. This is the case if a namespace is defined twice
|
||||
// or if a namespace with the same name is commented out.
|
||||
$statements = [];
|
||||
}
|
||||
|
||||
return $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the namespace.
|
||||
*
|
||||
* @return string The found namespace.
|
||||
*/
|
||||
public function parseNamespace()
|
||||
{
|
||||
$name = '';
|
||||
while (
|
||||
($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR || (
|
||||
PHP_VERSION_ID >= 80000 &&
|
||||
($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
|
||||
))
|
||||
) {
|
||||
$name .= $token[1];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class name.
|
||||
*
|
||||
* @return string The found class name.
|
||||
*/
|
||||
public function parseClass()
|
||||
{
|
||||
// Namespaces and class names are tokenized the same: T_STRINGs
|
||||
// separated by T_NS_SEPARATOR so we can use one function to provide
|
||||
// both.
|
||||
return $this->parseNamespace();
|
||||
}
|
||||
}
|
||||
19
vendor/doctrine/lexer/LICENSE
vendored
Normal file
19
vendor/doctrine/lexer/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2018 Doctrine Project
|
||||
|
||||
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.
|
||||
9
vendor/doctrine/lexer/README.md
vendored
Normal file
9
vendor/doctrine/lexer/README.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# Doctrine Lexer
|
||||
|
||||
Build Status: [](https://travis-ci.org/doctrine/lexer)
|
||||
|
||||
Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
|
||||
|
||||
This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL).
|
||||
|
||||
https://www.doctrine-project.org/projects/lexer.html
|
||||
41
vendor/doctrine/lexer/composer.json
vendored
Normal file
41
vendor/doctrine/lexer/composer.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
"type": "library",
|
||||
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
|
||||
"keywords": [
|
||||
"php",
|
||||
"parser",
|
||||
"lexer",
|
||||
"annotations",
|
||||
"docblock"
|
||||
],
|
||||
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
|
||||
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
|
||||
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^6.0",
|
||||
"phpstan/phpstan": "^0.11.8",
|
||||
"phpunit/phpunit": "^8.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": { "Doctrine\\Tests\\": "tests/Doctrine" }
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
||||
328
vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php
vendored
Normal file
328
vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Common\Lexer;
|
||||
|
||||
use ReflectionClass;
|
||||
use const PREG_SPLIT_DELIM_CAPTURE;
|
||||
use const PREG_SPLIT_NO_EMPTY;
|
||||
use const PREG_SPLIT_OFFSET_CAPTURE;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function preg_split;
|
||||
use function sprintf;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Base class for writing simple lexers, i.e. for creating small DSLs.
|
||||
*/
|
||||
abstract class AbstractLexer
|
||||
{
|
||||
/**
|
||||
* Lexer original input string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $input;
|
||||
|
||||
/**
|
||||
* Array of scanned tokens.
|
||||
*
|
||||
* Each token is an associative array containing three items:
|
||||
* - 'value' : the string value of the token in the input string
|
||||
* - 'type' : the type of the token (identifier, numeric, string, input
|
||||
* parameter, none)
|
||||
* - 'position' : the position of the token in the input string
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $tokens = [];
|
||||
|
||||
/**
|
||||
* Current lexer position in input string.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $position = 0;
|
||||
|
||||
/**
|
||||
* Current peek of current lexer position.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $peek = 0;
|
||||
|
||||
/**
|
||||
* The next token in the input.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
public $lookahead;
|
||||
|
||||
/**
|
||||
* The last matched/seen token.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* Composed regex for input parsing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $regex;
|
||||
|
||||
/**
|
||||
* Sets the input data to be tokenized.
|
||||
*
|
||||
* The Lexer is immediately reset and the new input tokenized.
|
||||
* Any unprocessed tokens from any previous input are lost.
|
||||
*
|
||||
* @param string $input The input to be tokenized.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->tokens = [];
|
||||
|
||||
$this->reset();
|
||||
$this->scan($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the lexer.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->lookahead = null;
|
||||
$this->token = null;
|
||||
$this->peek = 0;
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the peek pointer to 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetPeek()
|
||||
{
|
||||
$this->peek = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the lexer position on the input to the given position.
|
||||
*
|
||||
* @param int $position Position to place the lexical scanner.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetPosition($position = 0)
|
||||
{
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the original lexer's input until a given position.
|
||||
*
|
||||
* @param int $position
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInputUntilPosition($position)
|
||||
{
|
||||
return substr($this->input, 0, $position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given token matches the current lookahead.
|
||||
*
|
||||
* @param int|string $token
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isNextToken($token)
|
||||
{
|
||||
return $this->lookahead !== null && $this->lookahead['type'] === $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any of the given tokens matches the current lookahead.
|
||||
*
|
||||
* @param array $tokens
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isNextTokenAny(array $tokens)
|
||||
{
|
||||
return $this->lookahead !== null && in_array($this->lookahead['type'], $tokens, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the next token in the input string.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function moveNext()
|
||||
{
|
||||
$this->peek = 0;
|
||||
$this->token = $this->lookahead;
|
||||
$this->lookahead = isset($this->tokens[$this->position])
|
||||
? $this->tokens[$this->position++] : null;
|
||||
|
||||
return $this->lookahead !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the lexer to skip input tokens until it sees a token with the given value.
|
||||
*
|
||||
* @param string $type The token type to skip until.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function skipUntil($type)
|
||||
{
|
||||
while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
|
||||
$this->moveNext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given value is identical to the given token.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int|string $token
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isA($value, $token)
|
||||
{
|
||||
return $this->getType($value) === $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the lookahead token forward.
|
||||
*
|
||||
* @return array|null The next token or NULL if there are no more tokens ahead.
|
||||
*/
|
||||
public function peek()
|
||||
{
|
||||
if (isset($this->tokens[$this->position + $this->peek])) {
|
||||
return $this->tokens[$this->position + $this->peek++];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at the next token, returns it and immediately resets the peek.
|
||||
*
|
||||
* @return array|null The next token or NULL if there are no more tokens ahead.
|
||||
*/
|
||||
public function glimpse()
|
||||
{
|
||||
$peek = $this->peek();
|
||||
$this->peek = 0;
|
||||
|
||||
return $peek;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the input string for tokens.
|
||||
*
|
||||
* @param string $input A query string.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function scan($input)
|
||||
{
|
||||
if (! isset($this->regex)) {
|
||||
$this->regex = sprintf(
|
||||
'/(%s)|%s/%s',
|
||||
implode(')|(', $this->getCatchablePatterns()),
|
||||
implode('|', $this->getNonCatchablePatterns()),
|
||||
$this->getModifiers()
|
||||
);
|
||||
}
|
||||
|
||||
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
|
||||
$matches = preg_split($this->regex, $input, -1, $flags);
|
||||
|
||||
if ($matches === false) {
|
||||
// Work around https://bugs.php.net/78122
|
||||
$matches = [[$input, 0]];
|
||||
}
|
||||
|
||||
foreach ($matches as $match) {
|
||||
// Must remain before 'value' assignment since it can change content
|
||||
$type = $this->getType($match[0]);
|
||||
|
||||
$this->tokens[] = [
|
||||
'value' => $match[0],
|
||||
'type' => $type,
|
||||
'position' => $match[1],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the literal for a given token.
|
||||
*
|
||||
* @param int|string $token
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
public function getLiteral($token)
|
||||
{
|
||||
$className = static::class;
|
||||
$reflClass = new ReflectionClass($className);
|
||||
$constants = $reflClass->getConstants();
|
||||
|
||||
foreach ($constants as $name => $value) {
|
||||
if ($value === $token) {
|
||||
return $className . '::' . $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regex modifiers
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getModifiers()
|
||||
{
|
||||
return 'iu';
|
||||
}
|
||||
|
||||
/**
|
||||
* Lexical catchable patterns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getCatchablePatterns();
|
||||
|
||||
/**
|
||||
* Lexical non-catchable patterns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getNonCatchablePatterns();
|
||||
|
||||
/**
|
||||
* Retrieve token type. Also processes the token value if necessary.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return int|string|null
|
||||
*/
|
||||
abstract protected function getType(&$value);
|
||||
}
|
||||
17
vendor/hg/apidoc/.github/workflows/mirror.yml
vendored
Normal file
17
vendor/hg/apidoc/.github/workflows/mirror.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: 'GitHub Actions Mirror'
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
mirror_to_gitee:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v1
|
||||
- name: 'Mirror to gitee'
|
||||
uses: pixta-dev/repository-mirroring-action@v1
|
||||
with:
|
||||
target_repo_url:
|
||||
git@gitee.com:hg-code/thinkphp-apidoc.git
|
||||
ssh_private_key:
|
||||
${{ secrets.GITEE_KEY }}
|
||||
1
vendor/hg/apidoc/.gitignore
vendored
Normal file
1
vendor/hg/apidoc/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.idea
|
||||
21
vendor/hg/apidoc/LICENSE
vendored
Normal file
21
vendor/hg/apidoc/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
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
|
||||
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.
|
||||
79
vendor/hg/apidoc/README.md
vendored
Normal file
79
vendor/hg/apidoc/README.md
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<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文档。
|
||||
- 在线调试:在线文档可直接调试,支持设置全局参数,接口调试省时省力。
|
||||
- 轻松编写:支持公共注释定义、业务逻辑层、数据表字段的引用,几句注释即可完成。
|
||||
- 安全高效:支持访问密码验证、应用/版本独立密码;支持文档缓存。
|
||||
- 多应用/多版本:可适应各种单应用、多应用、多版本的项目的Api管理。
|
||||
- Markdown文档:支持.md文件的文档展示。
|
||||
- 快速生成Crud:配置+模板即可快速生成Crud接口代码及数据表的创建,大大提高工作效率。
|
||||
- 控制器分组:更精细化的对控制器接口进行分组展示。
|
||||
|
||||
|
||||
## 📌兼容
|
||||
|
||||
ThinkPHP 5.x
|
||||
|
||||
ThinkPHP 6.x
|
||||
|
||||
> 📢 2.6.0版本开始全面兼容TP5了啦~~~
|
||||
|
||||
|
||||
## 📖使用文档
|
||||
|
||||
[ThinkPHP ApiDoc V2.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>
|
||||
|
||||
## 💡鸣谢
|
||||
|
||||
[ThinkPHP](http://www.thinkphp.cn/)
|
||||
<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>
|
||||
|
||||
|
||||
43
vendor/hg/apidoc/composer.json
vendored
Normal file
43
vendor/hg/apidoc/composer.json
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "hg/apidoc",
|
||||
"description": "thinkphp API文档自动生成",
|
||||
"type": "think-extend",
|
||||
"keywords": [
|
||||
"thinkphp",
|
||||
"swagger",
|
||||
"apidoc",
|
||||
"api文档",
|
||||
"接口文档",
|
||||
"自动生成",
|
||||
"注释生成",
|
||||
"php接口文档"
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1.0",
|
||||
"doctrine/annotations": "^1.6",
|
||||
"symfony/class-loader": "~3.2.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "hg-code",
|
||||
"email": "376401263@qq.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"hg\\apidoc\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"think": {
|
||||
"services": [
|
||||
"hg\\apidoc\\Service"
|
||||
],
|
||||
"config": {
|
||||
"apidoc": "src/config.php"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "beta"
|
||||
}
|
||||
172
vendor/hg/apidoc/src/Auth.php
vendored
Normal file
172
vendor/hg/apidoc/src/Auth.php
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace hg\apidoc;
|
||||
|
||||
use think\facade\Config;
|
||||
use think\facade\Request;
|
||||
use hg\apidoc\exception\AuthException;
|
||||
|
||||
class Auth
|
||||
{
|
||||
protected $config = [];
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证密码
|
||||
* @param $password
|
||||
* @return false|string
|
||||
*/
|
||||
public function verifyAuth(string $password, string $appKey)
|
||||
{
|
||||
if (!empty($appKey)) {
|
||||
$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']);
|
||||
}
|
||||
throw new AuthException("password error");
|
||||
}
|
||||
}
|
||||
if ($this->config['auth']['enable']) {
|
||||
// 密码验证
|
||||
if (md5($this->config['auth']['password']) === $password) {
|
||||
return $this->createToken($this->config['auth']['password']);
|
||||
}
|
||||
throw new AuthException("password error");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取tokencode
|
||||
* @param string $password
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenCode(string $password): string
|
||||
{
|
||||
return md5(md5($password) . strtotime(date('Y-m-d', time())));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建token
|
||||
* @param string $password
|
||||
* @return string
|
||||
*/
|
||||
public function createToken(string $password): string
|
||||
{
|
||||
return $this->handleToken($this->getTokenCode($password), "CE");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证token
|
||||
* @param $token
|
||||
* @return bool
|
||||
*/
|
||||
public function checkToken(string $token, string $password): bool
|
||||
{
|
||||
if (empty($password)) {
|
||||
$password = $this->config['auth']['password'];
|
||||
}
|
||||
$decode = $this->handleToken($token, "DE");
|
||||
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("apidocToken");
|
||||
|
||||
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
|
||||
* @param $string
|
||||
* @param string $operation
|
||||
* @param string $key
|
||||
* @param int $expiry
|
||||
* @return false|string
|
||||
*/
|
||||
protected function handleToken(string $string, string $operation = 'DE', string $key = '', int $expiry = 0):string
|
||||
{
|
||||
$ckey_length = 4;
|
||||
$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)) : '';
|
||||
$cryptkey = $keya . md5($keya . $keyc);
|
||||
$key_length = strlen($cryptkey);
|
||||
$string = $operation == 'DE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
|
||||
$string_length = strlen($string);
|
||||
$result = '';
|
||||
$box = range(0, 255);
|
||||
$rndkey = array();
|
||||
for ($i = 0; $i <= 255; $i++) {
|
||||
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
|
||||
}
|
||||
for ($j = $i = 0; $i < 256; $i++) {
|
||||
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
|
||||
$tmp = $box[$i];
|
||||
$box[$i] = $box[$j];
|
||||
$box[$j] = $tmp;
|
||||
}
|
||||
for ($a = $j = $i = 0; $i < $string_length; $i++) {
|
||||
$a = ($a + 1) % 256;
|
||||
$j = ($j + $box[$a]) % 256;
|
||||
$tmp = $box[$a];
|
||||
$box[$a] = $box[$j];
|
||||
$box[$j] = $tmp;
|
||||
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
|
||||
}
|
||||
if ($operation == 'DE') {
|
||||
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
|
||||
return substr($result, 26);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
return $keyc . str_replace('=', '', base64_encode($result));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
259
vendor/hg/apidoc/src/Controller.php
vendored
Normal file
259
vendor/hg/apidoc/src/Controller.php
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
<?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\Request;
|
||||
use hg\apidoc\crud\CreateCrud;
|
||||
|
||||
class Controller
|
||||
{
|
||||
protected $app;
|
||||
|
||||
protected $config;
|
||||
|
||||
protected $defaultConfig=[
|
||||
'crud'=>[
|
||||
'model'=>[
|
||||
'fields_types'=>[
|
||||
"int",
|
||||
"tinyint",
|
||||
"smallint",
|
||||
"mediumint",
|
||||
"integer",
|
||||
"bigint",
|
||||
"bit",
|
||||
"real",
|
||||
"float",
|
||||
"decimal",
|
||||
"numeric",
|
||||
"char",
|
||||
"varchar",
|
||||
"date",
|
||||
"time",
|
||||
"year",
|
||||
"timestamp",
|
||||
"datetime",
|
||||
"tinyblob",
|
||||
"blob",
|
||||
"mediumblob",
|
||||
"longblob",
|
||||
"tinytext",
|
||||
"text",
|
||||
"mediumtext",
|
||||
"longtext",
|
||||
"enum",
|
||||
"set",
|
||||
"binary",
|
||||
"varbinary",
|
||||
"point",
|
||||
"linestring",
|
||||
"polygon",
|
||||
"geometry",
|
||||
"multipoint",
|
||||
"multilinestring",
|
||||
"multipolygon",
|
||||
"geometrycollection"
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->config = Config::get("apidoc")?Config::get("apidoc"):Config::get("apidoc.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function getConfig(){
|
||||
$config = $this->config;
|
||||
if (!empty($config['auth'])){
|
||||
unset($config['auth']['auth_password']);
|
||||
unset($config['auth']['password']);
|
||||
unset($config['auth']['key']);
|
||||
}
|
||||
// 处理统一返回信息
|
||||
if (!empty($config['responses']) && is_string($config['responses'])){
|
||||
// 兼容原配置
|
||||
$config['responses'] = [
|
||||
'jsonStr'=>$config['responses']
|
||||
];
|
||||
}else if (!empty($config['responses']) && isset($config['responses']['show_responses']) && !$config['responses']['show_responses'] && !empty($config['responses']['data'])){
|
||||
// 显示在提示中
|
||||
$responsesStr = '{'."\r\n";
|
||||
$responsesMain = "";
|
||||
foreach ($config['responses']['data'] as $item){
|
||||
$responsesStr.='"'.$item['name'].'":"'.$item['desc'].'",'."\r\n";
|
||||
if (!empty($item['main']) && $item['main']==true){
|
||||
$responsesMain = $item;
|
||||
}
|
||||
}
|
||||
$responsesStr.= '}';
|
||||
$config['responses']['jsonStr']=$responsesStr;
|
||||
$config['responses']['main']=$responsesMain;
|
||||
}
|
||||
|
||||
$config['debug']=app()->isDebug();
|
||||
|
||||
if (!empty($config['crud'])){
|
||||
// 无配置可选字段类型,使用默认的
|
||||
if (!empty($config['crud']['model']) && empty($config['crud']['model']['fields_types'])){
|
||||
$config['crud']['model']['fields_types'] = $this->defaultConfig['crud']['model']['fields_types'];
|
||||
}
|
||||
// 过滤route文件配置
|
||||
if (!empty($config['crud']['route'])){
|
||||
unset($config['crud']['route']);
|
||||
}
|
||||
}
|
||||
// 清除apps配置中的password
|
||||
$config['apps'] = (new Utils())->handleAppsConfig($config['apps']);
|
||||
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);
|
||||
return Utils::showJson(0,"",$hasAuth);
|
||||
} 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();
|
||||
(new Auth())->checkAuth($params['appKey']);
|
||||
|
||||
$cacheData=null;
|
||||
if (!empty($config['cache']) && $config['cache']['enable']){
|
||||
$cacheData = (new CacheApiData())->get($params['appKey'],$params['cacheFileName']);
|
||||
if ($cacheData && $params['reload']=='false'){
|
||||
$apiData = $cacheData['data'];
|
||||
}else{
|
||||
// 生成数据并缓存
|
||||
$apiData = (new ParseAnnotation())->renderApiData($params['appKey']);
|
||||
$cacheData =(new CacheApiData())->set($params['appKey'],$apiData);
|
||||
}
|
||||
}else{
|
||||
// 生成数据
|
||||
$apiData = (new ParseAnnotation())->renderApiData($params['appKey']);
|
||||
}
|
||||
$groups=[['title'=>'全部','name'=>0]];
|
||||
// 获取md
|
||||
$docs = (new ParseMarkdown())->getDocsMenu();
|
||||
if (count($docs)>0){
|
||||
$menu_title = !empty($config['docs']) && !empty($config['docs']['menu_title'])?$config['docs']['menu_title']:'文档';
|
||||
$groups[]=['title'=>$menu_title,'name'=>'markdown_doc'];
|
||||
}
|
||||
if (!empty($config['groups']) && count($config['groups'])>0 && !empty($apiData['groups']) && count($apiData['groups'])>0){
|
||||
$configGroups=[];
|
||||
foreach ($config['groups'] as $group) {
|
||||
if (in_array($group['name'],$apiData['groups'])){
|
||||
$configGroups[]=$group;
|
||||
}
|
||||
}
|
||||
$groups = array_merge($groups,$configGroups);
|
||||
}
|
||||
$json=[
|
||||
'groups'=>$groups,
|
||||
'list'=>$apiData['data'],
|
||||
'docs'=>$docs,
|
||||
'tags'=>$apiData['tags']
|
||||
];
|
||||
if ($cacheData && !empty($cacheData['list'])){
|
||||
$json['cacheFiles']=$cacheData['list'];
|
||||
$json['cacheName']=$cacheData['name'];
|
||||
}
|
||||
return Utils::showJson(0,"",$json);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取md文档内容
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function getMdDetail(){
|
||||
$request = Request::instance();
|
||||
$params = $request->param();
|
||||
try {
|
||||
if (empty($params['path'])){
|
||||
throw new ErrorException("mdPath not found");
|
||||
}
|
||||
if (empty($params['appKey'])){
|
||||
throw new ErrorException("appkey not found");
|
||||
}
|
||||
(new Auth())->checkAuth($params['appKey']);
|
||||
$res = (new ParseMarkdown())->getContent($params['appKey'],$params['path']);
|
||||
return Utils::showJson(0,"",$res);
|
||||
|
||||
} catch (ErrorException $e) {
|
||||
return Utils::showJson($e->getCode(),$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建Crud
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function createCrud()
|
||||
{
|
||||
if (!\think\facade\App::isDebug()) {
|
||||
throw new ErrorException("no debug",501);
|
||||
}
|
||||
$request = Request::instance();
|
||||
$params = $request->param();
|
||||
|
||||
if (!isset($params['appKey'])){
|
||||
throw new ErrorException("appkey not found");
|
||||
}
|
||||
(new Auth())->checkAuth($params['appKey']);
|
||||
$res = (new CreateCrud())->create($params);
|
||||
return Utils::showJson(0,"",$res);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
35
vendor/hg/apidoc/src/Service.php
vendored
Normal file
35
vendor/hg/apidoc/src/Service.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc;
|
||||
|
||||
use think\facade\Config;
|
||||
use think\facade\Route;
|
||||
|
||||
class Service extends \think\Service
|
||||
{
|
||||
|
||||
public function boot()
|
||||
{
|
||||
|
||||
$this->registerRoutes(function (){
|
||||
$route_prefix = 'apidoc';
|
||||
$apidocConfig = Config::get("apidoc")?Config::get("apidoc"):Config::get("apidoc.");
|
||||
$routes = function () {
|
||||
$controller_namespace = '\hg\apidoc\Controller@';
|
||||
Route::get('config' , $controller_namespace . 'getConfig');
|
||||
Route::get('apiData' , $controller_namespace . 'getApidoc');
|
||||
Route::get('mdDetail' , $controller_namespace . 'getMdDetail');
|
||||
Route::post('verifyAuth' , $controller_namespace . 'verifyAuth');
|
||||
Route::post('createCrud' , $controller_namespace . 'createCrud');
|
||||
};
|
||||
if (!empty($apidocConfig['allowCrossDomain'])){
|
||||
Route::group($route_prefix, $routes)->allowCrossDomain();
|
||||
}
|
||||
Route::group($route_prefix, $routes);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
330
vendor/hg/apidoc/src/Utils.php
vendored
Normal file
330
vendor/hg/apidoc/src/Utils.php
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace hg\apidoc;
|
||||
|
||||
use hg\apidoc\exception\ErrorException;
|
||||
use think\facade\Config;
|
||||
use think\response\Json;
|
||||
|
||||
class Utils
|
||||
{
|
||||
protected static $snakeCache = [];
|
||||
/**
|
||||
* 统一返回json格式
|
||||
* @param int $code
|
||||
* @param string $msg
|
||||
* @param string $data
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public static function showJson(int $code = 0, string $msg = "", $data = ""):Json
|
||||
{
|
||||
$res = [
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => $data,
|
||||
];
|
||||
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];
|
||||
}
|
||||
|
||||
$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数据
|
||||
* @param array $tree tree数据
|
||||
* @param string $childName 子节点名称
|
||||
* @return array 转换后的list数据
|
||||
*/
|
||||
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 = $this->treeToList($val[$childName], $childName);
|
||||
if ($children) {
|
||||
$newChildren = [];
|
||||
foreach ($children as $item) {
|
||||
$item[$parentField] = $val[$key];
|
||||
$newChildren[] = $item;
|
||||
}
|
||||
$array = array_merge($array, $newChildren);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据一组keys获取所有关联节点
|
||||
* @param $tree
|
||||
* @param $keys
|
||||
*/
|
||||
public function getTreeNodesByKeys(array $tree, array $keys, string $field = "id", string $childrenField = "children")
|
||||
{
|
||||
$list = $this->TreeToList($tree, $childrenField, "folder");
|
||||
$data = [];
|
||||
foreach ($keys as $k => $v) {
|
||||
$parent = !$k ? "" : $keys[$k - 1];
|
||||
foreach ($list as $item) {
|
||||
if (((!empty($item['parent']) && $item['parent'] === $parent) || empty($item['parent'])) && $item[$field] == $v) {
|
||||
$data[] = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换模板变量
|
||||
* @param $temp
|
||||
* @param $data
|
||||
* @return string|string[]
|
||||
*/
|
||||
public static function replaceTemplate(string $temp, array $data):string
|
||||
{
|
||||
$str = $temp;
|
||||
foreach ($data as $k => $v) {
|
||||
$key = '${' . $k . '}';
|
||||
if (strpos($str, $key) !== false) {
|
||||
$str = str_replace($key, $v, $str);
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换当前所选应用/版本的变量
|
||||
* @param $temp
|
||||
* @param $currentApps
|
||||
* @return string|string[]
|
||||
*/
|
||||
public function replaceCurrentAppTemplate(string $temp,array $currentApps):string
|
||||
{
|
||||
$str = $temp;
|
||||
if (!empty($currentApps) && count($currentApps) > 0) {
|
||||
$data = [];
|
||||
for ($i = 0; $i <= 3; $i++) {
|
||||
if (isset($currentApps[$i])) {
|
||||
$appItem = $currentApps[$i];
|
||||
foreach ($appItem as $k => $v) {
|
||||
$key = 'app[' . $i . '].' . $k;
|
||||
$data[$key] = $v;
|
||||
}
|
||||
} else {
|
||||
$appItem = $currentApps[0];
|
||||
foreach ($appItem as $k => $v) {
|
||||
$key = 'app[' . $i . '].' . $k;
|
||||
$data[$key] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
$str = $this->replaceTemplate($str, $data);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件获取数组中的值
|
||||
* @param array $array
|
||||
* @param $query
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function getArrayFind(array $array, $query)
|
||||
{
|
||||
$res = null;
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $item) {
|
||||
if ($query($item)) {
|
||||
$res = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并对象数组并根据key去重
|
||||
* @param string $name
|
||||
* @param mixed ...$array
|
||||
* @return array
|
||||
*/
|
||||
public static function arrayMergeAndUnique(string $key = "name", ...$array):array
|
||||
{
|
||||
$mergeArr = [];
|
||||
foreach ($array as $k => $v) {
|
||||
$mergeArr = array_merge($mergeArr, $v);
|
||||
}
|
||||
$keys = [];
|
||||
foreach ($mergeArr as $k => $v) {
|
||||
$keys[] = $v[$key];
|
||||
}
|
||||
$uniqueKeys = array_flip(array_flip($keys));
|
||||
$newArray = [];
|
||||
foreach ($uniqueKeys as $k => $v) {
|
||||
$newArray[] = $mergeArr[$k];
|
||||
}
|
||||
return $newArray;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化当前所选的应用/版本数据
|
||||
* @param $appKey
|
||||
*/
|
||||
public function getCurrentApps(string $appKey):array
|
||||
{
|
||||
$config = Config::get("apidoc")?Config::get("apidoc"):Config::get("apidoc.");
|
||||
if (!(!empty($config['apps']) && count($config['apps']) > 0)) {
|
||||
throw new ErrorException("no config apps", 500);
|
||||
}
|
||||
if (strpos($appKey, '_') !== false) {
|
||||
$keyArr = explode("_", $appKey);
|
||||
} else {
|
||||
$keyArr = [$appKey];
|
||||
}
|
||||
$currentApps = $this->getTreeNodesByKeys($config['apps'], $keyArr, 'folder', 'items');
|
||||
if (!$currentApps) {
|
||||
throw new ErrorException("appKey error", 412, [
|
||||
'appKey' => $appKey
|
||||
]);
|
||||
}
|
||||
return $currentApps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理apps配置参数
|
||||
* @param array $apps
|
||||
* @return array
|
||||
*/
|
||||
public function handleAppsConfig(array $apps):array
|
||||
{
|
||||
$appsConfig = [];
|
||||
foreach ($apps as $app) {
|
||||
if (!empty($app['password'])) {
|
||||
unset($app['password']);
|
||||
$app['hasPassword'] = true;
|
||||
}
|
||||
if (!empty($app['items']) && count($app['items']) > 0) {
|
||||
$app['items'] = $this->handleAppsConfig($app['items']);
|
||||
}
|
||||
$appsConfig[] = $app;
|
||||
}
|
||||
return $appsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $delimiter
|
||||
* @return string
|
||||
*/
|
||||
public static function snake(string $value, string $delimiter = '_'): string
|
||||
{
|
||||
$key = $value;
|
||||
|
||||
if (isset(static::$snakeCache[$key][$delimiter])) {
|
||||
return static::$snakeCache[$key][$delimiter];
|
||||
}
|
||||
|
||||
if (!ctype_lower($value)) {
|
||||
$value = preg_replace('/\s+/u', '', $value);
|
||||
|
||||
$value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value));
|
||||
}
|
||||
|
||||
return static::$snakeCache[$key][$delimiter] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转小写
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
public static function lower(string $value): string
|
||||
{
|
||||
return mb_strtolower($value, 'UTF-8');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
44
vendor/hg/apidoc/src/annotation/AddField.php
vendored
Normal file
44
vendor/hg/apidoc/src/annotation/AddField.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 添加模型的字段
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class AddField extends Annotation
|
||||
{
|
||||
/**
|
||||
* 字段名
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
* 类型
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'string';
|
||||
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
* @var string
|
||||
*/
|
||||
public $default;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
* @var string
|
||||
*/
|
||||
public $desc;
|
||||
|
||||
/**
|
||||
* 必须
|
||||
* @var bool
|
||||
*/
|
||||
public $require = false;
|
||||
}
|
||||
14
vendor/hg/apidoc/src/annotation/Author.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Author.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 作者
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class Author extends Annotation
|
||||
{}
|
||||
14
vendor/hg/apidoc/src/annotation/Desc.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Desc.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD","CLASS"})
|
||||
*/
|
||||
class Desc extends Annotation
|
||||
{}
|
||||
14
vendor/hg/apidoc/src/annotation/Field.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Field.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 指定获取模型的字段
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class Field extends Annotation
|
||||
{}
|
||||
14
vendor/hg/apidoc/src/annotation/Group.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Group.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 分组
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"CLASS"})
|
||||
*/
|
||||
class Group extends Annotation
|
||||
{}
|
||||
40
vendor/hg/apidoc/src/annotation/Header.php
vendored
Normal file
40
vendor/hg/apidoc/src/annotation/Header.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
|
||||
/**
|
||||
* 请求头
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class Header extends ParamBase
|
||||
{
|
||||
/**
|
||||
* 必须
|
||||
* @var bool
|
||||
*/
|
||||
public $require = false;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
* @var string
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* 引入
|
||||
* @var string
|
||||
*/
|
||||
public $ref;
|
||||
|
||||
|
||||
/**
|
||||
* 描述
|
||||
* @var string
|
||||
*/
|
||||
public $desc;
|
||||
|
||||
|
||||
}
|
||||
14
vendor/hg/apidoc/src/annotation/Method.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Method.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* Url
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class Method extends Annotation
|
||||
{}
|
||||
27
vendor/hg/apidoc/src/annotation/Param.php
vendored
Normal file
27
vendor/hg/apidoc/src/annotation/Param.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD","ANNOTATION"})
|
||||
*/
|
||||
final class Param extends ParamBase
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* 必须
|
||||
* @var bool
|
||||
*/
|
||||
public $require = false;
|
||||
|
||||
/**
|
||||
* 引入
|
||||
* @var string
|
||||
*/
|
||||
public $ref;
|
||||
}
|
||||
62
vendor/hg/apidoc/src/annotation/ParamBase.php
vendored
Normal file
62
vendor/hg/apidoc/src/annotation/ParamBase.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
abstract class ParamBase extends Annotation
|
||||
{
|
||||
|
||||
/**
|
||||
* 类型
|
||||
* @Enum({"string", "integer", "int", "boolean", "array", "double", "object", "tree", "file","float","date","time","datetime"})
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'string';
|
||||
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
* @var string
|
||||
*/
|
||||
public $default;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
* @var string
|
||||
*/
|
||||
public $desc;
|
||||
|
||||
/**
|
||||
* 为tree类型时指定children字段
|
||||
* @var string
|
||||
*/
|
||||
public $childrenField = '';
|
||||
|
||||
/**
|
||||
* 为tree类型时指定children字段说明
|
||||
* @var string
|
||||
*/
|
||||
public $childrenDesc = 'children';
|
||||
|
||||
/**
|
||||
* 为array类型时指定子节点类型
|
||||
* @Enum({"string", "int", "boolean", "array", "object"})
|
||||
* @var string
|
||||
*/
|
||||
public $childrenType = '';
|
||||
|
||||
/**
|
||||
* 指定引入的字段
|
||||
* @var string
|
||||
*/
|
||||
public $field;
|
||||
|
||||
/**
|
||||
* 指定从引入中过滤的字段
|
||||
* @var string
|
||||
*/
|
||||
public $withoutField;
|
||||
|
||||
|
||||
}
|
||||
14
vendor/hg/apidoc/src/annotation/ParamType.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/ParamType.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 参数类型
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class ParamType extends Annotation
|
||||
{}
|
||||
34
vendor/hg/apidoc/src/annotation/Returned.php
vendored
Normal file
34
vendor/hg/apidoc/src/annotation/Returned.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 返回参数
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD","ANNOTATION"})
|
||||
*/
|
||||
final class Returned extends ParamBase
|
||||
{
|
||||
|
||||
/**
|
||||
* 必须
|
||||
* @var bool
|
||||
*/
|
||||
public $require = false;
|
||||
|
||||
/**
|
||||
* 引入
|
||||
* @var string
|
||||
*/
|
||||
public $ref;
|
||||
|
||||
/**
|
||||
* 是否替换全局响应体中的参数
|
||||
* @var bool
|
||||
*/
|
||||
public $replaceGlobal = false;
|
||||
|
||||
}
|
||||
17
vendor/hg/apidoc/src/annotation/Route.php
vendored
Normal file
17
vendor/hg/apidoc/src/annotation/Route.php
vendored
Normal file
@@ -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";
|
||||
|
||||
}
|
||||
77
vendor/hg/apidoc/src/annotation/Rule.php
vendored
Normal file
77
vendor/hg/apidoc/src/annotation/Rule.php
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
abstract class Rule extends Annotation
|
||||
{
|
||||
/**
|
||||
* @var string|array
|
||||
*/
|
||||
public $middleware;
|
||||
|
||||
/**
|
||||
* 后缀
|
||||
* @var string
|
||||
*/
|
||||
public $ext;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $deny_ext;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $https;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $domain;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $complete_match;
|
||||
|
||||
/**
|
||||
* @var string|array
|
||||
*/
|
||||
public $cache;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $ajax;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $pjax;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $json;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $filter;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $append;
|
||||
|
||||
public function getOptions()
|
||||
{
|
||||
return array_intersect_key(get_object_vars($this), array_flip([
|
||||
'middleware', 'ext', 'deny_ext', 'https', 'domain', 'complete_match', 'cache', 'ajax', 'pjax', 'json', 'filter', 'append',
|
||||
]));
|
||||
}
|
||||
|
||||
}
|
||||
14
vendor/hg/apidoc/src/annotation/Sort.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Sort.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"CLASS"})
|
||||
*/
|
||||
class Sort extends Annotation
|
||||
{}
|
||||
14
vendor/hg/apidoc/src/annotation/Tag.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Tag.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* Tag
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class Tag extends Annotation
|
||||
{}
|
||||
14
vendor/hg/apidoc/src/annotation/Title.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Title.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD","CLASS"})
|
||||
*/
|
||||
class Title extends Annotation
|
||||
{}
|
||||
14
vendor/hg/apidoc/src/annotation/Url.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/Url.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* Url
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class Url extends Annotation
|
||||
{}
|
||||
14
vendor/hg/apidoc/src/annotation/WithoutField.php
vendored
Normal file
14
vendor/hg/apidoc/src/annotation/WithoutField.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace hg\apidoc\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
|
||||
/**
|
||||
* 排除模型的字段
|
||||
* @package hg\apidoc\annotation
|
||||
* @Annotation
|
||||
* @Target({"METHOD"})
|
||||
*/
|
||||
class WithoutField extends Annotation
|
||||
{}
|
||||
62
vendor/hg/apidoc/src/config.php
vendored
Normal file
62
vendor/hg/apidoc/src/config.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
return [
|
||||
// 文档标题
|
||||
'title' => 'APi接口文档',
|
||||
// 文档描述
|
||||
'desc' => '',
|
||||
// 版权申明
|
||||
'copyright' => 'Powered By hg-code',
|
||||
// 默认作者
|
||||
'default_author'=>'',
|
||||
// 默认请求类型
|
||||
'default_method'=>'GET',
|
||||
// 设置应用/版本(必须设置)
|
||||
'apps' => [
|
||||
['title'=>'v1.0','path'=>'app\controller','folder'=>'v1'],
|
||||
],
|
||||
// 控制器分组
|
||||
'groups' => [],
|
||||
// 指定公共注释定义的文件地址
|
||||
'definitions' => "app\controller\Definitions",
|
||||
//指定生成文档的控制器
|
||||
'controllers' => [],
|
||||
// 过滤,不解析的控制器
|
||||
'filter_controllers' => [],
|
||||
// 缓存配置
|
||||
'cache' => [
|
||||
// 是否开启缓存
|
||||
'enable' => false,
|
||||
// 缓存文件路径
|
||||
'path' => '../runtime/apidoc/',
|
||||
// 是否显示更新缓存按钮
|
||||
'reload' => true,
|
||||
// 最大缓存文件数
|
||||
'max' => 5, //最大缓存数量
|
||||
],
|
||||
// 权限认证配置
|
||||
'auth' => [
|
||||
// 是否启用密码验证
|
||||
'enable' => false,
|
||||
// 验证密码
|
||||
'password' => "123456",
|
||||
// 密码加密盐
|
||||
'secret_key' => "apidoc#hg_code",
|
||||
],
|
||||
// 统一的请求Header
|
||||
'headers'=>[],
|
||||
// 统一的请求参数Parameters
|
||||
'parameters'=>[],
|
||||
// 统一的请求响应体,仅显示在文档提示中
|
||||
'responses'=>[
|
||||
['name'=>'code','desc'=>'状态码','type'=>'int'],
|
||||
['name'=>'message','desc'=>'操作描述','type'=>'string'],
|
||||
['name'=>'data','desc'=>'业务数据','main'=>true,'type'=>'object'],
|
||||
],
|
||||
// md文档
|
||||
'docs' => [
|
||||
'menu_title' => '开发文档',
|
||||
'menus' => []
|
||||
],
|
||||
'crud'=>[]
|
||||
|
||||
];
|
||||
383
vendor/hg/apidoc/src/crud/CreateCrud.php
vendored
Normal file
383
vendor/hg/apidoc/src/crud/CreateCrud.php
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace hg\apidoc\crud;
|
||||
|
||||
|
||||
use hg\apidoc\exception\ErrorException;
|
||||
use think\Db as Db5;
|
||||
use think\facade\Config;
|
||||
use think\facade\Db;
|
||||
use think\facade\App;
|
||||
use hg\apidoc\Utils;
|
||||
|
||||
|
||||
class CreateCrud
|
||||
{
|
||||
protected $config;
|
||||
|
||||
protected $currentApps;
|
||||
|
||||
protected $controller_layer = "";
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
|
||||
$this->controller_layer = Config::get('route.controller_layer',"controller");
|
||||
if (!empty($config) && !empty($config['crud'])){
|
||||
$this->config = $config['crud'];
|
||||
}else{
|
||||
throw new ErrorException("no config crud",501);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Crud
|
||||
* @param $params
|
||||
* @return array
|
||||
*/
|
||||
public function create($params){
|
||||
|
||||
$appKey = $params['appKey'];
|
||||
$currentApps = (new Utils())->getCurrentApps($appKey);
|
||||
// $currentApp = $currentApps[count($currentApps) - 1];
|
||||
|
||||
$data = $this->renderTemplateData($params,$currentApps);
|
||||
$res = [];
|
||||
// 创建数据表
|
||||
if (!empty($params['model']['table'])){
|
||||
$sqlRes = $this->createModelTable($params['model'],$params['title']);
|
||||
if ($sqlRes == true){
|
||||
$res[]="创建数据表成功";
|
||||
}else{
|
||||
// $msg= $sqlRes?$sqlRes:"数据表创建失败,请检查配置";
|
||||
throw new ErrorException("datatable crud error",500);
|
||||
}
|
||||
}
|
||||
// 生成文件
|
||||
$keys = array_keys($this->config);
|
||||
foreach ($keys as $index=>$key) {
|
||||
// 添加路由
|
||||
if (
|
||||
$key==="route" &&
|
||||
!empty($this->config['route']) &&
|
||||
!empty($this->config['route']['template']) &&
|
||||
!empty($this->config['route']['path'])
|
||||
){
|
||||
$tmp_path = (new Utils())->replaceCurrentAppTemplate($this->config['route']['template'],$currentApps);
|
||||
$tempPath = $tmp_path.".txt";
|
||||
$str_tmp = Utils::getFileContent($tempPath);
|
||||
if (!empty($str_tmp)){
|
||||
$tmp_content = Utils::replaceTemplate($str_tmp,$data);
|
||||
$tmp_content = (new Utils())->replaceCurrentAppTemplate($tmp_content,$currentApps);
|
||||
$routePathStr = (new Utils())->replaceCurrentAppTemplate($this->config['route']['path'],$currentApps);
|
||||
$routePathStr = str_replace("\\","/",$routePathStr);
|
||||
$routePath = App::getAppPath().$routePathStr;
|
||||
$routeContent = Utils::getFileContent($routePath);
|
||||
$routeContent.="\r\n".$tmp_content."\r\n";
|
||||
Utils::createFile($routePath,$routeContent);
|
||||
$res[]="添加路由成功";
|
||||
}
|
||||
|
||||
}else{
|
||||
$currentConfig = $this->config[$key];
|
||||
$currentParam = $params[$key];
|
||||
$tmp_path = (new Utils())->replaceCurrentAppTemplate($currentParam['template'],$currentApps);
|
||||
$tempPath = $tmp_path.".txt";
|
||||
$str_tmp = Utils::getFileContent($tempPath);
|
||||
$file_content = Utils::replaceTemplate($str_tmp,$data);
|
||||
$file_content = (new Utils())->replaceCurrentAppTemplate($file_content,$currentApps);
|
||||
$namespacePath = str_replace("\\","/",$currentParam['path']);
|
||||
$fileName = $data[$key.'.file_name'];
|
||||
$filePath = '../'.$namespacePath.'/'.$fileName.'.php';
|
||||
$fp=Utils::createFile($filePath,$file_content);
|
||||
if ($fp){
|
||||
$res[]="创建文件成功 path:".$filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成模板变量的数据
|
||||
* @param $params
|
||||
* @return array
|
||||
*/
|
||||
public function renderTemplateData($params,array $currentApps){
|
||||
// 模板参数
|
||||
$api_group = "";
|
||||
if (!empty($params['group'])){
|
||||
$api_group = '@Apidoc\Group("'.$params['group'].'")';
|
||||
}
|
||||
$data=[
|
||||
'title'=>!empty($params['title'])?$params['title']:"",
|
||||
'api_group'=>$api_group,
|
||||
];
|
||||
$keys = array_keys($this->config);
|
||||
foreach ($keys as $index=>$key){
|
||||
$currentConfig = $this->config[$key];
|
||||
//验证模板是否存在
|
||||
$tmp_path = (new Utils())->replaceCurrentAppTemplate($currentConfig['template'],$currentApps);
|
||||
if(!file_exists($tmp_path.'.txt')){
|
||||
throw new ErrorException("template not found",404,[
|
||||
'template'=>$currentConfig['template']
|
||||
]);
|
||||
}
|
||||
if ($key==="route"){
|
||||
continue;
|
||||
}
|
||||
$currentParam = $params[$key];
|
||||
if(!preg_match("/^[A-Z]{1}[A-Za-z0-9]{1,32}$/",$currentParam['class_name'])){
|
||||
throw new ErrorException("classname error",412,[
|
||||
'classname'=>$currentParam['class_name']
|
||||
]);
|
||||
}
|
||||
$currentParamPath = str_replace("\\","/",$currentParam['path']);
|
||||
// 验证目录是否存在
|
||||
if(!is_dir('../'.$currentParamPath)){
|
||||
throw new ErrorException("path not found",404,[
|
||||
'path'=>$currentParamPath
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$appPath = App::getAppPath();
|
||||
$appPathArr = explode("\\", $appPath);
|
||||
$appFolder = $appPathArr[count($appPathArr)-1]?$appPathArr[count($appPathArr)-1]:$appPathArr[count($appPathArr)-2];
|
||||
$namespace = str_replace($appFolder, App::getNamespace(), $currentParam['path']);
|
||||
|
||||
if ($key==="controller"){
|
||||
$pathArr = explode("\\", $namespace);
|
||||
$notArr = array(App::getNamespace(), $this->controller_layer);
|
||||
$url = "/";
|
||||
foreach ($pathArr as $pathItem){
|
||||
if (!in_array($pathItem,$notArr)){
|
||||
$url.=$pathItem."/";
|
||||
}
|
||||
}
|
||||
$data['folder']=$url;
|
||||
$data['api_class_name']=lcfirst($currentParam['class_name']);
|
||||
$data['api_url']=$url.lcfirst($currentParam['class_name']);
|
||||
}else if ($key==="model" && !empty($currentParam['table'])){
|
||||
// 模型
|
||||
// 获取主键
|
||||
foreach ($currentParam['table'] as $item){
|
||||
if ($item['main_key']==true){
|
||||
$data['main_key.field'] = $item['field'];
|
||||
$data['main_key.type'] = $item['type'];
|
||||
$data['main_key.desc'] = $item['desc'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$tp_version = \think\facade\App::version();
|
||||
if (substr($tp_version, 0, 2) == '5.') {
|
||||
$table_prefix = Config::get('database.prefix');
|
||||
}else{
|
||||
$driver = Config::get('database.default');
|
||||
$table_prefix = Config::get('database.connections.' . $driver . '.prefix');
|
||||
}
|
||||
$data[$currentParam['name'] . '.table_prefix'] = $table_prefix;
|
||||
$table_name = Utils::snake($currentParam['class_name']);
|
||||
$data[$currentParam['name'].'.table_name']=$table_name;
|
||||
}
|
||||
|
||||
$namespace = str_replace($appFolder, App::getNamespace(), $currentParam['path']);
|
||||
$data[$currentParam['name'].'.class_name']=$currentParam['class_name'];
|
||||
$data[$currentParam['name'].'.namespace']=$namespace;
|
||||
|
||||
// 验证文件是否已存在
|
||||
$fileName = $currentParam['class_name'];
|
||||
if (!empty($currentConfig['file_name'])){
|
||||
$fileName = (new Utils())->replaceTemplate($currentConfig['file_name'],$data);
|
||||
}
|
||||
$filePath = '../'.$currentParamPath.'/'.$fileName.'.php';
|
||||
$data[$currentParam['name'].'.file_name']=$fileName;
|
||||
if(file_exists($filePath)){
|
||||
throw new ErrorException("file already exists",500,[
|
||||
'filepath'=>$filePath
|
||||
]);
|
||||
}
|
||||
$data[$currentParam['name'].'.use_path']=$namespace."\\".$fileName;
|
||||
$data[$currentParam['name'].'.use_alias']=$fileName.ucwords($currentParam['name']);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 字段过滤数据
|
||||
if (!empty($params['model']['table'])){
|
||||
$checkKeys = ['list','detail','add','edit'];
|
||||
foreach ($checkKeys as $checkKey){
|
||||
$itemArr = ['field'=>[],'withoutField'=>[]];
|
||||
foreach ($params['model']['table'] as $item){
|
||||
if ($item[$checkKey]){
|
||||
$itemArr['field'][]=$item['field'];
|
||||
}else{
|
||||
$itemArr['withoutField'][]=$item['field'];
|
||||
}
|
||||
}
|
||||
$data[$checkKey.'.field']=implode(",", $itemArr['field']);
|
||||
$data[$checkKey.'.withoutField']=implode(",", $itemArr['withoutField']);
|
||||
}
|
||||
// 查询条件、验证规则
|
||||
$query_where='$where=[];'."\r\n";
|
||||
$query_annotation = "";
|
||||
$validate_rule = "["."\r\n";
|
||||
$validate_message = "["."\r\n";
|
||||
$validate_fields = [];
|
||||
$addRequireFields = [];
|
||||
foreach ($params['model']['table'] as $i=>$item){
|
||||
if ($item['query']){
|
||||
$itemArr['field'][]=$item['field'];
|
||||
$query_where.= ' if(!empty($param[\''.$item['field'].'\'])){'."\r\n";
|
||||
$query_where.= ' $where[] = [\''.$item['field'].'\',\'=\',$param[\''.$item['field'].'\']];'."\r\n";
|
||||
$query_where.= ' }'."\r\n";
|
||||
$fh = empty($query_annotation)?'* ':' * ';
|
||||
$require = $item['not_null']==true?'true':'false';
|
||||
$rn="";
|
||||
if (($i+1)<count($params['model']['table'])){
|
||||
$rn="\r\n";
|
||||
}
|
||||
$query_annotation.=$fh.'@Apidoc\Param("'.$item['field'].'",type="'.$item['type'].'",require='.$require.',desc="'.$item['desc'].'")'.$rn;
|
||||
}
|
||||
// 验证规则
|
||||
if (!empty($this->config['validate'])){
|
||||
// 存在配置验证规则
|
||||
if (!empty($item['validate']) && $this->config['validate']['rules']){
|
||||
$rulesConfig = $this->config['validate']['rules'];
|
||||
$currentRuleConfig = "";
|
||||
foreach ($rulesConfig as $rule){
|
||||
if ($rule['rule'] === $item['validate']){
|
||||
$currentRuleConfig = $rule;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!empty($currentRuleConfig)){
|
||||
$validate_rule.=' \''.$item['field'].'\' => \''.$item['validate'].'\','."\r\n";
|
||||
if (!empty($currentRuleConfig['message']) ){
|
||||
if (is_array($currentRuleConfig['message']) && count($currentRuleConfig['message'])>0){
|
||||
foreach ($currentRuleConfig['message'] as $ruleKey=>$ruleMessage){
|
||||
if ($ruleKey=='0'){
|
||||
$ruleKeyStr = $item['field'];
|
||||
}else{
|
||||
$ruleKeyStr = Utils::replaceTemplate($ruleKey,$item);
|
||||
}
|
||||
$ruleMessageStr = Utils::replaceTemplate($ruleMessage,$item);
|
||||
$validate_message.=' \''.$ruleKeyStr.'\' => \''.$ruleMessageStr.'\','."\r\n";
|
||||
}
|
||||
}else{
|
||||
$ruleMessageStr = Utils::replaceTemplate($currentRuleConfig['message'],$item);
|
||||
$validate_message.=' \''.$item['field'].'\' => \''.$ruleMessageStr.'\','."\r\n";
|
||||
}
|
||||
}
|
||||
$validate_fields[]=$item['field'];
|
||||
if($item['field'] !== $data['main_key.field']){
|
||||
$addRequireFields[]=$item['field'];
|
||||
}
|
||||
}
|
||||
}else if($item['not_null']){
|
||||
$validate_fields[]=$item['field'];
|
||||
if($item['field'] !== $data['main_key.field']){
|
||||
$addRequireFields[]=$item['field'];
|
||||
}
|
||||
// 根据not_null生成必填
|
||||
$validate_rule.=' \''.$item['field'].'\' => \'require\','."\r\n";
|
||||
$validate_message.=' \''.$item['field'].'\' => \''.$item['field'].'不可为空\','."\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
$validate_rule.=' ];'."\r\n";
|
||||
$validate_message.=' ];'."\r\n";
|
||||
if (!empty($this->config['validate'])) {
|
||||
$data['validate.rule'] = $validate_rule;
|
||||
$data['validate.message'] = $validate_message;
|
||||
$data['validate.scene.edit'] = json_encode($validate_fields);
|
||||
$data['validate.scene.add'] = json_encode($addRequireFields)=='[]'?'[\'\']':json_encode($addRequireFields);
|
||||
$data['validate.scene.delete'] = '[\'' . $data['main_key.field'] . '\']';
|
||||
}
|
||||
|
||||
$data['query.where']=$query_where;
|
||||
$data['query.annotation']=$query_annotation;
|
||||
}
|
||||
return $data;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建数据表
|
||||
* @return mixed
|
||||
*/
|
||||
public function createModelTable($params,$title=""){
|
||||
$data = $params['table'];
|
||||
if (empty($title)){
|
||||
$title =$params['class_name'];
|
||||
}
|
||||
$driver = Config::get('database.default');
|
||||
$table_prefix=Config::get('database.connections.'.$driver.'.prefix');
|
||||
$table_name = $table_prefix.Utils::snake($params['class_name']);
|
||||
$table_data = '';
|
||||
$main_keys = '';
|
||||
foreach ($data as $item){
|
||||
$table_field="`".$item['field']."` ".$item['type'];
|
||||
if (!empty($item['length'])){
|
||||
$table_field.="(".$item['length'].")";
|
||||
}
|
||||
if ($item['main_key']){
|
||||
$main_keys.=$item['field'];
|
||||
$table_field.=" NOT NULL";
|
||||
}else if ($item['not_null']){
|
||||
$table_field.=" NOT NULL";
|
||||
}
|
||||
if ($item['incremental']==true){
|
||||
$table_field.=" AUTO_INCREMENT";
|
||||
}
|
||||
if (!empty($item['default']) || $item['default']=="0"){
|
||||
$table_field.=" DEFAULT '".$item['default']."'";
|
||||
}
|
||||
$table_field.=" COMMENT '".$item['desc']."',";
|
||||
$table_data.=$table_field;
|
||||
}
|
||||
$sql = "CREATE TABLE IF NOT EXISTS `$table_name` (
|
||||
$table_data
|
||||
PRIMARY KEY (`$main_keys`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='$title' AUTO_INCREMENT=1 ;";
|
||||
|
||||
$tp_version = \think\facade\App::version();
|
||||
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();
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
33
vendor/hg/apidoc/src/exception/AuthException.php
vendored
Normal file
33
vendor/hg/apidoc/src/exception/AuthException.php
vendored
Normal file
@@ -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');
|
||||
}
|
||||
}
|
||||
44
vendor/hg/apidoc/src/exception/ErrorException.php
vendored
Normal file
44
vendor/hg/apidoc/src/exception/ErrorException.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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 crud error' => ['code' => 5003, 'msg' => '数据表创建失败,请检查配置'],
|
||||
'file already exists' => ['code' => 5004, 'msg' => '${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');
|
||||
}
|
||||
|
||||
}
|
||||
127
vendor/hg/apidoc/src/parseApi/CacheApiData.php
vendored
Normal file
127
vendor/hg/apidoc/src/parseApi/CacheApiData.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace hg\apidoc\parseApi;
|
||||
|
||||
|
||||
use hg\apidoc\Utils;
|
||||
use think\facade\Config;
|
||||
|
||||
class CacheApiData
|
||||
{
|
||||
protected $config = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = Config::get('apidoc');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存目录
|
||||
* @param string $appKey
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheFolder(string $appKey):string
|
||||
{
|
||||
$config = $this->config;
|
||||
$currentApps = (new Utils())->getCurrentApps($appKey);
|
||||
$configPath = !empty($config['cache']) && !empty($config['cache']['path']) ? $config['cache']['path'] : '../runtime/apidoc/';
|
||||
$cacheAppFolder = "";
|
||||
if (!empty($currentApps) && count($currentApps) > 0) {
|
||||
foreach ($currentApps as $keyIndex => $appItem) {
|
||||
$cacheAppFolder .= $appItem['folder'] . "/";
|
||||
}
|
||||
}
|
||||
$cacheFolder = $configPath . $cacheAppFolder;
|
||||
return $cacheFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定目录下缓存文件名列表
|
||||
* @param string $folder
|
||||
* @return array
|
||||
*/
|
||||
public function getCacheFileList(string $folder):array
|
||||
{
|
||||
$filePaths = glob($folder . '*.json');
|
||||
$cacheFiles = [];
|
||||
if (count($filePaths) > 0) {
|
||||
foreach ($filePaths as $item) {
|
||||
$cacheFiles[] = str_replace(".json", "", basename($item));
|
||||
}
|
||||
}
|
||||
return $cacheFiles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取接口缓存数据
|
||||
* @param string $appKey
|
||||
* @param string $cacheFileName
|
||||
* @return array|false
|
||||
*/
|
||||
public function get(string $appKey, string $cacheFileName)
|
||||
{
|
||||
$cacheFolder = $this->getCacheFolder($appKey);
|
||||
$cacheFileList = $this->getCacheFileList($cacheFolder);
|
||||
if (!file_exists($cacheFolder)) {
|
||||
return false;
|
||||
}
|
||||
if (empty($cacheFileName) && count($cacheFileList) > 0) {
|
||||
// 默认最后一个缓存文件
|
||||
$cacheFileName = $cacheFileList[count($cacheFileList) - 1];
|
||||
}
|
||||
$cacheFilePath = $cacheFolder . "/" . $cacheFileName . '.json';
|
||||
if (file_exists($cacheFilePath)) {
|
||||
// 存在缓存文件
|
||||
$fileContent = file_get_contents($cacheFilePath);
|
||||
if (empty($fileContent)) {
|
||||
return false;
|
||||
}
|
||||
$json = json_decode($fileContent);
|
||||
if (is_object($json)) {
|
||||
$json = [
|
||||
"data" => $json->data,
|
||||
"tags" => $json->tags,
|
||||
"groups" => $json->groups,
|
||||
];
|
||||
}
|
||||
return [
|
||||
'name' => $cacheFileName,
|
||||
'data' => $json,
|
||||
'list' => $cacheFileList
|
||||
];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置接口缓存
|
||||
* @param string $appKey
|
||||
* @param array $json
|
||||
* @return array|false
|
||||
*/
|
||||
public function set(string $appKey, array $json):array
|
||||
{
|
||||
if (empty($json)) {
|
||||
return false;
|
||||
}
|
||||
$config = $this->config;
|
||||
$fileName = date("Y-m-d H_i_s");
|
||||
$fileContent = json_encode($json);
|
||||
$cacheFolder = $this->getCacheFolder($appKey);
|
||||
$path = $cacheFolder . $fileName . ".json";
|
||||
Utils::createFile($path, $fileContent);
|
||||
$filePaths = $this->getCacheFileList($cacheFolder);
|
||||
if ($config['cache']['max'] && count($filePaths) >= $config['cache']['max']) {
|
||||
//达到最大数量,删除第一个
|
||||
$filePath = $cacheFolder . $filePaths[0] . ".json";
|
||||
Utils::delFile($filePath);
|
||||
}
|
||||
return [
|
||||
"name" => $fileName,
|
||||
"data" => $json,
|
||||
"list" => $this->getCacheFileList($cacheFolder)
|
||||
];
|
||||
}
|
||||
}
|
||||
663
vendor/hg/apidoc/src/parseApi/ParseAnnotation.php
vendored
Normal file
663
vendor/hg/apidoc/src/parseApi/ParseAnnotation.php
vendored
Normal file
@@ -0,0 +1,663 @@
|
||||
<?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\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 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 = "";
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->reader = new AnnotationReader();
|
||||
$this->config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
|
||||
$this->controller_layer = Config::get('route.controller_layer',"controller");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成api接口数据
|
||||
* @param string $appKey
|
||||
* @return array
|
||||
*/
|
||||
public function renderApiData(string $appKey): array
|
||||
{
|
||||
$config = $this->config;
|
||||
$currentApps = (new Utils())->getCurrentApps($appKey);
|
||||
$currentApp = $currentApps[count($currentApps) - 1];
|
||||
|
||||
if (!empty($config['controllers']) && count($config['controllers']) > 0) {
|
||||
// 配置的控制器列表
|
||||
$controllers = $this->getConfigControllers($currentApp['path']);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
$json = array(
|
||||
"data" => $apiData,
|
||||
"tags" => $this->tags,
|
||||
"groups" => $this->groups
|
||||
);
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取生成文档的控制器列表
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
protected function getConfigControllers(string $path): array
|
||||
{
|
||||
$config = $this->config;
|
||||
$controllers = [];
|
||||
|
||||
$configControllers = $config['controllers'];
|
||||
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 (
|
||||
!isset($this->config['filter_controllers']) ||
|
||||
(isset($this->config['filter_controllers']) && !in_array($class, $this->config['filter_controllers'])) &&
|
||||
$this->config['definitions'] != $class
|
||||
) {
|
||||
if (strpos($class, '\\') === false) {
|
||||
$list[] = $appPath . "\\" . $class;
|
||||
} else {
|
||||
$list[] = $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function parseController($class)
|
||||
{
|
||||
$config = $this->config;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
$methodList = [];
|
||||
$filter_method = !empty($config['filter_method']) ? $config['filter_method'] : [];
|
||||
$data['menu_key'] = $data['controller'] . "_" . mt_rand(10000, 99999);
|
||||
|
||||
foreach ($refClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $refMethod) {
|
||||
if (!empty($refMethod->name) && !in_array($refMethod->name, $filter_method)) {
|
||||
$methodItem = $this->parseAnnotation($refMethod, true,"controller");
|
||||
if (!count((array)$methodItem)) {
|
||||
continue;
|
||||
}
|
||||
$textAnnotations = $this->parseTextAnnotation($refMethod);
|
||||
// 标注不解析的方法
|
||||
if (in_array("NotParse", $textAnnotations)) {
|
||||
continue;
|
||||
}
|
||||
// 无标题,且有文本注释
|
||||
if (empty($methodItem['title']) && !empty($textAnnotations) && count($textAnnotations) > 0) {
|
||||
$methodItem['title'] = $textAnnotations[0];
|
||||
}
|
||||
// 添加统一headers请求头参数
|
||||
if (!empty($config['headers']) && !in_array("NotHeaders", $textAnnotations)) {
|
||||
if (!empty($methodItem['header'])) {
|
||||
$methodItem['header'] = Utils::arrayMergeAndUnique("name", $config['headers'], $methodItem['header']);
|
||||
} else {
|
||||
$methodItem['header'] = $config['headers'];
|
||||
}
|
||||
}
|
||||
// 添加统一params请求参数
|
||||
if (!empty($config['parameters']) && !in_array("NotParameters", $textAnnotations)) {
|
||||
if (!empty($methodItem['param'])) {
|
||||
$methodItem['param'] = Utils::arrayMergeAndUnique("name", $config['parameters'], $methodItem['param']);
|
||||
} else {
|
||||
$methodItem['param'] = $config['parameters'];
|
||||
}
|
||||
}
|
||||
// 添加responses统一响应体
|
||||
if (
|
||||
!empty($config['responses']) &&
|
||||
!is_string($config['responses']) &&
|
||||
!in_array("NotResponses", $textAnnotations)
|
||||
) {
|
||||
// 显示在响应体中
|
||||
$returned = [];
|
||||
$hasMian = false;
|
||||
if (isset($config['responses']['data']) && !$config['responses']['show_responses']) {
|
||||
$responsesData = [];
|
||||
} else if (isset($config['responses']['data']) && $config['responses']['show_responses'] === true) {
|
||||
$responsesData = $config['responses']['data'];
|
||||
} else {
|
||||
$responsesData = $config['responses'];
|
||||
}
|
||||
// 合并统一响应体及响应参数相同的字段
|
||||
$returnData = [];
|
||||
$resKeys = [];
|
||||
foreach ($responsesData as $resItem) {
|
||||
$resKeys[]=$resItem['name'];
|
||||
}
|
||||
foreach ($methodItem['return'] as $returnItem){
|
||||
if (!(in_array($returnItem['name'],$resKeys) && $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'] && $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['params'] = $returnData;
|
||||
|
||||
$resData['resKeys']=$resKeys;
|
||||
$hasMian = true;
|
||||
}
|
||||
$resData['find'] =$globalFind;
|
||||
$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';
|
||||
}
|
||||
// 默认default_author
|
||||
if (empty($methodItem['author']) && !empty($config['default_author']) && !in_array("NotDefaultAuthor", $textAnnotations)) {
|
||||
$methodItem['author'] = $config['default_author'];
|
||||
}
|
||||
|
||||
// Tags
|
||||
if (!empty($methodItem['tag'])) {
|
||||
if (strpos($methodItem['tag'], ' ') !== false) {
|
||||
$tagArr = explode(" ", $methodItem['tag']);
|
||||
foreach ($tagArr as $tag) {
|
||||
if (!in_array($tag, $this->tags)) {
|
||||
$this->tags[] = $tag;
|
||||
}
|
||||
}
|
||||
} else if (!in_array($methodItem['tag'], $this->tags)) {
|
||||
$this->tags[] = $methodItem['tag'];
|
||||
}
|
||||
}
|
||||
|
||||
// 无url,自动生成
|
||||
if (empty($methodItem['url'])) {
|
||||
$methodItem['url'] = $this->autoCreateUrl($refMethod);
|
||||
} else if (!empty($routeGroup->value)) {
|
||||
// 路由分组,url加上分组
|
||||
$methodItem['url'] = '/' . $routeGroup->value . '/' . $methodItem['url'];
|
||||
}
|
||||
if (!empty($methodItem['url']) && substr($methodItem['url'], 0, 1) != "/") {
|
||||
$methodItem['url'] = "/" . $methodItem['url'];
|
||||
}
|
||||
$methodItem['name'] = $refMethod->name;
|
||||
$methodItem['menu_key'] = $methodItem['method'] . "_" . $refMethod->name . "_" . mt_rand(10000, 99999);
|
||||
|
||||
$methodList[] = $methodItem;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
$data['children'] = $methodList;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动生成url
|
||||
* @param $method
|
||||
* @return string
|
||||
*/
|
||||
protected function autoCreateUrl($method): string
|
||||
{
|
||||
if (Config::get("controller_auto_search") || !empty($this->config['controller_auto_search'])){
|
||||
$pathArr = explode("\\", $method->class );
|
||||
}else{
|
||||
$searchString = $this->controller_layer . '\\';
|
||||
$substr = substr(strstr($method->class, $searchString), strlen($searchString));
|
||||
$pathArr = explode("\\", str_replace($substr, str_replace('\\', '.', $substr), $method->class));
|
||||
}
|
||||
// 控制器地址
|
||||
$filterPathNames = array(App::getNamespace(), $this->controller_layer);
|
||||
$classPathArr = [];
|
||||
foreach ($pathArr as $item) {
|
||||
if (!in_array($item, $filterPathNames)) {
|
||||
if (!empty($this->config['auto_url_rule'])){
|
||||
switch ($this->config['auto_url_rule']) {
|
||||
case 'lcfirst':
|
||||
$classPathArr[] = lcfirst($item);
|
||||
break;
|
||||
case 'ucfirst':
|
||||
$classPathArr[] = ucfirst($item);
|
||||
break;
|
||||
default:
|
||||
$classPathArr[] = $item;
|
||||
}
|
||||
}else{
|
||||
$classPathArr[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
$classPath = implode('/', $classPathArr);
|
||||
return '/' . $classPath . '/' . $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" => $item->desc,
|
||||
"default" => $item->default,
|
||||
"require" => $item->require,
|
||||
"childrenType"=> $item->childrenType
|
||||
];
|
||||
$children = $this->handleParamValue($item->value);
|
||||
$param['name'] = $children['name'];
|
||||
if (count($children['params']) > 0) {
|
||||
$param['params'] = $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 = [];
|
||||
|
||||
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" => $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'] = $annotation->value;
|
||||
break;
|
||||
case $annotation instanceof Desc:
|
||||
$data['desc'] = $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:
|
||||
$data['method'] = $annotation->value;
|
||||
break;
|
||||
case $annotation instanceof Tag:
|
||||
$data['tag'] = $annotation->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($headers && count($headers) > 0) {
|
||||
$data['header'] = $headers;
|
||||
}
|
||||
$data['param'] = $params;
|
||||
$data['return'] = $returns;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理请求参数与返回参数
|
||||
* @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 = [
|
||||
"name" => "",
|
||||
"type" => $annotation->type,
|
||||
"desc" => $annotation->desc,
|
||||
"default" => $annotation->default,
|
||||
"require" => $annotation->require,
|
||||
"childrenType" => $annotation->childrenType,
|
||||
"source" => $source,
|
||||
"replaceGlobal" =>!empty($annotation->replaceGlobal)?$annotation->replaceGlobal:""
|
||||
];
|
||||
$children = $this->handleParamValue($annotation->value, $type);
|
||||
$param['name'] = $children['name'];
|
||||
if (count($children['params']) > 0) {
|
||||
$param['params'] = $children['params'];
|
||||
if ($annotation->type === 'tree' && !empty($annotation->childrenField)) {
|
||||
// 类型为tree的
|
||||
$param['params'][] = [
|
||||
'params' => $children['params'],
|
||||
'name' => $annotation->childrenField,
|
||||
'type' => 'array',
|
||||
'desc' => $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 = [
|
||||
'name' => $annotation->value,
|
||||
'desc' => $annotation->desc,
|
||||
'type' => $annotation->type,
|
||||
'require' => $annotation->require,
|
||||
'default' => $annotation->default,
|
||||
'params' => $data,
|
||||
'source'=>$source,
|
||||
"replaceGlobal" =>!empty($annotation->replaceGlobal)?$annotation->replaceGlobal:""
|
||||
];
|
||||
$children = $this->handleParamValue($annotation->value, 'param');
|
||||
$item['name'] = $children['name'];
|
||||
if (count($children['params']) > 0) {
|
||||
$item['params'] = Utils::arrayMergeAndUnique("name",$data,$children['params']);
|
||||
if ($annotation->type === 'tree' && !empty($annotation->childrenField)) {
|
||||
// 类型为tree的
|
||||
$item['params'][] = [
|
||||
'params' => $item['params'],
|
||||
'name' => $annotation->childrenField,
|
||||
'type' => 'array',
|
||||
'desc' => $annotation->childrenDesc,
|
||||
];
|
||||
}
|
||||
}
|
||||
$params[] = $item;
|
||||
|
||||
|
||||
} else {
|
||||
$params = array_merge($params, $data);
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
71
vendor/hg/apidoc/src/parseApi/ParseMarkdown.php
vendored
Normal file
71
vendor/hg/apidoc/src/parseApi/ParseMarkdown.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace hg\apidoc\parseApi;
|
||||
|
||||
use think\facade\App;
|
||||
use hg\apidoc\Utils;
|
||||
use think\facade\Config;
|
||||
|
||||
class ParseMarkdown
|
||||
{
|
||||
protected $config = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = Config::get('apidoc')?Config::get('apidoc'):Config::get('apidoc.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取md文档菜单
|
||||
* @return array
|
||||
*/
|
||||
public function getDocsMenu(): array
|
||||
{
|
||||
$config = $this->config;
|
||||
$docData = [];
|
||||
if (!empty($config['docs']) && !empty($config['docs']['menus']) && count($config['docs']['menus']) > 0) {
|
||||
$docData = $this->handleDocsMenuData($config['docs']['menus']);
|
||||
}
|
||||
return $docData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理md文档菜单数据
|
||||
* @param array $menus
|
||||
* @return array
|
||||
*/
|
||||
protected function handleDocsMenuData(array $menus): array
|
||||
{
|
||||
$list = [];
|
||||
foreach ($menus as $item) {
|
||||
if (!empty($item['items']) && count($item['items']) > 0) {
|
||||
$item['items'] = $this->handleDocsMenuData($item['items']);
|
||||
$item['group'] = 'markdown_doc';
|
||||
$item['menu_key'] = "md_group_" . mt_rand(10000, 99999);
|
||||
$list[] = $item;
|
||||
} else {
|
||||
$item['type'] = 'md';
|
||||
$item['menu_key'] = "md_" . mt_rand(10000, 99999);
|
||||
$list[] = $item;
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取md文档内容
|
||||
* @param string $appKey
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(string $appKey, string $path): string
|
||||
{
|
||||
$currentApps = (new Utils())->getCurrentApps($appKey);
|
||||
$mdPath = (new Utils())->replaceCurrentAppTemplate($path, $currentApps);
|
||||
$filePath = App::getRootPath() . $mdPath . '.md';
|
||||
$contents = Utils::getFileContent($filePath);
|
||||
return $contents;
|
||||
}
|
||||
}
|
||||
236
vendor/hg/apidoc/src/parseApi/ParseModel.php
vendored
Normal file
236
vendor/hg/apidoc/src/parseApi/ParseModel.php
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace hg\apidoc\parseApi;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
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)
|
||||
{
|
||||
$modelClassArr = explode("\\", $path);
|
||||
$modelActionName = $modelClassArr[count($modelClassArr) - 1];
|
||||
$modelClassName = $modelClassArr[count($modelClassArr) - 2];
|
||||
unset($modelClassArr[count($modelClassArr) - 1]);
|
||||
$modelClassPath = implode("\\", $modelClassArr);
|
||||
$classReflect = new \ReflectionClass($modelClassPath);
|
||||
$modelActionName = trim($modelActionName);
|
||||
$methodAction = $classReflect->getMethod($modelActionName);
|
||||
// 获取所有模型属性
|
||||
$propertys = $classReflect->getDefaultProperties();
|
||||
|
||||
// 获取表字段
|
||||
$model = $this->getModel($methodAction, $modelClassName);
|
||||
if (!is_callable(array($model, 'getTable'))) {
|
||||
return false;
|
||||
}
|
||||
$table = $this->getTableDocument($model, $propertys);
|
||||
|
||||
// 模型注释-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['params'] = $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['params'] = $children['params'];
|
||||
}
|
||||
$params[] = $param;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$name = $values;
|
||||
}
|
||||
return ['name' => $name, 'params' => $params];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型实例
|
||||
* @param $method
|
||||
* @param $modelClassName
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getModel($method, $modelClassName)
|
||||
{
|
||||
if (!empty($method->class)) {
|
||||
$relationModelClass = $this->getIncludeClassName($method->class, $modelClassName);
|
||||
if ($relationModelClass) {
|
||||
$modelInstance = new $relationModelClass();
|
||||
return $modelInstance;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取模型类
|
||||
* @param $mainClass
|
||||
* @param $class
|
||||
* @return string
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected function getIncludeClassName($mainClass, $class)
|
||||
{
|
||||
$classReflect = new \ReflectionClass($mainClass);
|
||||
$possibleClass = $classReflect->getNamespaceName() . "\\" . $class;
|
||||
if (class_exists($possibleClass)) {
|
||||
return $possibleClass;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型注解数据
|
||||
* @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]['Create Table'];
|
||||
}else{
|
||||
$createSQL = Db::query("show create table " . $model->getTable())[0]['Create Table'];
|
||||
}
|
||||
// $createSQL = Db::query("show create table " . $model->getTable())[0]['Create Table'];
|
||||
preg_match_all("#[^KEY]`(.*?)` (.*?) (.*?),\n#", $createSQL, $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 = "0";
|
||||
$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 = $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;
|
||||
}
|
||||
|
||||
}
|
||||
3
vendor/itxq/api-doc-php/.gitignore
vendored
Normal file
3
vendor/itxq/api-doc-php/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.idea
|
||||
/vendor/
|
||||
/composer.lock
|
||||
191
vendor/itxq/api-doc-php/LICENSE
vendored
Normal file
191
vendor/itxq/api-doc-php/LICENSE
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "{}" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright 2018 IT小强xqitw.cn
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
49
vendor/itxq/api-doc-php/README.md
vendored
Normal file
49
vendor/itxq/api-doc-php/README.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
# Api-Doc-PHP
|
||||
|
||||
### 主要功能:
|
||||
|
||||
+ 根据接口注释自动生成接口文档
|
||||
|
||||
### 演示地址
|
||||
|
||||
[【Gitee Pages:】http://itxq.gitee.io/api-doc-php](http://itxq.gitee.io/api-doc-php)
|
||||
|
||||
### 开源地址:
|
||||
|
||||
[【GigHub:】https://github.com/itxq/api-doc-php](https://github.com/itxq/api-doc-php)
|
||||
|
||||
[【码云:】https://gitee.com/itxq/api-doc-php](https://github.com/itxq/api-doc-php)
|
||||
|
||||
### 扩展安装:
|
||||
|
||||
+ 方法一:composer命令 `composer require itxq/api-doc-php`
|
||||
|
||||
+ 方法二:直接下载压缩包,然后进入项目中执行 composer命令 `composer update` 来生成自动加载文件
|
||||
|
||||
### 引用扩展:
|
||||
|
||||
+ 当你的项目不支持composer自动加载时,可以使用以下方式来引用该扩展包
|
||||
|
||||
```
|
||||
// 引入扩展(具体路径请根据你的目录结构自行修改)
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
```
|
||||
|
||||
### 使用扩展:
|
||||
|
||||
```
|
||||
// 引入扩展(具体路径请根据你的目录结构自行修改)
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
// 加载测试API类1
|
||||
require_once __DIR__ . '/Api.php';
|
||||
// 加载测试API类2
|
||||
require_once __DIR__ . '/Api2.php';
|
||||
$config = [
|
||||
'class' => ['Api', 'Api2'], // 要生成文档的类
|
||||
'filter_method' => ['__construct'], // 要过滤的方法名称
|
||||
];
|
||||
$api = new \itxq\apidoc\BootstrapApiDoc($config);
|
||||
$doc = $api->getHtml();
|
||||
exit($doc);
|
||||
```
|
||||
### 具体效果可运行test目录下的`index.php`查看
|
||||
7
vendor/itxq/api-doc-php/assets/css/bootstrap.min.css
vendored
Normal file
7
vendor/itxq/api-doc-php/assets/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
193
vendor/itxq/api-doc-php/assets/index.html
vendored
Normal file
193
vendor/itxq/api-doc-php/assets/index.html
vendored
Normal file
File diff suppressed because one or more lines are too long
7
vendor/itxq/api-doc-php/assets/js/bootstrap.min.js
vendored
Normal file
7
vendor/itxq/api-doc-php/assets/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
vendor/itxq/api-doc-php/assets/js/jquery.min.js
vendored
Normal file
2
vendor/itxq/api-doc-php/assets/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
20
vendor/itxq/api-doc-php/composer.json
vendored
Normal file
20
vendor/itxq/api-doc-php/composer.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name" : "itxq/api-doc-php",
|
||||
"description": "api-doc-php",
|
||||
"type" : "library",
|
||||
"license" : "Apache-2.0",
|
||||
"authors" : [
|
||||
{
|
||||
"name" : "IT小强xqitw.cn",
|
||||
"email": "360237521@qq.com"
|
||||
}
|
||||
],
|
||||
"require" : {
|
||||
"php": ">=5.6.0"
|
||||
},
|
||||
"autoload" : {
|
||||
"psr-4": {
|
||||
"itxq\\apidoc\\": "src"
|
||||
}
|
||||
}
|
||||
}
|
||||
126
vendor/itxq/api-doc-php/src/ApiDoc.php
vendored
Normal file
126
vendor/itxq/api-doc-php/src/ApiDoc.php
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: ApiDoc.php
|
||||
* 概 要: ApiDoc生成
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/5 9:40
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
|
||||
namespace itxq\apidoc;
|
||||
|
||||
use itxq\apidoc\lib\ParseComment;
|
||||
|
||||
/**
|
||||
* ApiDoc生成
|
||||
* Class ApiDoc
|
||||
* @package itxq\apidoc
|
||||
*/
|
||||
class ApiDoc
|
||||
{
|
||||
/**
|
||||
* @var array - 结构化的数组
|
||||
*/
|
||||
private $ApiTree = [];
|
||||
|
||||
/**
|
||||
* @var array - 要生成API的Class类名
|
||||
*/
|
||||
private $class = [];
|
||||
|
||||
/**
|
||||
* @var array - 忽略生成的类方法名
|
||||
*/
|
||||
private $filterMethod = ['__construct'];
|
||||
|
||||
/**
|
||||
* ApiDoc 构造函数.
|
||||
* @param array $config - 配置信息
|
||||
*/
|
||||
public function __construct($config) {
|
||||
// 需要解析的类
|
||||
if (isset($config['class'])) {
|
||||
$this->class = array_merge($this->class, $config['class']);
|
||||
}
|
||||
// 忽略生成的类方法
|
||||
if (isset($config['filter_method'])) {
|
||||
$this->filterMethod = array_merge($this->filterMethod, $config['filter_method']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取API文档数据
|
||||
* @param int $type - 方法过滤,默认只获取 public类型 方法
|
||||
* ReflectionMethod::IS_STATIC
|
||||
* ReflectionMethod::IS_PUBLIC
|
||||
* ReflectionMethod::IS_PROTECTED
|
||||
* ReflectionMethod::IS_PRIVATE
|
||||
* ReflectionMethod::IS_ABSTRACT
|
||||
* ReflectionMethod::IS_FINAL
|
||||
* @return array
|
||||
*/
|
||||
public function getApiDoc($type = \ReflectionMethod::IS_PUBLIC) {
|
||||
foreach ($this->class as $classItem) {
|
||||
$actionInfo = $this->_getActionComment($classItem, $type);
|
||||
if (count($actionInfo) >= 1) {
|
||||
$this->ApiTree[$classItem] = $this->_getClassComment($classItem);
|
||||
$this->ApiTree[$classItem]['action'] = $actionInfo;
|
||||
}
|
||||
}
|
||||
return $this->ApiTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的注释
|
||||
* @param $class - 类名称(存在命名空间时要完整写入) eg: $class = 'itxq\\apidoc\\ApiDoc';
|
||||
* @return array - 返回格式为数组(未获取到注释时返回空数组)
|
||||
*/
|
||||
private function _getClassComment($class) {
|
||||
try {
|
||||
$reflection = new \ReflectionClass($class);
|
||||
$classDocComment = $reflection->getDocComment();
|
||||
} catch (\Exception $exception) {
|
||||
return [];
|
||||
}
|
||||
$parse = new ParseComment();
|
||||
return $parse->parseCommentToArray($classDocComment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类下方法的注释
|
||||
* @param $class - 类名称(存在命名空间时要完整写入) eg: $class = 'itxq\\apidoc\\ApiDoc';
|
||||
* @param int $type - 方法过滤,默认只获取 public类型 方法
|
||||
* ReflectionMethod::IS_STATIC
|
||||
* ReflectionMethod::IS_PUBLIC
|
||||
* ReflectionMethod::IS_PROTECTED
|
||||
* ReflectionMethod::IS_PRIVATE
|
||||
* ReflectionMethod::IS_ABSTRACT
|
||||
* ReflectionMethod::IS_FINAL
|
||||
* @return array - 返回格式为数组(未获取到注释时返回空数组)
|
||||
*/
|
||||
private function _getActionComment($class, $type = \ReflectionMethod::IS_PUBLIC) {
|
||||
try {
|
||||
$reflection = new \ReflectionClass($class);
|
||||
//只允许生成public方法
|
||||
$method = $reflection->getMethods($type);
|
||||
} catch (\Exception $exception) {
|
||||
return [];
|
||||
}
|
||||
$comments = [];
|
||||
foreach ($method as $action) {
|
||||
try {
|
||||
$parse = new ParseComment();
|
||||
$actionComments = $parse->parseCommentToArray($action->getDocComment());
|
||||
if (count($actionComments) >= 1 && !in_array($action->name, $this->filterMethod)) {
|
||||
$comments[$action->name] = $actionComments;
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return $comments;
|
||||
}
|
||||
}
|
||||
357
vendor/itxq/api-doc-php/src/BootstrapApiDoc.php
vendored
Normal file
357
vendor/itxq/api-doc-php/src/BootstrapApiDoc.php
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: BootstrapApiDoc.php
|
||||
* 概 要: BootstrapAPI文档生成
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/6 13:57
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
|
||||
namespace itxq\apidoc;
|
||||
|
||||
use itxq\apidoc\lib\Tools;
|
||||
|
||||
/**
|
||||
* BootstrapAPI文档生成
|
||||
* Class BootstrapApiDoc
|
||||
* @package itxq\apidoc
|
||||
*/
|
||||
class BootstrapApiDoc extends ApiDoc
|
||||
{
|
||||
/**
|
||||
* @var string - Bootstrap CSS文件路径
|
||||
*/
|
||||
private $bootstrapCss = __DIR__ . '/../assets/css/bootstrap.min.css';
|
||||
|
||||
/**
|
||||
* @var string - Bootstrap JS文件路径
|
||||
*/
|
||||
private $bootstrapJs = __DIR__ . '/../assets/js/bootstrap.min.js';
|
||||
|
||||
/**
|
||||
* @var string - jQuery Js文件路径
|
||||
*/
|
||||
private $jQueryJs = __DIR__ . '/../assets/js/jquery.min.js';
|
||||
|
||||
/**
|
||||
* @var string - 自定义CSS
|
||||
*/
|
||||
private $customCss = '<style type="text/css">
|
||||
::-webkit-scrollbar {width: 5px;}
|
||||
.navbar-collapse.collapse.show::-webkit-scrollbar {width: 0; height: 0;background-color: rgba(255, 255, 255, 0);}
|
||||
::-webkit-scrollbar-track {background-color: rgba(255, 255, 255, 0.2);-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;}
|
||||
::-webkit-scrollbar-thumb {background-color: rgba(0, 0, 0, 0.8);-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;}
|
||||
::-webkit-scrollbar-button {-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;height: 0;background-color: rgba(0, 0, 0, 0.9);}
|
||||
::-webkit-scrollbar-corner {background-color: rgba(0, 0, 0, 0.9);}
|
||||
#list-tab-left-nav{display: none;}
|
||||
.doc-content{margin-top: 75px;}
|
||||
.class-item .class-title {text-indent: 0.6em;border-left: 5px solid lightseagreen;font-size: 24px;margin: 15px 0;}
|
||||
.action-item .action-title {text-indent: 0.6em;border-left: 3px solid #F0AD4E;font-size: 20px;margin: 8px 0;}
|
||||
.table-item {background-color:#FFFFFF;padding-top: 10px;margin-bottom:10px;border: solid 1px #ccc;border-radius: 5px;}
|
||||
.list-group-item-sub{padding: .5rem 1.25rem;}
|
||||
.copyright-content{margin: 10px 0;}
|
||||
</style>';
|
||||
|
||||
/**
|
||||
* @var string - 自定义JS
|
||||
*/
|
||||
private $customJs = '<script type="text/javascript">
|
||||
$(\'a[href*="#"]:not([href="#"])\').click(function() {
|
||||
if (location.pathname.replace(/^\//, \'\') == this.pathname.replace(/^\//, \'\') && location.hostname == this.hostname) {
|
||||
var target = $(this.hash);
|
||||
target = target.length ? target : $("[name=\' + this.hash.slice(1) +\']");
|
||||
if (target.length) {
|
||||
var topOffset = target.offset().top - 60;
|
||||
$("html, body").animate({
|
||||
scrollTop: topOffset
|
||||
}, 800);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>';
|
||||
|
||||
/**
|
||||
* Bootstrap 构造函数.
|
||||
* @param array $config - 配置信息
|
||||
*/
|
||||
public function __construct($config) {
|
||||
parent::__construct($config);
|
||||
// bootstrapJs文件路径
|
||||
$this->bootstrapJs = Tools::getSubValue('bootstrap_js', $config, $this->bootstrapJs);
|
||||
// jQueryJs文件路径
|
||||
$this->jQueryJs = Tools::getSubValue('jquery_js', $config, $this->jQueryJs);
|
||||
// 自定义js
|
||||
$this->customJs .= Tools::getSubValue('custom_js', $config, '');
|
||||
// bootstrapCSS文件路径
|
||||
$this->bootstrapCss = Tools::getSubValue('bootstrap_css', $config, $this->bootstrapCss);
|
||||
// 自定义CSS
|
||||
$this->customCss .= Tools::getSubValue('custom_css', $config, '');
|
||||
// 合并CSS
|
||||
$this->_getCss();
|
||||
// 合并JS
|
||||
$this->_getJs();
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出HTML
|
||||
* @param int $type - 方法过滤,默认只获取 public类型 方法
|
||||
* ReflectionMethod::IS_STATIC
|
||||
* ReflectionMethod::IS_PUBLIC
|
||||
* ReflectionMethod::IS_PROTECTED
|
||||
* ReflectionMethod::IS_PRIVATE
|
||||
* ReflectionMethod::IS_ABSTRACT
|
||||
* ReflectionMethod::IS_FINAL
|
||||
* @return string
|
||||
*/
|
||||
public function getHtml($type = \ReflectionMethod::IS_PUBLIC) {
|
||||
$data = $this->getApiDoc($type);
|
||||
$html = <<<EXT
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
||||
<!-- 禁止浏览器初始缩放 -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1, user-scalable=0">
|
||||
<title>API文档 By Api-Doc-PHP</title>
|
||||
{$this->customCss}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top">
|
||||
<a class="navbar-brand" href="#">API文档</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01" >
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarColor01">
|
||||
{$this->_getTopNavList($data)}
|
||||
</div>
|
||||
</nav>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">{$this->_getDocList($data)}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center copyright-content">
|
||||
Copyright 2016 - 2018 <a href="http://www.xqitw.cn">小强IT屋</a> 版权所有
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{$this->customJs}
|
||||
</body>
|
||||
</html>
|
||||
EXT;
|
||||
|
||||
if (isset($_GET['download']) && $_GET['download'] === 'api_doc_php') {
|
||||
Tools::downloadFile($html);
|
||||
return true;
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析return 并生成HTML
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
private function _getReturnData($data = []) {
|
||||
$html = '';
|
||||
if (!is_array($data) || count($data) < 1) {
|
||||
return $html;
|
||||
}
|
||||
$html .= '<div class="table-item col-md-12"><p class="table-title"><span class="btn btn-sm btn-success">返回参数</span></p>';
|
||||
$html .= '<table class="table"><tr><td>参数</td><td>类型</td><td>描述</td></tr>';
|
||||
foreach ($data as $v) {
|
||||
$html .= '<tr>
|
||||
<td>' . Tools::getSubValue('return_name', $v, '') . '</td>
|
||||
<td>' . Tools::getSubValue('return_type', $v, '') . '</td>
|
||||
<td>' . Tools::getSubValue('return_title', $v, '') . '</td>
|
||||
</tr>';
|
||||
}
|
||||
$html .= '</table></div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析param 并生成HTML
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
private function _getParamData($data = []) {
|
||||
$html = '';
|
||||
if (!is_array($data) || count($data) < 1) {
|
||||
return $html;
|
||||
}
|
||||
$html .= '<div class="table-item col-md-12"><p class="table-title"><span class="btn btn-sm btn-danger">请求参数</span></p>';
|
||||
$html .= '<table class="table"><tr><td>参数</td><td>类型</td><td>描述</td><td>默认值</td><td>是否必须</td></tr>';
|
||||
foreach ($data as $v) {
|
||||
$html .= '<tr>
|
||||
<td>' . Tools::getSubValue('param_name', $v, '') . '</td>
|
||||
<td>' . Tools::getSubValue('param_type', $v, '') . '</td>
|
||||
<td>' . Tools::getSubValue('param_title', $v, '') . '</td>
|
||||
<td>' . Tools::getSubValue('param_default', $v, '无默认值') . '</td>
|
||||
<td>' . Tools::getSubValue('param_require', $v, '非必须') . '</td>
|
||||
</tr>';
|
||||
}
|
||||
$html .= '</table></div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析code 并生成HTML
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
private function _getCodeData($data = []) {
|
||||
$html = '';
|
||||
if (!is_array($data) || count($data) < 1) {
|
||||
return $html;
|
||||
}
|
||||
$html .= '<div class="table-item col-md-12"><p class="table-title"><span class="btn btn-sm btn-warning">状态码说明</span></p>';
|
||||
$html .= '<table class="table"><tr><td>状态码</td><td>描述</td></tr>';
|
||||
foreach ($data as $v) {
|
||||
$html .= '<tr>
|
||||
<td>' . Tools::getSubValue('code', $v, '') . '</td>
|
||||
<td>' . Tools::getSubValue('content', $v, '暂无说明') . '</td>
|
||||
</tr>';
|
||||
}
|
||||
$html .= '</table></div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定接口操作下的文档信息
|
||||
* @param $className - 类名
|
||||
* @param $actionName - 操作名
|
||||
* @param $actionItem - 接口数据
|
||||
* @return string
|
||||
*/
|
||||
private function _getActionItem($className, $actionName, $actionItem) {
|
||||
$html = <<<EXT
|
||||
<div class="list-group-item list-group-item-action action-item col-md-12" id="{$className}_{$actionName}">
|
||||
<h4 class="action-title">API - {$actionItem['title']}</h4>
|
||||
<p>请求方式:
|
||||
<span class="btn btn-info btn-sm">{$actionItem['method']}</span>
|
||||
</p>
|
||||
<p>请求地址:<a href="{$actionItem['url']}">{$actionItem['url']}</a></p>
|
||||
{$this->_getParamData(Tools::getSubValue('param', $actionItem, []))}
|
||||
{$this->_getReturnData(Tools::getSubValue('return', $actionItem, []))}
|
||||
{$this->_getCodeData(Tools::getSubValue('code', $actionItem, []))}
|
||||
</div>
|
||||
EXT;
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定API类的文档HTML
|
||||
* @param $className - 类名称
|
||||
* @param $classItem - 类数据
|
||||
* @return string
|
||||
*/
|
||||
private function _getClassItem($className, $classItem) {
|
||||
$title = Tools::getSubValue('title', $classItem, '未命名');
|
||||
$actionHtml = '';
|
||||
if (isset($classItem['action']) && is_array($classItem['action']) && count($classItem['action']) >= 1) {
|
||||
foreach ($classItem['action'] as $actionName => $actionItem) {
|
||||
$actionHtml .= $this->_getActionItem($className, $actionName, $actionItem);
|
||||
}
|
||||
}
|
||||
$html = <<<EXT
|
||||
<div class="class-item" id="{$className}">
|
||||
<h2 class="class-title">{$title}</h2>
|
||||
<div class="list-group">{$actionHtml}</div>
|
||||
</div>
|
||||
EXT;
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取API文档HTML
|
||||
* @param array $data - 文档数据
|
||||
* @return string
|
||||
*/
|
||||
private function _getDocList($data) {
|
||||
$html = '';
|
||||
if (count($data) < 1) {
|
||||
return $html;
|
||||
}
|
||||
$html .= '<div class="doc-content">';
|
||||
foreach ($data as $className => $classItem) {
|
||||
$html .= $this->_getClassItem($className, $classItem);
|
||||
}
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶部导航HTML
|
||||
* @param $data -API文档数据
|
||||
* @return string
|
||||
*/
|
||||
private function _getTopNavList($data) {
|
||||
$html = '<ul class="navbar-nav" id="navbar-nav-top-nav">';
|
||||
foreach ($data as $className => $classItem) {
|
||||
$title = Tools::getSubValue('title', $classItem, '未命名');
|
||||
$html .= '<li class="nav-item dropdown">';
|
||||
$html .= '<a class="nav-link dropdown-toggle" href="#" id="' . $className . '-nav" data-toggle="dropdown">' . $title . '</a>';
|
||||
$html .= '<div class="dropdown-menu" aria-labelledby="' . $className . '-nav">';
|
||||
foreach ($classItem['action'] as $actionName => $actionItem) {
|
||||
$title = Tools::getSubValue('title', $actionItem, '未命名');
|
||||
$id = $className . '_' . $actionName;
|
||||
$html .= '<a class="dropdown-item" href="#' . $id . '">' . $title . '</a>';
|
||||
}
|
||||
$html .= '</div></li>';
|
||||
}
|
||||
$html .= ' <li class="nav-item"><a class="nav-link" href="?download=api_doc_php">下载文档</a></li>';
|
||||
$html .= '</ul>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档CSS
|
||||
* @return string
|
||||
*/
|
||||
private function _getCss() {
|
||||
$path = realpath($this->bootstrapCss);
|
||||
if (!$path || !is_file($path)) {
|
||||
return $this->customCss;
|
||||
}
|
||||
$bootstrapCss = file_get_contents($path);
|
||||
if (empty($bootstrapCss)) {
|
||||
return $this->customCss;
|
||||
}
|
||||
$this->customCss = '<style type="text/css">' . $bootstrapCss . '</style>' . $this->customCss;
|
||||
// $this->customCss = ' <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">' . $this->customCss;
|
||||
return $this->customCss;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档JS
|
||||
* @return string
|
||||
*/
|
||||
private function _getJs() {
|
||||
// $js = '<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>';
|
||||
// $js .= '<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" type="text/javascript"></script>';
|
||||
// $this->customJs = $js . $this->customJs;
|
||||
// return $this->customJs;
|
||||
$bootstrapJs = realpath($this->bootstrapJs);
|
||||
$jQueryJs = realpath($this->jQueryJs);
|
||||
if (!$bootstrapJs || !$jQueryJs || !is_file($bootstrapJs) || !is_file($jQueryJs)) {
|
||||
$this->customJs = '';
|
||||
return $this->customCss;
|
||||
}
|
||||
$bootstrapJs = file_get_contents($bootstrapJs);
|
||||
$jQueryJs = file_get_contents($jQueryJs);
|
||||
if (empty($bootstrapJs) || empty($jQueryJs)) {
|
||||
$this->customJs = '';
|
||||
return $this->customJs;
|
||||
}
|
||||
$js = '<script type="text/javascript">' . $jQueryJs . '</script>' . '<script type="text/javascript">' . $bootstrapJs . '</script>';
|
||||
$this->customJs = $js . $this->customJs;
|
||||
return $this->customJs;
|
||||
}
|
||||
}
|
||||
87
vendor/itxq/api-doc-php/src/lib/ParseComment.php
vendored
Normal file
87
vendor/itxq/api-doc-php/src/lib/ParseComment.php
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: ParseComment.php
|
||||
* 概 要: 注释解析
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/5 10:38
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
|
||||
namespace itxq\apidoc\lib;
|
||||
|
||||
/**
|
||||
* 注释解析
|
||||
* Class ParseComment
|
||||
* @package itxq\apidoc\lib
|
||||
*/
|
||||
class ParseComment
|
||||
{
|
||||
/**
|
||||
* @var array - 注释解析后的数组
|
||||
*/
|
||||
private $commentParams = [];
|
||||
|
||||
/**
|
||||
* 将注释按行解析并以数组格式返回
|
||||
* @param $comment - 原始注释字符串
|
||||
* @return bool|array
|
||||
*/
|
||||
public function parseCommentToArray($comment) {
|
||||
$comments = [];
|
||||
if (empty($comment)) {
|
||||
return $comments;
|
||||
}
|
||||
// 获取注释
|
||||
if (preg_match('#^/\*\*(.*)\*/#s', $comment, $matches) === false) {
|
||||
return $comments;
|
||||
}
|
||||
$matches = trim($matches[1]);
|
||||
// 按行分割注释
|
||||
if (preg_match_all('#^\s*\*(.*)#m', $matches, $lines) === false) {
|
||||
return $comments;
|
||||
}
|
||||
$comments = $lines[1];
|
||||
// 去除无用的注释
|
||||
foreach ($comments as $k => $v) {
|
||||
$comments[$k] = $v = trim($v);
|
||||
if (strpos($v, '@') !== 0) {
|
||||
continue;
|
||||
}
|
||||
$_parse = $this->_parseCommentLine($v);
|
||||
if (!$_parse) {
|
||||
continue;
|
||||
}
|
||||
$_type = $_parse['type'];
|
||||
$_content = isset($_parse['content']) ? $_parse['content'] : '';
|
||||
if (in_array($_type, ['param', 'code', 'return'])) {
|
||||
if (!isset($this->commentParams[$_type])) {
|
||||
$this->commentParams[$_type] = [];
|
||||
}
|
||||
unset($_parse['type']);
|
||||
$this->commentParams[$_type][] = $_parse;
|
||||
} else {
|
||||
$this->commentParams[$_type] = $_content;
|
||||
}
|
||||
}
|
||||
return $this->commentParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析注释中的参数
|
||||
* @param $line - 注释行
|
||||
* @return bool|array - 解析后的数组(解析失败返回false)
|
||||
*/
|
||||
private function _parseCommentLine($line) {
|
||||
$line = explode(' ', $line);
|
||||
$line[0] = substr($line[0], 1);
|
||||
$class = new ParseLine();
|
||||
$action = 'parseLine' . Tools::underlineToHump($line[0]);
|
||||
if (!method_exists($class, $action)) {
|
||||
$action = 'parseLineTitle';
|
||||
}
|
||||
return $class->$action($line);
|
||||
}
|
||||
}
|
||||
73
vendor/itxq/api-doc-php/src/lib/ParseLine.php
vendored
Normal file
73
vendor/itxq/api-doc-php/src/lib/ParseLine.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: ParseLine.php
|
||||
* 概 要: 按行解析注释参数
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/5 10:34
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
|
||||
namespace itxq\apidoc\lib;
|
||||
|
||||
/**
|
||||
* 按行解析注释参数
|
||||
* Class ParseLine
|
||||
* @package itxq\apidoc\lib
|
||||
*/
|
||||
class ParseLine
|
||||
{
|
||||
/**
|
||||
* 解析 title|url
|
||||
* @param $line
|
||||
* @return array
|
||||
*/
|
||||
public function parseLineTitle($line) {
|
||||
return ['type' => isset($line[0]) ? $line[0] : '', 'content' => isset($line[1]) ? $line[1] : ''];
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 param
|
||||
* @param $line
|
||||
* @return array
|
||||
*/
|
||||
public function parseLineParam($line) {
|
||||
return [
|
||||
'type' => isset($line[0]) ? $line[0] : '',
|
||||
'param_type' => isset($line[1]) ? $line[1] : '',
|
||||
'param_name' => isset($line[2]) ? $line[2] : '',
|
||||
'param_title' => isset($line[3]) ? $line[3] : '',
|
||||
'param_default' => isset($line[4]) ? $line[4] : '',
|
||||
'param_require' => isset($line[5]) ? $line[5] : '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 code
|
||||
* @param $line
|
||||
* @return array
|
||||
*/
|
||||
public function parseLineCode($line) {
|
||||
return [
|
||||
'type' => isset($line[0]) ? $line[0] : '',
|
||||
'code' => isset($line[1]) ? $line[1] : '',
|
||||
'content' => isset($line[2]) ? $line[2] : '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 return
|
||||
* @param $line
|
||||
* @return array
|
||||
*/
|
||||
public function parseLineReturn($line) {
|
||||
return [
|
||||
'type' => isset($line[0]) ? $line[0] : '',
|
||||
'return_type' => isset($line[1]) ? $line[1] : '',
|
||||
'return_name' => isset($line[2]) ? $line[2] : '',
|
||||
'return_title' => isset($line[3]) ? $line[3] : '',
|
||||
];
|
||||
}
|
||||
}
|
||||
82
vendor/itxq/api-doc-php/src/lib/Tools.php
vendored
Normal file
82
vendor/itxq/api-doc-php/src/lib/Tools.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: Tools.php
|
||||
* 概 要:
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/6 8:47
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
|
||||
namespace itxq\apidoc\lib;
|
||||
|
||||
/**
|
||||
* 工具类
|
||||
* Class Tools
|
||||
* @package itxq\apidoc\lib
|
||||
*/
|
||||
class Tools
|
||||
{
|
||||
/**
|
||||
* 下划线命名转驼峰命名
|
||||
* @param $str - 下划线命名字符串
|
||||
* @param $isFirst - 是否为大驼峰(即首字母也大写)
|
||||
* @return mixed
|
||||
*/
|
||||
public static function underlineToHump($str, $isFirst = false) {
|
||||
$str = preg_replace_callback('/([\-\_]+([a-z]{1}))/i', function ($matches) {
|
||||
return strtoupper($matches[2]);
|
||||
}, $str);
|
||||
if ($isFirst) {
|
||||
$str = ucfirst($str);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名转下划线命名
|
||||
* @param $str
|
||||
* @return mixed
|
||||
*/
|
||||
public static function humpToUnderline($str) {
|
||||
$str = preg_replace_callback('/([A-Z]{1})/', function ($matches) {
|
||||
return '_' . strtolower($matches[0]);
|
||||
}, $str);
|
||||
$str = preg_replace('/^\_/', '', $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数组、对象下标对应值,不存在时返回指定的默认值
|
||||
* @param string|integer $name - 下标(键名)
|
||||
* @param array|object $data - 原始数组/对象
|
||||
* @param mixed $default - 指定默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getSubValue($name, $data, $default = '') {
|
||||
if (is_object($data)) {
|
||||
$value = isset($data->$name) ? $data->$name : $default;
|
||||
} else if (is_array($data)) {
|
||||
$value = isset($data[$name]) ? $data[$name] : $default;
|
||||
} else {
|
||||
$value = $default;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
* @param string - $docHtml - API文档HTML内容
|
||||
*/
|
||||
public static function downloadFile($docHtml) {
|
||||
set_time_limit(0);
|
||||
//下载文件需要用到的头
|
||||
header('Content-type: application/octet-stream');
|
||||
header('Accept-Ranges: bytes');
|
||||
header('Content-Disposition: attachment; filename=api-doc_' . date('Y-m-d') . '.html');
|
||||
echo $docHtml;
|
||||
exit();
|
||||
}
|
||||
}
|
||||
49
vendor/itxq/api-doc-php/test/Api.php
vendored
Normal file
49
vendor/itxq/api-doc-php/test/Api.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: Api.php
|
||||
* 概 要:
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/5 9:43
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @title 登录注册
|
||||
* Class Api
|
||||
*/
|
||||
class Api
|
||||
{
|
||||
/**
|
||||
* @title 用户登录API
|
||||
* @url https://wwww.baidu.com/login
|
||||
* @method POST
|
||||
* @param string username 账号 空 必须
|
||||
* @param string password 密码 空 必须
|
||||
* @code 1 成功
|
||||
* @code 2 失败
|
||||
* @return int code 状态码(具体参见状态码说明)
|
||||
* @return string msg 提示信息
|
||||
*/
|
||||
public function login() {
|
||||
return json_encode(['code' => 1, 'msg' => '登录成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 用户注册API
|
||||
* @url https://wwww.baidu.com/reg
|
||||
* @method POST
|
||||
* @param string username 账号 空 必须
|
||||
* @param string password 密码 空 必须
|
||||
* @param string password2 重复密码 空 必须
|
||||
* @code 1 成功
|
||||
* @code 2 失败
|
||||
* @return int code 状态码(具体参见状态码说明)
|
||||
* @return string msg 提示信息
|
||||
*/
|
||||
public function reg() {
|
||||
return json_encode(['code' => 1, 'msg' => '注册成功']);
|
||||
}
|
||||
}
|
||||
33
vendor/itxq/api-doc-php/test/Api2.php
vendored
Normal file
33
vendor/itxq/api-doc-php/test/Api2.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: Api2.php
|
||||
* 概 要:
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/6 9:17
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @title 用户相关
|
||||
* Class Api
|
||||
*/
|
||||
class Api2
|
||||
{
|
||||
/**
|
||||
* @title 获取用户信息
|
||||
* @url https://wwww.baidu.com/getuserinfo
|
||||
* @method GET
|
||||
* @param int uid 用户ID 0 必须
|
||||
* @param string token 令牌 空 必须
|
||||
* @code 1 成功
|
||||
* @code 2 失败
|
||||
* @return int code 状态码(具体参见状态码说明)
|
||||
* @return string msg 提示信息
|
||||
*/
|
||||
public function getUserInfo() {
|
||||
return json_encode(['code' => 1, 'msg' => '获取信息成功', 'data' => ['uid' => 1, 'username' => 'admin']]);
|
||||
}
|
||||
}
|
||||
22
vendor/itxq/api-doc-php/test/index.php
vendored
Normal file
22
vendor/itxq/api-doc-php/test/index.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* ==================================================================
|
||||
* 文 件 名: index.php
|
||||
* 概 要: API文档 By Api-Doc-PHP
|
||||
* 作 者: IT小强
|
||||
* 创建时间: 2018/6/5 9:48
|
||||
* 修改时间:
|
||||
* copyright (c) 2016 - 2018 mail@xqitw.cn
|
||||
* ==================================================================
|
||||
*/
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
require_once __DIR__ . '/Api.php'; // 加载测试API类1
|
||||
require_once __DIR__ . '/Api2.php'; // 加载测试API类2
|
||||
$config = [
|
||||
'class' => ['Api', 'Api2'], // 要生成文档的类
|
||||
'filter_method' => ['__construct'], // 要过滤的方法名称
|
||||
];
|
||||
$api = new \itxq\apidoc\BootstrapApiDoc($config);
|
||||
$doc = $api->getHtml();
|
||||
exit($doc);
|
||||
|
||||
28
vendor/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php
vendored
Normal file
28
vendor/phpmailer/phpmailer/language/phpmailer.lang-sr_latn.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Serbian PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
* @author Александар Јевремовић <ajevremovic@gmail.com>
|
||||
* @author Miloš Milanović <mmilanovic016@gmail.com>
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'SMTP greška: autentifikacija nije uspela.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'SMTP greška: povezivanje sa SMTP serverom nije uspelo.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP greška: podaci nisu prihvaćeni.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'Sadržaj poruke je prazan.';
|
||||
$PHPMAILER_LANG['encoding'] = 'Nepoznato kodiranje: ';
|
||||
$PHPMAILER_LANG['execute'] = 'Nije moguće izvršiti naredbu: ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Nije moguće pristupiti datoteci: ';
|
||||
$PHPMAILER_LANG['file_open'] = 'Nije moguće otvoriti datoteku: ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'SMTP greška: slanje sa sledećih adresa nije uspelo: ';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'SMTP greška: slanje na sledeće adrese nije uspelo: ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Nije moguće pokrenuti mail funkciju.';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Poruka nije poslata. Neispravna adresa: ';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = ' majler nije podržan.';
|
||||
$PHPMAILER_LANG['provide_address'] = 'Definišite bar jednu adresu primaoca.';
|
||||
$PHPMAILER_LANG['signing'] = 'Greška prilikom prijave: ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'Povezivanje sa SMTP serverom nije uspelo.';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'Greška SMTP servera: ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'Nije moguće zadati niti resetovati promenljivu: ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Nedostaje proširenje: ';
|
||||
44
vendor/phpmailer/phpmailer/src/OAuthTokenProvider.php
vendored
Normal file
44
vendor/phpmailer/phpmailer/src/OAuthTokenProvider.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHPMailer - PHP email creation and transport class.
|
||||
* PHP Version 5.5.
|
||||
*
|
||||
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
*
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2020 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
namespace PHPMailer\PHPMailer;
|
||||
|
||||
/**
|
||||
* OAuthTokenProvider - OAuth2 token provider interface.
|
||||
* Provides base64 encoded OAuth2 auth strings for SMTP authentication.
|
||||
*
|
||||
* @see OAuth
|
||||
* @see SMTP::authenticate()
|
||||
*
|
||||
* @author Peter Scopes (pdscopes)
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
*/
|
||||
interface OAuthTokenProvider
|
||||
{
|
||||
/**
|
||||
* Generate a base64-encoded OAuth token ensuring that the access token has not expired.
|
||||
* The string to be base 64 encoded should be in the form:
|
||||
* "user=<user_email_address>\001auth=Bearer <access_token>\001\001"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOauth64();
|
||||
}
|
||||
16
vendor/psr/cache/CHANGELOG.md
vendored
Normal file
16
vendor/psr/cache/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file, in reverse chronological order by release.
|
||||
|
||||
## 1.0.1 - 2016-08-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Make spacing consistent in phpdoc annotations php-fig/cache#9 - chalasr
|
||||
- Fix grammar in phpdoc annotations php-fig/cache#10 - chalasr
|
||||
- Be more specific in docblocks that `getItems()` and `deleteItems()` take an array of strings (`string[]`) compared to just `array` php-fig/cache#8 - GrahamCampbell
|
||||
- For `expiresAt()` and `expiresAfter()` in CacheItemInterface fix docblock to specify null as a valid parameters as well as an implementation of DateTimeInterface php-fig/cache#7 - GrahamCampbell
|
||||
|
||||
## 1.0.0 - 2015-12-11
|
||||
|
||||
Initial stable release; reflects accepted PSR-6 specification
|
||||
19
vendor/psr/cache/LICENSE.txt
vendored
Normal file
19
vendor/psr/cache/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015 PHP Framework Interoperability Group
|
||||
|
||||
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.
|
||||
9
vendor/psr/cache/README.md
vendored
Normal file
9
vendor/psr/cache/README.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
PSR Cache
|
||||
=========
|
||||
|
||||
This repository holds all interfaces defined by
|
||||
[PSR-6](http://www.php-fig.org/psr/psr-6/).
|
||||
|
||||
Note that this is not a Cache implementation of its own. It is merely an
|
||||
interface that describes a Cache implementation. See the specification for more
|
||||
details.
|
||||
25
vendor/psr/cache/composer.json
vendored
Normal file
25
vendor/psr/cache/composer.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "psr/cache",
|
||||
"description": "Common interface for caching libraries",
|
||||
"keywords": ["psr", "psr-6", "cache"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Cache\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
vendor/psr/cache/src/CacheException.php
vendored
Normal file
10
vendor/psr/cache/src/CacheException.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Psr\Cache;
|
||||
|
||||
/**
|
||||
* Exception interface for all exceptions thrown by an Implementing Library.
|
||||
*/
|
||||
interface CacheException
|
||||
{
|
||||
}
|
||||
105
vendor/psr/cache/src/CacheItemInterface.php
vendored
Normal file
105
vendor/psr/cache/src/CacheItemInterface.php
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Psr\Cache;
|
||||
|
||||
/**
|
||||
* CacheItemInterface defines an interface for interacting with objects inside a cache.
|
||||
*
|
||||
* Each Item object MUST be associated with a specific key, which can be set
|
||||
* according to the implementing system and is typically passed by the
|
||||
* Cache\CacheItemPoolInterface object.
|
||||
*
|
||||
* The Cache\CacheItemInterface object encapsulates the storage and retrieval of
|
||||
* cache items. Each Cache\CacheItemInterface is generated by a
|
||||
* Cache\CacheItemPoolInterface object, which is responsible for any required
|
||||
* setup as well as associating the object with a unique Key.
|
||||
* Cache\CacheItemInterface objects MUST be able to store and retrieve any type
|
||||
* of PHP value defined in the Data section of the specification.
|
||||
*
|
||||
* Calling Libraries MUST NOT instantiate Item objects themselves. They may only
|
||||
* be requested from a Pool object via the getItem() method. Calling Libraries
|
||||
* SHOULD NOT assume that an Item created by one Implementing Library is
|
||||
* compatible with a Pool from another Implementing Library.
|
||||
*/
|
||||
interface CacheItemInterface
|
||||
{
|
||||
/**
|
||||
* Returns the key for the current cache item.
|
||||
*
|
||||
* The key is loaded by the Implementing Library, but should be available to
|
||||
* the higher level callers when needed.
|
||||
*
|
||||
* @return string
|
||||
* The key string for this cache item.
|
||||
*/
|
||||
public function getKey();
|
||||
|
||||
/**
|
||||
* Retrieves the value of the item from the cache associated with this object's key.
|
||||
*
|
||||
* The value returned must be identical to the value originally stored by set().
|
||||
*
|
||||
* If isHit() returns false, this method MUST return null. Note that null
|
||||
* is a legitimate cached value, so the isHit() method SHOULD be used to
|
||||
* differentiate between "null value was found" and "no value was found."
|
||||
*
|
||||
* @return mixed
|
||||
* The value corresponding to this cache item's key, or null if not found.
|
||||
*/
|
||||
public function get();
|
||||
|
||||
/**
|
||||
* Confirms if the cache item lookup resulted in a cache hit.
|
||||
*
|
||||
* Note: This method MUST NOT have a race condition between calling isHit()
|
||||
* and calling get().
|
||||
*
|
||||
* @return bool
|
||||
* True if the request resulted in a cache hit. False otherwise.
|
||||
*/
|
||||
public function isHit();
|
||||
|
||||
/**
|
||||
* Sets the value represented by this cache item.
|
||||
*
|
||||
* The $value argument may be any item that can be serialized by PHP,
|
||||
* although the method of serialization is left up to the Implementing
|
||||
* Library.
|
||||
*
|
||||
* @param mixed $value
|
||||
* The serializable value to be stored.
|
||||
*
|
||||
* @return static
|
||||
* The invoked object.
|
||||
*/
|
||||
public function set($value);
|
||||
|
||||
/**
|
||||
* Sets the expiration time for this cache item.
|
||||
*
|
||||
* @param \DateTimeInterface|null $expiration
|
||||
* The point in time after which the item MUST be considered expired.
|
||||
* If null is passed explicitly, a default value MAY be used. If none is set,
|
||||
* the value should be stored permanently or for as long as the
|
||||
* implementation allows.
|
||||
*
|
||||
* @return static
|
||||
* The called object.
|
||||
*/
|
||||
public function expiresAt($expiration);
|
||||
|
||||
/**
|
||||
* Sets the expiration time for this cache item.
|
||||
*
|
||||
* @param int|\DateInterval|null $time
|
||||
* The period of time from the present after which the item MUST be considered
|
||||
* expired. An integer parameter is understood to be the time in seconds until
|
||||
* expiration. If null is passed explicitly, a default value MAY be used.
|
||||
* If none is set, the value should be stored permanently or for as long as the
|
||||
* implementation allows.
|
||||
*
|
||||
* @return static
|
||||
* The called object.
|
||||
*/
|
||||
public function expiresAfter($time);
|
||||
}
|
||||
138
vendor/psr/cache/src/CacheItemPoolInterface.php
vendored
Normal file
138
vendor/psr/cache/src/CacheItemPoolInterface.php
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Psr\Cache;
|
||||
|
||||
/**
|
||||
* CacheItemPoolInterface generates CacheItemInterface objects.
|
||||
*
|
||||
* The primary purpose of Cache\CacheItemPoolInterface is to accept a key from
|
||||
* the Calling Library and return the associated Cache\CacheItemInterface object.
|
||||
* It is also the primary point of interaction with the entire cache collection.
|
||||
* All configuration and initialization of the Pool is left up to an
|
||||
* Implementing Library.
|
||||
*/
|
||||
interface CacheItemPoolInterface
|
||||
{
|
||||
/**
|
||||
* Returns a Cache Item representing the specified key.
|
||||
*
|
||||
* This method must always return a CacheItemInterface object, even in case of
|
||||
* a cache miss. It MUST NOT return null.
|
||||
*
|
||||
* @param string $key
|
||||
* The key for which to return the corresponding Cache Item.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
|
||||
* MUST be thrown.
|
||||
*
|
||||
* @return CacheItemInterface
|
||||
* The corresponding Cache Item.
|
||||
*/
|
||||
public function getItem($key);
|
||||
|
||||
/**
|
||||
* Returns a traversable set of cache items.
|
||||
*
|
||||
* @param string[] $keys
|
||||
* An indexed array of keys of items to retrieve.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
|
||||
* MUST be thrown.
|
||||
*
|
||||
* @return array|\Traversable
|
||||
* A traversable collection of Cache Items keyed by the cache keys of
|
||||
* each item. A Cache item will be returned for each key, even if that
|
||||
* key is not found. However, if no keys are specified then an empty
|
||||
* traversable MUST be returned instead.
|
||||
*/
|
||||
public function getItems(array $keys = array());
|
||||
|
||||
/**
|
||||
* Confirms if the cache contains specified cache item.
|
||||
*
|
||||
* Note: This method MAY avoid retrieving the cached value for performance reasons.
|
||||
* This could result in a race condition with CacheItemInterface::get(). To avoid
|
||||
* such situation use CacheItemInterface::isHit() instead.
|
||||
*
|
||||
* @param string $key
|
||||
* The key for which to check existence.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
|
||||
* MUST be thrown.
|
||||
*
|
||||
* @return bool
|
||||
* True if item exists in the cache, false otherwise.
|
||||
*/
|
||||
public function hasItem($key);
|
||||
|
||||
/**
|
||||
* Deletes all items in the pool.
|
||||
*
|
||||
* @return bool
|
||||
* True if the pool was successfully cleared. False if there was an error.
|
||||
*/
|
||||
public function clear();
|
||||
|
||||
/**
|
||||
* Removes the item from the pool.
|
||||
*
|
||||
* @param string $key
|
||||
* The key to delete.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
|
||||
* MUST be thrown.
|
||||
*
|
||||
* @return bool
|
||||
* True if the item was successfully removed. False if there was an error.
|
||||
*/
|
||||
public function deleteItem($key);
|
||||
|
||||
/**
|
||||
* Removes multiple items from the pool.
|
||||
*
|
||||
* @param string[] $keys
|
||||
* An array of keys that should be removed from the pool.
|
||||
|
||||
* @throws InvalidArgumentException
|
||||
* If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
|
||||
* MUST be thrown.
|
||||
*
|
||||
* @return bool
|
||||
* True if the items were successfully removed. False if there was an error.
|
||||
*/
|
||||
public function deleteItems(array $keys);
|
||||
|
||||
/**
|
||||
* Persists a cache item immediately.
|
||||
*
|
||||
* @param CacheItemInterface $item
|
||||
* The cache item to save.
|
||||
*
|
||||
* @return bool
|
||||
* True if the item was successfully persisted. False if there was an error.
|
||||
*/
|
||||
public function save(CacheItemInterface $item);
|
||||
|
||||
/**
|
||||
* Sets a cache item to be persisted later.
|
||||
*
|
||||
* @param CacheItemInterface $item
|
||||
* The cache item to save.
|
||||
*
|
||||
* @return bool
|
||||
* False if the item could not be queued or if a commit was attempted and failed. True otherwise.
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item);
|
||||
|
||||
/**
|
||||
* Persists any deferred cache items.
|
||||
*
|
||||
* @return bool
|
||||
* True if all not-yet-saved items were successfully saved or there were none. False otherwise.
|
||||
*/
|
||||
public function commit();
|
||||
}
|
||||
13
vendor/psr/cache/src/InvalidArgumentException.php
vendored
Normal file
13
vendor/psr/cache/src/InvalidArgumentException.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Psr\Cache;
|
||||
|
||||
/**
|
||||
* Exception interface for invalid cache arguments.
|
||||
*
|
||||
* Any time an invalid argument is passed into a method it must throw an
|
||||
* exception class which implements Psr\Cache\InvalidArgumentException.
|
||||
*/
|
||||
interface InvalidArgumentException extends CacheException
|
||||
{
|
||||
}
|
||||
3
vendor/symfony/class-loader/.gitignore
vendored
Normal file
3
vendor/symfony/class-loader/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
141
vendor/symfony/class-loader/ApcClassLoader.php
vendored
Normal file
141
vendor/symfony/class-loader/ApcClassLoader.php
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
class ApcClassLoader
|
||||
{
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* A class loader object that implements the findFile() method.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $decorated;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @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(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(array($this->decorated, $method), $args);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user