forked from admin/services_core
Update Database dan ALL yang di butuhkan
This commit is contained in:
+93
@@ -0,0 +1,93 @@
|
||||
# swagger-php
|
||||
|
||||
A PHP library that generates OpenAPI specification documents from PHP source code
|
||||
by scanning annotations (attributes and docblocks) and processing them into a
|
||||
complete spec.
|
||||
|
||||
## Language
|
||||
|
||||
### Core Concepts
|
||||
|
||||
**Annotation**:
|
||||
An OpenAPI specification element declared as a PHP 8+ attribute or legacy docblock comment on a class, method, or property.
|
||||
_Avoid_: Attribute (too narrow), decorator, metadata
|
||||
|
||||
**Analysis**:
|
||||
The aggregate result of scanning source code — contains all discovered annotations and structural definitions, before processing.
|
||||
_Avoid_: Result, scan output
|
||||
|
||||
**Context**:
|
||||
Nested metadata describing where an annotation was found in the source hierarchy (file, namespace, class, method, property).
|
||||
_Avoid_: Location, position
|
||||
|
||||
**Generator**:
|
||||
The orchestrator that coordinates scanning, processing, and output — it generates an OpenAPI spec from annotations, not code from a spec.
|
||||
_Avoid_: Builder, compiler
|
||||
|
||||
**Processor**:
|
||||
A single transformation step in an ordered pipeline that converts raw Analysis into a valid, complete OpenAPI specification.
|
||||
_Avoid_: Handler, middleware, transformer
|
||||
|
||||
### Annotation Lifecycle
|
||||
|
||||
**Unmerged**:
|
||||
An annotation that has been discovered but not yet incorporated into the target OpenAPI root object.
|
||||
_Avoid_: Pending, orphaned
|
||||
|
||||
**Merge**:
|
||||
Incorporating an annotation into its correct position within the OpenAPI object tree, guided by the nesting map.
|
||||
_Avoid_: Combine, attach
|
||||
|
||||
**Augment**:
|
||||
Filling in missing annotation fields with values inferred from code (e.g. deriving a schema type from a PHP type hint).
|
||||
_Avoid_: Enrich, hydrate
|
||||
|
||||
**Expand**:
|
||||
Resolving PHP inheritance (classes, interfaces, traits, enums) by copying parent annotations into child schemas.
|
||||
_Avoid_: Inherit, flatten
|
||||
|
||||
### Structural Concepts
|
||||
|
||||
**Nesting**:
|
||||
The declarative parent-child mapping (`$_nested`) that defines which annotation types can belong inside other annotation types — distinct from PHP class inheritance.
|
||||
_Avoid_: Hierarchy (ambiguous with class hierarchy)
|
||||
|
||||
**Component**:
|
||||
A reusable named definition stored in `#/components/` and referenced via `$ref` elsewhere in the spec.
|
||||
_Avoid_: Shared schema, template
|
||||
|
||||
**Ref**:
|
||||
A JSON Pointer (`$ref`) linking to another part of the spec, resolved by processors into `#/components/...` paths.
|
||||
_Avoid_: Link (means something else in OpenAPI), pointer
|
||||
|
||||
### Scanning
|
||||
|
||||
**Analyser**:
|
||||
Reflects on PHP source files to discover annotations and produce an Analysis.
|
||||
_Avoid_: Scanner (too narrow — TokenScanner is a sub-component), parser
|
||||
|
||||
**AnnotationFactory**:
|
||||
Creates annotation objects from discovered PHP attributes or docblock comments during analysis.
|
||||
_Avoid_: Builder, constructor
|
||||
|
||||
## Relationships
|
||||
|
||||
- A **Generator** uses an **Analyser** to produce an **Analysis**
|
||||
- An **Analysis** contains **Annotations**, each carrying a **Context**
|
||||
- **Processors** run sequentially on an **Analysis**, first **merging** unmerged annotations, then **expanding** inheritance, then **augmenting** missing fields
|
||||
- **Nesting** defines where an **Annotation** can be merged within the OpenAPI tree
|
||||
- A **Component** is an **Annotation** that has been merged into `#/components/` and is reachable by **Ref**
|
||||
|
||||
## Example dialogue
|
||||
|
||||
> **Dev:** "I added a `@OA\Schema` on a class but it's not appearing in the output."
|
||||
> **Domain expert:** "Is it still **unmerged**? Check that the **nesting** map allows it to be **merged** into Components, and that a **processor** hasn't filtered it out."
|
||||
|
||||
> **Dev:** "Why does the child class schema include the parent's properties?"
|
||||
> **Domain expert:** "That's **expansion** — the ExpandClasses **processor** copies parent **annotations** into the child during the pipeline."
|
||||
|
||||
## Flagged ambiguities
|
||||
|
||||
- "generate" — resolved: reserve for the full end-to-end pipeline (`Generator::generate()`). Use **analyse** for the discovery phase and **serialize** for producing JSON/YAML output.
|
||||
- "merge" — resolved: reserve for tree-placement (moving an annotation into its correct position in the OpenAPI object). Combining multiple annotations' fields into one (e.g. Properties into a Schema) is part of **augment**.
|
||||
- "nested" — resolved: use **nesting map** when referring to the `$_nested` declaration. Use **enclosing** when talking about the physical source code structure (file, class, method) that Context tracks.
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
## Contributing
|
||||
|
||||
Contributions of any kind are welcome.
|
||||
|
||||
Feel free to submit [Github Issues](https://github.com/zircote/swagger-php/issues)
|
||||
or [pull requests](https://github.com/zircote/swagger-php/pulls).
|
||||
|
||||
|
||||
## Quick Guide
|
||||
|
||||
The documentation site has [some details](https://zircote.github.io/swagger-php/guide/under-the-hood.html#documentation) about internals.
|
||||
|
||||
### How-To
|
||||
|
||||
* [Fork](https://help.github.com/articles/fork-a-repo/) the repo.
|
||||
* [Checkout](https://git-scm.com/docs/git-checkout) the branch you want to make changes on.
|
||||
* Typically, this will be `master`. Note that most of the time, `master` represents the next release of swagger-php, so Pull Requests that break backwards compatibility might be postponed.
|
||||
* Install dependencies: `composer install`.
|
||||
* Create a new branch, e.g. `feature-foo` or `bugfix-bar`.
|
||||
* Make changes.
|
||||
* If you are adding functionality or fixing a bug - add a test!
|
||||
|
||||
Prefer adding new test cases over modifying existing ones.
|
||||
* Update documentation: `composer docs:gen`.
|
||||
* Run static analysis using PHPStan/Psalm: `composer analyse`.
|
||||
* Check if tests pass: `composer test`.
|
||||
* Fix code style issues: `composer cs`.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation website is build from the [docs](docs/) folder with [vitepress](https://vitepress.vuejs.org).
|
||||
This process involves converting the existing markdown (`.md`) files into static HTML pages and publishing them.
|
||||
|
||||
Some reference content is based on the existing code, so changes to annotations, attributes and processors will require to re-generate those markdown files: `composer docs:gen`.
|
||||
|
||||
The actual published content is managed in the [gh-pages](https://github.com/zircote/swagger-php/tree/gh-pages) branch and driven by a [publish action](https://github.com/zircote/swagger-php/actions/workflows/gh-pages.yml).
|
||||
|
||||
|
||||
## Useful commands
|
||||
|
||||
### To run both unit tests and linting execute
|
||||
```shell
|
||||
composer test
|
||||
```
|
||||
|
||||
### To run static-analysis execute
|
||||
```shell
|
||||
composer analyse
|
||||
```
|
||||
|
||||
### Running unit tests only
|
||||
```shell
|
||||
./bin/phpunit
|
||||
```
|
||||
|
||||
### Regenerate reference markup docs
|
||||
```shell
|
||||
composer docs:gen
|
||||
```
|
||||
|
||||
### Running linting only
|
||||
```shell
|
||||
composer lint
|
||||
```
|
||||
|
||||
### To make `php-cs-fixer` fix linting errors
|
||||
```shell
|
||||
composer cs
|
||||
```
|
||||
|
||||
### Run dev server for local development of `gh-pages`
|
||||
```shell
|
||||
composer docs:dev
|
||||
```
|
||||
|
||||
|
||||
## Project's Standards
|
||||
|
||||
* [PSR-1: Basic Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
|
||||
* [PSR-2: Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
|
||||
* [PSR-4: Autoloading Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md)
|
||||
* [PSR-5: PHPDoc (draft)](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md)
|
||||
Vendored
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
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:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) 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
|
||||
|
||||
(d) 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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
swagger-php
|
||||
Copyright 2022 The swagger-php project
|
||||
Vendored
+152
@@ -0,0 +1,152 @@
|
||||
[](https://github.com/zircote/swagger-php/actions?query=workflow:build)
|
||||
[](https://packagist.org/packages/zircote/swagger-php)
|
||||
[](LICENSE)
|
||||
|
||||
# swagger-php
|
||||
|
||||
Generate interactive [OpenAPI](https://www.openapis.org) documentation for your RESTful API
|
||||
using [PHP attributes](https://www.php.net/manual/en/language.attributes.overview.php) (preferred) or
|
||||
[doctrine annotations](https://www.doctrine-project.org/projects/annotations.html) (requires additional
|
||||
`doctrine/annotations` library).
|
||||
|
||||
See the [documentation website](https://zircote.github.io/swagger-php/guide/using-attributes.html) for supported
|
||||
attributes and annotations.
|
||||
|
||||
**Annotations are deprecated and may be removed in a future release of swagger-php.**
|
||||
|
||||
## Features
|
||||
|
||||
- Compatible with the OpenAPI **3.0**, **3.1** and **3.2** specification.
|
||||
- Extracts information from code and existing phpdoc comments.
|
||||
- Can be used programmatically or via command-line tool.
|
||||
- [Documentation site](https://zircote.github.io/swagger-php/) with a getting started guide.
|
||||
- Error reporting (with hints, context).
|
||||
- All metadata is configured via PHP attributes.
|
||||
|
||||
## OpenAPI version support
|
||||
|
||||
`swagger-php` allows to generate specs either for **OpenAPI 3.0.0**, **OpenAPI 3.1.0** and **OpenAPI 3.2.0**.
|
||||
By default, the spec will be in version `3.0.0`. The command line option `--version` may be used to change to
|
||||
any other supported version.
|
||||
|
||||
Programmatically, the method `Generator::setVersion()` can be used to change the version.
|
||||
|
||||
## Requirements
|
||||
|
||||
`swagger-php` requires at least **PHP 8.2**.
|
||||
|
||||
## Installation (with [Composer](https://getcomposer.org))
|
||||
|
||||
```shell
|
||||
composer require zircote/swagger-php
|
||||
```
|
||||
|
||||
For cli usage from anywhere, install swagger-php globally and make sure to place the `~/.composer/vendor/bin` directory
|
||||
in your PATH so the `openapi` executable can be located by your system.
|
||||
|
||||
```shell
|
||||
composer global require zircote/swagger-php
|
||||
```
|
||||
|
||||
### doctrine/annotations
|
||||
|
||||
As of version `4.8` the [doctrine annotations](https://www.doctrine-project.org/projects/annotations.html) library **is
|
||||
optional** and **no longer installed by default**.
|
||||
|
||||
If your code uses doctrine annotations you will need to install that library manually:
|
||||
|
||||
```shell
|
||||
composer require doctrine/annotations
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Use OpenAPI attributes to add metadata to your classes, methods and other structural PHP elements.
|
||||
|
||||
```php
|
||||
|
||||
use OpenApi\Attributes as OAT;
|
||||
|
||||
#[OAT\Info(title: 'My First API', version: '0.1')]
|
||||
class MyApi
|
||||
{
|
||||
#[OAT\Get(path: '/api/resource.json')]
|
||||
#[OAT\Response(response: '200', description: 'An example resource')]
|
||||
public function getResource()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Visit the [Documentation website](https://zircote.github.io/swagger-php/) for
|
||||
the [Getting started guide](https://zircote.github.io/swagger-php/guide) or look at
|
||||
the [examples directory](docs/examples) for more examples.
|
||||
|
||||
### Usage from PHP
|
||||
|
||||
Generate always-up-to-date documentation.
|
||||
|
||||
```php
|
||||
<?php
|
||||
require("vendor/autoload.php");
|
||||
$openapi = (new \OpenApi\Generator())->generate(['/path/to/project']);
|
||||
header('Content-Type: application/x-yaml');
|
||||
echo $openapi->toYaml();
|
||||
```
|
||||
|
||||
Documentation of how to use the `Generator` class can be found in
|
||||
the [Generator reference](https://zircote.github.io/swagger-php/reference/generator).
|
||||
|
||||
### Usage from the Command Line Interface
|
||||
|
||||
The `openapi` command line interface can be used to generate the documentation to a static yaml/json file.
|
||||
|
||||
```shell
|
||||
./vendor/bin/openapi --help
|
||||
```
|
||||
|
||||
## Automatic type resolution
|
||||
|
||||
As of version 6, resolving of types is done using the `TypeInfoTypeResolver` class. It uses the `symfony/type-info`
|
||||
library under the hood which allows handling of complext types.
|
||||
|
||||
With this change, `swagger-php` supports all available native type-hints and also complext generic type-hints via phpdoc
|
||||
blocks.
|
||||
This simplifies the definition of schemas.
|
||||
|
||||
For example, the following two examples are now equivalent:
|
||||
|
||||
```php
|
||||
class MyClass
|
||||
{
|
||||
#[OAT\Property(items: new OAT\Items(oneOf: [
|
||||
new OAT\Schema(type: SchemaOne::class),
|
||||
new OAT\Schema(type: SchemaTwo::class),
|
||||
]))]
|
||||
public array $values;
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
class MyClass
|
||||
{
|
||||
/**
|
||||
* @var list<SchemaOne|SchemaTwo>
|
||||
*/
|
||||
public array $values;
|
||||
}
|
||||
```
|
||||
|
||||
If this is not desired, the `LegacyTypeResolver` can be used to preserve the old behaviour of version 5.
|
||||
The `LegacyTypeResolver` is deprecated and will be removed in a future release.
|
||||
|
||||
## [Contributing](CONTRIBUTING.md)
|
||||
|
||||
## More on OpenApi & Swagger
|
||||
|
||||
- https://swagger.io
|
||||
- https://www.openapis.org
|
||||
- [OpenApi Documentation](https://swagger.io/docs/)
|
||||
- [OpenApi Specification](http://swagger.io/specification/)
|
||||
- [Related projects](docs/related-projects.md)
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use OpenApi\Console\GenerateCommand;
|
||||
use OpenApi\Generator;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Logger\ConsoleLogger;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
if (class_exists(Generator::class) === false) {
|
||||
if (file_exists(__DIR__.'/../vendor/autoload.php')) { // cloned / dev environment?
|
||||
require_once(__DIR__.'/../vendor/autoload.php');
|
||||
} else {
|
||||
require_once(realpath(__DIR__.'/../../../').'/autoload.php');
|
||||
}
|
||||
}
|
||||
|
||||
$input = new class extends ArgvInput
|
||||
{
|
||||
public function hasParameterOption(array|string $values, bool $onlyParams = false): bool
|
||||
{
|
||||
// Skip the built-in version option check
|
||||
// thus the command can use it for its own purpose
|
||||
if (['--version', '-V'] === $values) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::hasParameterOption($values, $onlyParams);
|
||||
}
|
||||
};
|
||||
$output = new ConsoleOutput();
|
||||
$logger = new ConsoleLogger($output);
|
||||
$app = new Application();
|
||||
|
||||
// Remove Symfony's built-in options that conflict with our command options:
|
||||
// --version (-V): conflicts with our --version (VALUE_REQUIRED for OpenAPI spec version)
|
||||
// --no-interaction (-n): conflicts with our --pattern (-n)
|
||||
$definition = $app->getDefinition();
|
||||
$options = $definition->getOptions();
|
||||
unset($options['version'], $options['no-interaction']);
|
||||
$definition->setOptions($options);
|
||||
|
||||
$app->addCommand(new GenerateCommand($logger));
|
||||
$app->setDefaultCommand('openapi', true);
|
||||
$app->run($input, $output);
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"name": "zircote/swagger-php",
|
||||
"type": "library",
|
||||
"license": "Apache-2.0",
|
||||
"bin": [
|
||||
"bin/openapi"
|
||||
],
|
||||
"description": "Generate interactive documentation for your RESTful API using PHP attributes (preferred) or PHPDoc annotations",
|
||||
"keywords": [
|
||||
"json",
|
||||
"rest",
|
||||
"api",
|
||||
"service discovery"
|
||||
],
|
||||
"homepage": "https://github.com/zircote/swagger-php",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Robert Allen",
|
||||
"email": "zircote@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Bob Fanger",
|
||||
"email": "bfanger@gmail.com",
|
||||
"homepage": "https://bfanger.nl"
|
||||
},
|
||||
{
|
||||
"name": "Martin Rademacher",
|
||||
"email": "mano@radebatz.net",
|
||||
"homepage": "https://radebatz.net"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"bin-dir": "bin",
|
||||
"optimize-autoloader": true,
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.x-dev"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"nikic/php-parser": "^4.19 || ^5.0",
|
||||
"phpstan/phpdoc-parser": "^2.0",
|
||||
"psr/log": "^1.1 || ^2.0 || ^3.0",
|
||||
"radebatz/type-info-extras": "^1.0.2",
|
||||
"symfony/console": "^7.4 || ^8.0",
|
||||
"symfony/deprecation-contracts": "^2 || ^3",
|
||||
"symfony/finder": "^5.0 || ^6.0 || ^7.0 || ^8.0",
|
||||
"symfony/yaml": "^5.4 || ^6.0 || ^7.0 || ^8.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OpenApi\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"exclude-from-classmap": [
|
||||
"/tests/Fixtures"
|
||||
],
|
||||
"psr-4": {
|
||||
"OpenApi\\Tools\\": "tools/src/",
|
||||
"OpenApi\\Tests\\": "tests/",
|
||||
"AnotherNamespace\\": "tests/Fixtures/AnotherNamespace"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/package-versions-deprecated": "^1.11",
|
||||
"doctrine/annotations": "^2.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.62.0",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpunit/phpunit": "^11.5 || >=12.5.22",
|
||||
"rector/rector": "^2.3.1"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/process": ">=6, <6.4.14"
|
||||
},
|
||||
"scripts-descriptions": {
|
||||
"cs": "Fix all codestyle issues",
|
||||
"rector": "Automatic refactoring",
|
||||
"lint": "Test codestyle",
|
||||
"test": "Run all PHP, codestyle and rector tests",
|
||||
"analyse": "Run static analysis (phpstan)",
|
||||
"spectral-examples": "Run spectral lint over all .yaml files in the docs/examples folder",
|
||||
"spectral-scratch": "Run spectral lint over all .yaml files in the tests/Fixtures/Scratch folder",
|
||||
"spectral": "Run all spectral tests",
|
||||
"redocly-examples": "Run redocly lint over all .yaml files in the docs/examples folder",
|
||||
"redocly-scratch": "Run redocly lint over all .yaml files in the tests/Fixtures/Scratch folder",
|
||||
"redocly": "Run all redocly tests",
|
||||
"docs:gen": "Rebuild reference documentation",
|
||||
"docs:dev": "Run dev server for local development of gh-pages",
|
||||
"docs:build": "Re-build static gh-pages"
|
||||
},
|
||||
"scripts": {
|
||||
"cs": "export XDEBUG_MODE=off && php-cs-fixer fix --allow-risky=yes",
|
||||
"rector": "rector process src tests docs/examples",
|
||||
"lint": [
|
||||
"@cs --dry-run",
|
||||
"@rector --dry-run"
|
||||
],
|
||||
"test": [
|
||||
"export XDEBUG_MODE=off && phpunit --display-all-issues",
|
||||
"@lint"
|
||||
],
|
||||
"analyse": [
|
||||
"export XDEBUG_MODE=off && phpstan analyse --memory-limit=3G"
|
||||
],
|
||||
"spectral-examples": "for ff in `find docs/examples -name '*.yaml'`; do npm run spectral lint $ff; done",
|
||||
"spectral-scratch": "for ff in `find tests/Fixtures/Scratch -name '*.yaml'`; do npm run spectral lint $ff; done",
|
||||
"spectral": [
|
||||
"@spectral-examples",
|
||||
"@spectral-scratch"
|
||||
],
|
||||
"redocly-examples": "for ff in `find docs/examples -name '*.yaml'`; do npm run redocly lint $ff; done",
|
||||
"redocly-scratch": "for ff in `find tests/Fixtures/Scratch -name '*.yaml'`; do npm run redocly lint $ff; done",
|
||||
"redocly": [
|
||||
"@redocly-examples",
|
||||
"@redocly-scratch"
|
||||
],
|
||||
"docs:gen": [
|
||||
"@php tools/refgen.php",
|
||||
"@php tools/procgen.php",
|
||||
"@php tools/examplegen.php"
|
||||
],
|
||||
"docs:dev": "cd docs && npm run dev",
|
||||
"docs:build": [
|
||||
"@docs:gen",
|
||||
"cd docs && npm run build"
|
||||
]
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "swagger-php-tools",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"spectral": "spectral",
|
||||
"redocly": "redocly"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@redocly/cli": "^2.5.1",
|
||||
"@stoplight/spectral-cli": "^6.15.0"
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector;
|
||||
use Rector\CodeQuality\Rector\For_\ForRepeatedCountToOwnVariableRector;
|
||||
use Rector\CodeQuality\Rector\If_\CombineIfRector;
|
||||
use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector;
|
||||
use Rector\CodeQuality\Rector\If_\ShortenElseIfRector;
|
||||
use Rector\CodingStyle\Rector\ClassMethod\NewlineBeforeNewAssignSetRector;
|
||||
use Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector;
|
||||
use Rector\CodingStyle\Rector\Encapsed\WrapEncapsedVariableInCurlyBracesRector;
|
||||
use Rector\CodingStyle\Rector\If_\NullableCompareToNullRector;
|
||||
use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector;
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector;
|
||||
use Rector\DeadCode\Rector\If_\RemoveDeadInstanceOfRector;
|
||||
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
|
||||
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
|
||||
use Rector\Php81\Rector\Array_\ArrayToFirstClassCallableRector;
|
||||
use Rector\Php81\Rector\Property\ReadOnlyPropertyRector;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\ParamTypeByMethodCallTypeRector;
|
||||
use Rector\ValueObject\PhpVersion;
|
||||
|
||||
return RectorConfig::configure()
|
||||
->withSkipPath(__DIR__ . '/tests/Fixtures')
|
||||
->withSkip([
|
||||
NewlineBeforeNewAssignSetRector::class,
|
||||
CombineIfRector::class,
|
||||
ExplicitBoolCompareRector::class,
|
||||
ForRepeatedCountToOwnVariableRector::class,
|
||||
ReadOnlyPropertyRector::class,
|
||||
RemoveAlwaysTrueIfConditionRector::class => [
|
||||
__DIR__ . '/src/Processors/ExpandEnums.php',
|
||||
],
|
||||
RemoveDeadInstanceOfRector::class => [
|
||||
__DIR__ . '/src/Processors/ExpandEnums.php',
|
||||
],
|
||||
ShortenElseIfRector::class,
|
||||
NewlineAfterStatementRector::class,
|
||||
NullableCompareToNullRector::class,
|
||||
StringClassNameToClassConstantRector::class => [
|
||||
__DIR__ . '/src/Analysers/DocBlockParser.php',
|
||||
__DIR__ . '/src/Analysers/TypeResolverTrait.php',
|
||||
__DIR__ . '/tests/Analysers/ComposerAutoloaderScannerTest.php',
|
||||
__DIR__ . '/tests/Analysers/TokenScannerTest.php',
|
||||
__DIR__ . '/tests/AnalysisTest.php',
|
||||
__DIR__ . '/tests/ContextTest.php',
|
||||
],
|
||||
WrapEncapsedVariableInCurlyBracesRector::class => [
|
||||
__DIR__ . '/src/Type/LegacyTypeResolver.php',
|
||||
],
|
||||
EncapsedStringsToSprintfRector::class,
|
||||
ParamTypeByMethodCallTypeRector::class => [
|
||||
__DIR__ . '/src/Serializer.php',
|
||||
],
|
||||
ClassPropertyAssignToConstructorPromotionRector::class,
|
||||
CompleteDynamicPropertiesRector::class => [
|
||||
__DIR__ . '/src/Annotations/AbstractAnnotation.php',
|
||||
],
|
||||
ArrayToFirstClassCallableRector::class => [
|
||||
__DIR__ . '/tests/Analysers/ComposerAutoloaderScannerTest.php',
|
||||
],
|
||||
])
|
||||
->withPreparedSets(
|
||||
deadCode: true,
|
||||
codeQuality: true,
|
||||
codingStyle: true,
|
||||
typeDeclarations: true,
|
||||
phpunitCodeQuality: true,
|
||||
)
|
||||
->withAttributesSets(phpunit: true)
|
||||
->withPhpVersion(PhpVersion::PHP_82)
|
||||
->withPhpSets();
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Context;
|
||||
use OpenApi\GeneratorAwareInterface;
|
||||
|
||||
interface AnalyserInterface extends GeneratorAwareInterface
|
||||
{
|
||||
public function fromFile(string $filename, Context $context): Analysis;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Context;
|
||||
use OpenApi\GeneratorAwareInterface;
|
||||
|
||||
interface AnnotationFactoryInterface extends GeneratorAwareInterface
|
||||
{
|
||||
/**
|
||||
* Checks if this factory is supported by the current runtime.
|
||||
*/
|
||||
public function isSupported(): bool;
|
||||
|
||||
/**
|
||||
* @return list<OA\AbstractAnnotation> top level annotations
|
||||
*/
|
||||
public function build(\Reflector $reflector, Context $context): array;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Attributes as OAT;
|
||||
use OpenApi\Context;
|
||||
use OpenApi\Generator;
|
||||
use OpenApi\GeneratorAwareTrait;
|
||||
|
||||
class AttributeAnnotationFactory implements AnnotationFactoryInterface
|
||||
{
|
||||
use GeneratorAwareTrait;
|
||||
|
||||
protected bool $ignoreOtherAttributes = false;
|
||||
|
||||
public function __construct(bool $ignoreOtherAttributes = false)
|
||||
{
|
||||
$this->ignoreOtherAttributes = $ignoreOtherAttributes;
|
||||
}
|
||||
|
||||
public function isSupported(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function build(\Reflector $reflector, Context $context): array
|
||||
{
|
||||
if (!$this->isSupported()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($reflector instanceof \ReflectionProperty && $reflector->isPromoted()) {
|
||||
// handled via __construct() parameter
|
||||
return [];
|
||||
}
|
||||
|
||||
// no proper way to inject
|
||||
Generator::$context = $context;
|
||||
|
||||
/** @var list<OA\AbstractAnnotation> $annotations */
|
||||
$annotations = [];
|
||||
try {
|
||||
$attributeName = $this->ignoreOtherAttributes
|
||||
? [OA\AbstractAnnotation::class, \ReflectionAttribute::IS_INSTANCEOF]
|
||||
: [];
|
||||
|
||||
foreach ($reflector->getAttributes(...$attributeName) as $attribute) {
|
||||
if (class_exists($attribute->getName())) {
|
||||
$instance = $attribute->newInstance();
|
||||
if ($instance instanceof OA\AbstractAnnotation) {
|
||||
$annotations[] = $instance;
|
||||
} else {
|
||||
if (false === $context->is('other')) {
|
||||
$context->other = [];
|
||||
}
|
||||
$context->other[] = $instance;
|
||||
}
|
||||
} else {
|
||||
$context->logger->debug(sprintf('Could not instantiate attribute "%s"; class not found.', $attribute->getName()));
|
||||
}
|
||||
}
|
||||
|
||||
if ($reflector instanceof \ReflectionMethod) {
|
||||
// also look at parameter attributes
|
||||
foreach ($reflector->getParameters() as $rp) {
|
||||
foreach ([OA\Property::class, OAT\Parameter::class, OA\RequestBody::class] as $attributeName) {
|
||||
foreach ($rp->getAttributes($attributeName, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
|
||||
/** @var OA\Property|OAT\Parameter|OA\RequestBody $instance */
|
||||
$instance = $attribute->newInstance();
|
||||
$instance->_context = new Context([
|
||||
'nested' => false,
|
||||
'property' => $rp->getName(),
|
||||
'reflector' => $rp,
|
||||
], $context);
|
||||
|
||||
if ($instance instanceof OA\Property) {
|
||||
if ($rp->isPromoted()) {
|
||||
// ensure each property has its own context
|
||||
$instance->_context = new Context([
|
||||
'generated' => true,
|
||||
'annotations' => [$instance],
|
||||
'property' => $rp->getName(),
|
||||
'reflector' => $rp,
|
||||
], $context);
|
||||
|
||||
// promoted parameter - docblock is available via class/property
|
||||
if ($comment = $rp->getDeclaringClass()->getProperty($rp->getName())->getDocComment()) {
|
||||
$instance->_context->comment = $comment;
|
||||
}
|
||||
} else {
|
||||
$instance->_context->property = $rp->getName();
|
||||
}
|
||||
} elseif ($instance instanceof OAT\Parameter) {
|
||||
if (method_exists($rp, 'getDocComment')) {
|
||||
if ($comment = $rp->getDocComment()) {
|
||||
$instance->_context->comment = $comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$annotations[] = $instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Generator::$context = null;
|
||||
}
|
||||
|
||||
// merge backwards into parents...
|
||||
$isParent = static function (OA\AbstractAnnotation $annotation, OA\AbstractAnnotation $possibleParent): bool {
|
||||
// regular annotation hierarchy
|
||||
$explicitParent = null !== $possibleParent->matchNested($annotation) && !$annotation instanceof OA\Attachable;
|
||||
$isParentAllowed = false;
|
||||
// support Attachable subclasses
|
||||
if ($isAttachable = $annotation instanceof OA\Attachable) {
|
||||
if (!$isParentAllowed = (null === $annotation->allowedParents())) {
|
||||
// check for allowed parents
|
||||
foreach ($annotation->allowedParents() as $allowedParent) {
|
||||
if ($possibleParent instanceof $allowedParent) {
|
||||
$isParentAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attachables can always be nested (unless explicitly restricted)
|
||||
return ($isAttachable && $isParentAllowed)
|
||||
|| ($annotation->getRoot() !== $possibleParent->getRoot() && $explicitParent);
|
||||
};
|
||||
|
||||
$annotationsWithoutParent = [];
|
||||
foreach ($annotations as $index => $annotation) {
|
||||
$mergedIntoParent = false;
|
||||
|
||||
for ($ii = 0; $ii < count($annotations); ++$ii) {
|
||||
if ($ii === $index) {
|
||||
continue;
|
||||
}
|
||||
$possibleParent = $annotations[$ii];
|
||||
if ($isParent($annotation, $possibleParent)) {
|
||||
$mergedIntoParent = true; //
|
||||
$possibleParent->merge([$annotation]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$mergedIntoParent) {
|
||||
$annotationsWithoutParent[] = $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
return $annotationsWithoutParent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
|
||||
/**
|
||||
* Scans for classes/interfaces/traits.
|
||||
*
|
||||
* Relies on a <code>composer --optimized</code> run in order to utilize
|
||||
* the generated class map.
|
||||
*/
|
||||
class ComposerAutoloaderScanner
|
||||
{
|
||||
/**
|
||||
* Collect all classes/interfaces/traits known by composer.
|
||||
*
|
||||
* @param list<string> $namespaces
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
public function scan(array $namespaces): array
|
||||
{
|
||||
$units = [];
|
||||
if ($autoloader = static::getComposerAutoloader()) {
|
||||
foreach (array_keys($autoloader->getClassMap()) as $unit) {
|
||||
foreach ($namespaces as $namespace) {
|
||||
if (str_starts_with($unit, $namespace)) {
|
||||
$units[] = $unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $units;
|
||||
}
|
||||
|
||||
public static function getComposerAutoloader(): ?ClassLoader
|
||||
{
|
||||
foreach (spl_autoload_functions() as $fkt) {
|
||||
if (is_array($fkt) && $fkt[0] instanceof ClassLoader) {
|
||||
return $fkt[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Context;
|
||||
use OpenApi\Generator;
|
||||
use OpenApi\GeneratorAwareTrait;
|
||||
|
||||
class DocBlockAnnotationFactory implements AnnotationFactoryInterface
|
||||
{
|
||||
use GeneratorAwareTrait;
|
||||
|
||||
protected ?DocBlockParser $docBlockParser = null;
|
||||
|
||||
public function __construct(?DocBlockParser $docBlockParser = null)
|
||||
{
|
||||
$this->docBlockParser = $docBlockParser ?: new DocBlockParser();
|
||||
}
|
||||
|
||||
public function isSupported(): bool
|
||||
{
|
||||
return DocBlockParser::isEnabled();
|
||||
}
|
||||
|
||||
public function setGenerator(Generator $generator): static
|
||||
{
|
||||
$this->generator = $generator;
|
||||
|
||||
$this->docBlockParser->setAliases($generator->getAliases());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function build(\Reflector $reflector, Context $context): array
|
||||
{
|
||||
$aliases = $this->generator ? $this->generator->getAliases() : [];
|
||||
|
||||
if (method_exists($reflector, 'getShortName') && method_exists($reflector, 'getName')) {
|
||||
$aliases[strtolower((string) $reflector->getShortName())] = $reflector->getName();
|
||||
}
|
||||
|
||||
if ($context->with('scanned')) {
|
||||
$details = $context->scanned;
|
||||
foreach ($details['uses'] as $alias => $name) {
|
||||
$aliasKey = strtolower((string) $alias);
|
||||
if ($name != $alias && !array_key_exists($aliasKey, $aliases)) {
|
||||
// real aliases only
|
||||
$aliases[strtolower((string) $alias)] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->docBlockParser->setAliases($aliases);
|
||||
|
||||
if (method_exists($reflector, 'getDocComment') && ($comment = $reflector->getDocComment())) {
|
||||
$annotations = [];
|
||||
foreach ($this->docBlockParser->fromComment($comment, $context) as $instance) {
|
||||
if ($instance instanceof OA\AbstractAnnotation) {
|
||||
$annotations[] = $instance;
|
||||
} else {
|
||||
if ($context->is('other') === false) {
|
||||
$context->other = [];
|
||||
}
|
||||
$context->other[] = $instance;
|
||||
}
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use Doctrine\Common\Annotations\DocParser;
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Context;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Extract swagger-php annotations from a [PHPDoc](http://en.wikipedia.org/wiki/PHPDoc) using Doctrine's DocParser.
|
||||
*/
|
||||
class DocBlockParser
|
||||
{
|
||||
protected DocParser $docParser;
|
||||
|
||||
/**
|
||||
* @param array<string, class-string> $aliases
|
||||
*/
|
||||
public function __construct(array $aliases = [])
|
||||
{
|
||||
if (DocBlockParser::isEnabled()) {
|
||||
$docParser = new DocParser();
|
||||
$docParser->setIgnoreNotImportedAnnotations(true);
|
||||
$docParser->setImports($aliases);
|
||||
$this->docParser = $docParser;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we can process annotations.
|
||||
*/
|
||||
public static function isEnabled(): bool
|
||||
{
|
||||
return class_exists('Doctrine\\Common\\Annotations\\DocParser');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, class-string> $aliases
|
||||
*/
|
||||
public function setAliases(array $aliases): void
|
||||
{
|
||||
$this->docParser->setImports($aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use doctrine to parse the comment block and return the detected annotations.
|
||||
*
|
||||
* @param string $comment a T_DOC_COMMENT
|
||||
*
|
||||
* @return list<OA\AbstractAnnotation|object>
|
||||
*/
|
||||
public function fromComment(string $comment, Context $context): array
|
||||
{
|
||||
$context->comment = $comment;
|
||||
|
||||
try {
|
||||
Generator::$context = $context;
|
||||
if ($context->is('annotations') === false) {
|
||||
$context->annotations = [];
|
||||
}
|
||||
|
||||
return $this->docParser->parse($comment, $context->getDebugLocation());
|
||||
} catch (\Exception $exception) {
|
||||
if (preg_match('/^(.+) at position ([0-9]+) in ' . preg_quote((string) $context, '/') . '\.$/', $exception->getMessage(), $matches)) {
|
||||
$errorMessage = $matches[1];
|
||||
$errorPos = (int) $matches[2];
|
||||
$atPos = strpos($comment, '@');
|
||||
$context->line -= substr_count($comment, "\n", $atPos + $errorPos) + 1;
|
||||
$lines = explode("\n", substr($comment, $atPos, $errorPos));
|
||||
$context->character = strlen(array_pop($lines)) + 1; // position starts at 0 character starts at 1
|
||||
$context->logger->error($errorMessage . ' in ' . $context, ['exception' => $exception]);
|
||||
} else {
|
||||
$context->logger->error(
|
||||
$exception->getMessage() . ($context->filename ? ('; file=' . $context->filename) : ''),
|
||||
['exception' => $exception]
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
} finally {
|
||||
Generator::$context = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Context;
|
||||
use OpenApi\Generator;
|
||||
use OpenApi\GeneratorAwareTrait;
|
||||
use OpenApi\OpenApiException;
|
||||
|
||||
/**
|
||||
* OpenApi analyser using reflection.
|
||||
*
|
||||
* Can read either PHP <code>DocBlock</code>s or <code>Attribute</code>s.
|
||||
*
|
||||
* Due to the nature of reflection, this requires all related classes to be auto-loadable.
|
||||
*/
|
||||
class ReflectionAnalyser implements AnalyserInterface
|
||||
{
|
||||
use GeneratorAwareTrait;
|
||||
|
||||
/** @var list<AnnotationFactoryInterface> */
|
||||
protected array $annotationFactories = [];
|
||||
|
||||
/**
|
||||
* @param list<AnnotationFactoryInterface> $annotationFactories
|
||||
*/
|
||||
public function __construct(array $annotationFactories = [])
|
||||
{
|
||||
foreach ($annotationFactories as $annotationFactory) {
|
||||
if ($annotationFactory->isSupported()) {
|
||||
$this->annotationFactories[] = $annotationFactory;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->annotationFactories) {
|
||||
throw new OpenApiException('No suitable annotation factory found. At least one of "Doctrine Annotations" or PHP 8.1 are required');
|
||||
}
|
||||
}
|
||||
|
||||
public function setGenerator(Generator $generator): static
|
||||
{
|
||||
$this->generator = $generator;
|
||||
|
||||
foreach ($this->annotationFactories as $annotationFactory) {
|
||||
$annotationFactory->setGenerator($generator);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fromFile(string $filename, Context $context): Analysis
|
||||
{
|
||||
$scanner = new TokenScanner();
|
||||
$fileDetails = $scanner->scanFile($filename);
|
||||
|
||||
$analysis = new Analysis([], $context);
|
||||
foreach ($fileDetails as $fqdn => $details) {
|
||||
$this->analyzeFqdn($fqdn, $analysis, $details);
|
||||
}
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
public function fromFqdn(string $fqdn, Analysis $analysis): Analysis
|
||||
{
|
||||
$fqdn = ltrim($fqdn, '\\');
|
||||
|
||||
$rc = new \ReflectionClass($fqdn);
|
||||
if (!$filename = $rc->getFileName()) {
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
$scanner = new TokenScanner();
|
||||
$fileDetails = $scanner->scanFile($filename);
|
||||
|
||||
$this->analyzeFqdn($fqdn, $analysis, $fileDetails[$fqdn]);
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
protected function analyzeFqdn(string $fqdn, Analysis $analysis, array $details): Analysis
|
||||
{
|
||||
if (!class_exists($fqdn) && !interface_exists($fqdn) && !trait_exists($fqdn) && (!function_exists('enum_exists') || !enum_exists($fqdn))) {
|
||||
$analysis->context->logger->warning('Skipping unknown ' . $fqdn);
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
$rc = new \ReflectionClass($fqdn);
|
||||
$contextType = $rc->isInterface()
|
||||
? 'interface'
|
||||
: ($rc->isTrait() ? 'trait' : ($rc->isEnum() ? 'enum' : 'class'));
|
||||
$context = new Context([
|
||||
$contextType => $rc->getShortName(),
|
||||
'namespace' => $rc->getNamespaceName() ?: null,
|
||||
'uses' => $details['uses'],
|
||||
'comment' => $rc->getDocComment() ?: null,
|
||||
'filename' => $rc->getFileName() ?: null,
|
||||
'line' => $rc->getStartLine(),
|
||||
'annotations' => [],
|
||||
'scanned' => $details,
|
||||
'reflector' => $rc,
|
||||
], $analysis->context);
|
||||
|
||||
$definition = [
|
||||
$contextType => $rc->getShortName(),
|
||||
'extends' => null,
|
||||
'implements' => [],
|
||||
'traits' => [],
|
||||
'properties' => [],
|
||||
'methods' => [],
|
||||
'context' => $context,
|
||||
];
|
||||
$normaliseClass = static fn (string $name): string => '\\' . ltrim($name, '\\');
|
||||
if ($parentClass = $rc->getParentClass()) {
|
||||
$definition['extends'] = $normaliseClass($parentClass->getName());
|
||||
}
|
||||
$definition[$contextType === 'class' ? 'implements' : 'extends'] = array_map($normaliseClass, $details['interfaces']);
|
||||
$definition['traits'] = array_map($normaliseClass, $details['traits']);
|
||||
|
||||
foreach ($this->annotationFactories as $annotationFactory) {
|
||||
$analysis->addAnnotations($annotationFactory->build($rc, $context), $context);
|
||||
}
|
||||
|
||||
foreach ($rc->getMethods() as $method) {
|
||||
if (in_array($method->name, $details['methods'])) {
|
||||
$definition['methods'][$method->getName()] = $ctx = new Context([
|
||||
'method' => $method->getName(),
|
||||
'comment' => $method->getDocComment() ?: null,
|
||||
'filename' => $method->getFileName() ?: null,
|
||||
'line' => $method->getStartLine(),
|
||||
'annotations' => [],
|
||||
'reflector' => $method,
|
||||
], $context);
|
||||
foreach ($this->annotationFactories as $annotationFactory) {
|
||||
$annotations = $annotationFactory->build($method, $ctx);
|
||||
$analysis->addAnnotations($annotations, $ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rc->getProperties() as $property) {
|
||||
if (in_array($property->name, $details['properties'])) {
|
||||
$definition['properties'][$property->getName()] = $ctx = new Context([
|
||||
'property' => $property->getName(),
|
||||
'comment' => $property->getDocComment() ?: null,
|
||||
'annotations' => [],
|
||||
'reflector' => $property,
|
||||
], $context);
|
||||
if ($property->isStatic()) {
|
||||
$ctx->static = true;
|
||||
}
|
||||
foreach ($this->annotationFactories as $annotationFactory) {
|
||||
$analysis->addAnnotations($annotationFactory->build($property, $ctx), $ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rc->getReflectionConstants() as $constant) {
|
||||
foreach ($this->annotationFactories as $annotationFactory) {
|
||||
$definition['constants'][$constant->getName()] = $ctx = new Context([
|
||||
'constant' => $constant->getName(),
|
||||
'comment' => $constant->getDocComment() ?: null,
|
||||
'annotations' => [],
|
||||
'reflector' => $constant,
|
||||
], $context);
|
||||
foreach ($annotationFactory->build($constant, $ctx) as $annotation) {
|
||||
if ($annotation instanceof OA\Property) {
|
||||
$analysis->addAnnotation($annotation, $ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$addDefinition = 'add' . ucfirst($contextType) . 'Definition';
|
||||
$analysis->{$addDefinition}($definition);
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Analysers;
|
||||
|
||||
use PhpParser\Error;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Enum_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\ParserFactory;
|
||||
|
||||
/**
|
||||
* High-level, PHP-token-based, scanner.
|
||||
*/
|
||||
class TokenScanner
|
||||
{
|
||||
/**
|
||||
* Scan a given file for all classes, interfaces, and traits.
|
||||
*
|
||||
* @return array{
|
||||
* 'uses': array<string, class-string>,
|
||||
* 'interfaces': list<class-string>,
|
||||
* 'traits': list<class-string>,
|
||||
* 'enums': list<class-string>,
|
||||
* 'methods': list<string>,
|
||||
* 'properties': list<string>,
|
||||
* } File details
|
||||
*/
|
||||
public function scanFile(string $filename): array
|
||||
{
|
||||
$parser = (new ParserFactory())->createForNewestSupportedVersion();
|
||||
try {
|
||||
$stmts = $parser->parse(file_get_contents($filename));
|
||||
} catch (Error $error) {
|
||||
throw new \RuntimeException($error->getMessage(), $error->getCode(), $error);
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$result += $this->collect_stmts($stmts, '');
|
||||
foreach ($stmts as $stmt) {
|
||||
if ($stmt instanceof Namespace_) {
|
||||
$namespace = (string) $stmt->name;
|
||||
|
||||
$result += $this->collect_stmts($stmt->stmts, $namespace);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function collect_stmts(array $stmts, string $namespace): array
|
||||
{
|
||||
/** @var array $uses */
|
||||
$uses = [];
|
||||
$resolve = static function (string $name) use ($namespace, &$uses) {
|
||||
if (array_key_exists($name, $uses)) {
|
||||
return $uses[$name];
|
||||
}
|
||||
|
||||
return $namespace . '\\' . $name;
|
||||
};
|
||||
$details = static function () use (&$uses): array {
|
||||
return [
|
||||
'uses' => $uses,
|
||||
'interfaces' => [],
|
||||
'traits' => [],
|
||||
'enums' => [],
|
||||
'methods' => [],
|
||||
'properties' => [],
|
||||
];
|
||||
};
|
||||
$result = [];
|
||||
foreach ($stmts as $stmt) {
|
||||
switch ($stmt::class) {
|
||||
case Use_::class:
|
||||
$uses += $this->collect_uses($stmt);
|
||||
break;
|
||||
case Class_::class:
|
||||
$result += $this->collect_class($stmt, $details(), $resolve);
|
||||
break;
|
||||
case Interface_::class:
|
||||
$result += $this->collect_interface($stmt, $details(), $resolve);
|
||||
break;
|
||||
case Trait_::class:
|
||||
case Enum_::class:
|
||||
$result += $this->collect_classlike($stmt, $details(), $resolve);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function collect_uses(Use_ $stmt): array
|
||||
{
|
||||
$uses = [];
|
||||
|
||||
foreach ($stmt->uses as $use) {
|
||||
$uses[(string) $use->getAlias()] = (string) $use->name;
|
||||
}
|
||||
|
||||
return $uses;
|
||||
}
|
||||
|
||||
protected function collect_classlike(ClassLike $stmt, array $details, callable $resolve): array
|
||||
{
|
||||
foreach ($stmt->getProperties() as $properties) {
|
||||
foreach ($properties->props as $prop) {
|
||||
$details['properties'][] = (string) $prop->name;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($stmt->getMethods() as $method) {
|
||||
$details['methods'][] = (string) $method->name;
|
||||
}
|
||||
|
||||
foreach ($stmt->getTraitUses() as $traitUse) {
|
||||
foreach ($traitUse->traits as $trait) {
|
||||
$details['traits'][] = $resolve((string) $trait);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
$resolve($stmt->name->name) => $details,
|
||||
];
|
||||
}
|
||||
|
||||
protected function collect_class(Class_ $stmt, array $details, callable $resolve): array
|
||||
{
|
||||
foreach ($stmt->implements as $implement) {
|
||||
$details['interfaces'][] = $resolve((string) $implement);
|
||||
}
|
||||
|
||||
// promoted properties
|
||||
if ($ctor = $stmt->getMethod('__construct')) {
|
||||
foreach ($ctor->getParams() as $param) {
|
||||
if ($param->flags) {
|
||||
$details['properties'][] = $param->var->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->collect_classlike($stmt, $details, $resolve);
|
||||
}
|
||||
|
||||
protected function collect_interface(Interface_ $stmt, array $details, callable $resolve): array
|
||||
{
|
||||
foreach ($stmt->extends as $extend) {
|
||||
$details['interfaces'][] = $resolve((string) $extend);
|
||||
}
|
||||
|
||||
return $this->collect_classlike($stmt, $details, $resolve);
|
||||
}
|
||||
}
|
||||
+449
@@ -0,0 +1,449 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
* Result of the analyser.
|
||||
*
|
||||
* Pretends to be an array of annotations but also contains detected classes and helper functions for the processors.
|
||||
*/
|
||||
class Analysis
|
||||
{
|
||||
/** @var \SplObjectStorage<OA\AbstractAnnotation, Context> */
|
||||
public \SplObjectStorage $annotations;
|
||||
|
||||
/**
|
||||
* Class definitions.
|
||||
*/
|
||||
public array $classes = [];
|
||||
|
||||
/**
|
||||
* Interface definitions.
|
||||
*/
|
||||
public array $interfaces = [];
|
||||
|
||||
/**
|
||||
* Trait definitions.
|
||||
*/
|
||||
public array $traits = [];
|
||||
|
||||
/**
|
||||
* Enum definitions.
|
||||
*/
|
||||
public array $enums = [];
|
||||
|
||||
/**
|
||||
* The target OpenApi annotation.
|
||||
*/
|
||||
public ?OA\OpenApi $openapi = null;
|
||||
|
||||
public ?Context $context = null;
|
||||
|
||||
/**
|
||||
* @param list<OA\AbstractAnnotation> $annotations
|
||||
*/
|
||||
public function __construct(array $annotations = [], ?Context $context = null)
|
||||
{
|
||||
$this->annotations = new \SplObjectStorage();
|
||||
$this->context = $context;
|
||||
|
||||
$this->addAnnotations($annotations, $context);
|
||||
}
|
||||
|
||||
public function addAnnotation(OA\AbstractAnnotation $annotation, Context $context): void
|
||||
{
|
||||
if ($this->annotations->offsetExists($annotation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$context->ensureRoot($this->context);
|
||||
|
||||
if ($annotation instanceof OA\OpenApi) {
|
||||
$this->openapi = $this->openapi ?: $annotation;
|
||||
} else {
|
||||
if ($context->is('annotations') === false) {
|
||||
$context->annotations = [];
|
||||
}
|
||||
|
||||
if (in_array($annotation, $context->annotations, strict: true) === false) {
|
||||
$context->annotations[] = $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
$this->annotations->offsetSet($annotation, $context);
|
||||
|
||||
foreach (get_object_vars($annotation) as $property => $value) {
|
||||
if (in_array($property, $annotation::$_blacklist)) {
|
||||
if ($property === '_unmerged') {
|
||||
foreach ($value as $item) {
|
||||
$this->addAnnotation($item, $context);
|
||||
}
|
||||
}
|
||||
} elseif (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
if ($item instanceof OA\AbstractAnnotation) {
|
||||
$this->addAnnotation($item, $context);
|
||||
}
|
||||
}
|
||||
} elseif ($value instanceof OA\AbstractAnnotation) {
|
||||
$this->addAnnotation($value, $context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeAnnotation(OA\AbstractAnnotation $annotation): void
|
||||
{
|
||||
if ($this->annotations->offsetExists($annotation)) {
|
||||
$context = $this->annotations->offsetGet($annotation);
|
||||
$this->annotations->offsetUnset($annotation);
|
||||
|
||||
if ($context->is('annotations') !== false) {
|
||||
$index = array_search($annotation, $context->annotations, true);
|
||||
if ($index !== false) {
|
||||
array_splice($context->annotations, $index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<OA\AbstractAnnotation> $annotations
|
||||
*/
|
||||
public function addAnnotations(array $annotations, Context $context): void
|
||||
{
|
||||
foreach ($annotations as $annotation) {
|
||||
$this->addAnnotation($annotation, $context);
|
||||
}
|
||||
}
|
||||
|
||||
public function addClassDefinition(array $definition): void
|
||||
{
|
||||
$class = $definition['context']->fullyQualifiedName($definition['class']);
|
||||
$this->classes[$class] = $definition;
|
||||
}
|
||||
|
||||
public function addInterfaceDefinition(array $definition): void
|
||||
{
|
||||
$interface = $definition['context']->fullyQualifiedName($definition['interface']);
|
||||
$this->interfaces[$interface] = $definition;
|
||||
}
|
||||
|
||||
public function addTraitDefinition(array $definition): void
|
||||
{
|
||||
$trait = $definition['context']->fullyQualifiedName($definition['trait']);
|
||||
$this->traits[$trait] = $definition;
|
||||
}
|
||||
|
||||
public function addEnumDefinition(array $definition): void
|
||||
{
|
||||
$enum = $definition['context']->fullyQualifiedName($definition['enum']);
|
||||
$this->enums[$enum] = $definition;
|
||||
}
|
||||
|
||||
public function addAnalysis(Analysis $analysis): void
|
||||
{
|
||||
foreach ($analysis->annotations as $annotation) {
|
||||
$this->addAnnotation($annotation, $analysis->annotations[$annotation]);
|
||||
}
|
||||
$this->classes = array_merge($this->classes, $analysis->classes);
|
||||
$this->interfaces = array_merge($this->interfaces, $analysis->interfaces);
|
||||
$this->traits = array_merge($this->traits, $analysis->traits);
|
||||
$this->enums = array_merge($this->enums, $analysis->enums);
|
||||
if (!$this->openapi instanceof OA\OpenApi && $analysis->openapi instanceof OA\OpenApi) {
|
||||
$this->openapi = $analysis->openapi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all subclasses of the given parent class.
|
||||
*
|
||||
* @param class-string $parent the parent class
|
||||
*
|
||||
* @return array map of class => definition pairs of sub-classes
|
||||
*/
|
||||
public function getSubClasses(string $parent): array
|
||||
{
|
||||
$definitions = [];
|
||||
foreach ($this->classes as $class => $classDefinition) {
|
||||
if ($classDefinition['extends'] === $parent) {
|
||||
$definitions[$class] = $classDefinition;
|
||||
$definitions = array_merge($definitions, $this->getSubClasses($class));
|
||||
}
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all super classes for the given class.
|
||||
*
|
||||
* @param class-string|null $class the class name
|
||||
* @param bool $direct flag to find only the actual class parents
|
||||
*
|
||||
* @return array map of class => definition pairs of parent classes
|
||||
*/
|
||||
public function getSuperClasses(?string $class, bool $direct = false): array
|
||||
{
|
||||
$classDefinition = $this->classes[$class ?? ''] ?? null;
|
||||
if (!$classDefinition || empty($classDefinition['extends'])) {
|
||||
// unknown class, or no inheritance
|
||||
return [];
|
||||
}
|
||||
|
||||
$extends = $classDefinition['extends'];
|
||||
$extendsDefinition = $this->classes[$extends] ?? null;
|
||||
if (!$extendsDefinition) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$parentDetails = [$extends => $extendsDefinition];
|
||||
|
||||
if ($direct) {
|
||||
return $parentDetails;
|
||||
}
|
||||
|
||||
return array_merge($parentDetails, $this->getSuperClasses($extends));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of interfaces used by the given class or by classes which it extends.
|
||||
*
|
||||
* @param class-string|null $class the class name
|
||||
* @param bool $direct flag to find only the actual class interfaces
|
||||
*
|
||||
* @return array map of class => definition pairs of interfaces
|
||||
*/
|
||||
public function getInterfacesOfClass(?string $class, bool $direct = false): array
|
||||
{
|
||||
$classes = $direct ? [] : array_keys($this->getSuperClasses($class));
|
||||
// add self
|
||||
$classes[] = $class;
|
||||
|
||||
$definitions = [];
|
||||
foreach ($classes as $clazz) {
|
||||
if (isset($this->classes[$clazz])) {
|
||||
$definition = $this->classes[$clazz];
|
||||
if (isset($definition['implements'])) {
|
||||
foreach ($definition['implements'] as $interface) {
|
||||
if (array_key_exists($interface, $this->interfaces)) {
|
||||
$definitions[$interface] = $this->interfaces[$interface];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$direct) {
|
||||
// expand recursively for interfaces extending other interfaces
|
||||
$collect = function ($interfaces, $cb) use (&$definitions): void {
|
||||
foreach ($interfaces as $interface) {
|
||||
if (isset($this->interfaces[$interface]['extends'])) {
|
||||
$cb($this->interfaces[$interface]['extends'], $cb);
|
||||
foreach ($this->interfaces[$interface]['extends'] as $fqdn) {
|
||||
$definitions[$fqdn] = $this->interfaces[$fqdn];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
$collect(array_keys($definitions), $collect);
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of traits used by the given class/trait or by classes which it extends.
|
||||
*
|
||||
* @param string|null $source the source name
|
||||
* @param bool $direct flag to find only the actual class traits
|
||||
*
|
||||
* @return array map of class => definition pairs of traits
|
||||
*/
|
||||
public function getTraitsOfClass(?string $source, bool $direct = false): array
|
||||
{
|
||||
$sources = $direct ? [] : array_keys($this->getSuperClasses($source));
|
||||
// add self
|
||||
$sources[] = $source;
|
||||
|
||||
$definitions = [];
|
||||
foreach ($sources as $sourze) {
|
||||
if (isset($this->classes[$sourze]) || isset($this->traits[$sourze])) {
|
||||
$definition = $this->classes[$sourze] ?? $this->traits[$sourze];
|
||||
if (isset($definition['traits'])) {
|
||||
foreach ($definition['traits'] as $trait) {
|
||||
if (array_key_exists($trait, $this->traits)) {
|
||||
$definitions[$trait] = $this->traits[$trait];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$direct) {
|
||||
// expand recursively for traits using other traits
|
||||
$collect = function ($traits, $cb) use (&$definitions): void {
|
||||
foreach ($traits as $trait) {
|
||||
if (isset($this->traits[$trait]['traits'])) {
|
||||
$cb($this->traits[$trait]['traits'], $cb);
|
||||
foreach ($this->traits[$trait]['traits'] as $fqdn) {
|
||||
$definitions[$fqdn] = $this->traits[$fqdn];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
$collect(array_keys($definitions), $collect);
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T extends OA\AbstractAnnotation
|
||||
*
|
||||
* @param class-string<T>|list<class-string<T>> $classes one or more class names
|
||||
* @param bool $strict in non-strict mode child classes are also detected
|
||||
*
|
||||
* @return list<T>
|
||||
*/
|
||||
public function getAnnotationsOfType($classes, bool $strict = false): array
|
||||
{
|
||||
$unique = new \SplObjectStorage();
|
||||
$annotations = [];
|
||||
|
||||
foreach ((array) $classes as $class) {
|
||||
/** @var OA\AbstractAnnotation $annotation */
|
||||
foreach ($this->annotations as $annotation) {
|
||||
if ($annotation instanceof $class && (!$strict || ($annotation->isRoot($class) && !$unique->offsetExists($annotation)))) {
|
||||
$unique->offsetSet($annotation);
|
||||
$annotations[] = $annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of OA\AbstractAnnotation
|
||||
*
|
||||
* @param string $fqdn the source class/interface/trait
|
||||
* @param class-string<T> $sourceClass
|
||||
* @return T|null
|
||||
*/
|
||||
public function getAnnotationForSource(string $fqdn, string $sourceClass = OA\Schema::class): ?OA\AbstractAnnotation
|
||||
{
|
||||
$fqdn = '\\' . ltrim($fqdn, '\\');
|
||||
|
||||
foreach ([$this->classes, $this->interfaces, $this->traits, $this->enums] as $definitions) {
|
||||
if (array_key_exists($fqdn, $definitions)) {
|
||||
$definition = $definitions[$fqdn];
|
||||
if (is_iterable($definition['context']->annotations)) {
|
||||
/** @var OA\AbstractAnnotation $annotation */
|
||||
foreach (array_reverse($definition['context']->annotations) as $annotation) {
|
||||
if ($annotation instanceof $sourceClass && $annotation->isRoot($sourceClass) && !$annotation->_context->is('generated')) {
|
||||
return $annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an analysis with only the annotations that are merged into the OpenAPI annotation.
|
||||
*/
|
||||
public function merged(): Analysis
|
||||
{
|
||||
if (!$this->openapi instanceof OA\OpenApi) {
|
||||
throw new OpenApiException('No openapi target set. Run the MergeIntoOpenApi processor');
|
||||
}
|
||||
$unmerged = $this->openapi->_unmerged;
|
||||
$this->openapi->_unmerged = [];
|
||||
$analysis = new Analysis([$this->openapi], $this->context);
|
||||
$this->openapi->_unmerged = $unmerged;
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analysis with only the annotations that not merged.
|
||||
*/
|
||||
public function unmerged(): Analysis
|
||||
{
|
||||
return $this->split()->unmerged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the annotation into two analysis.
|
||||
* One with annotations that are merged and one with annotations that are not merged.
|
||||
*
|
||||
* @return \stdClass {merged: Analysis, unmerged: Analysis}
|
||||
*/
|
||||
public function split(): \stdClass
|
||||
{
|
||||
$result = new \stdClass();
|
||||
$result->merged = $this->merged();
|
||||
$result->unmerged = new Analysis([], $this->context);
|
||||
foreach ($this->annotations as $annotation) {
|
||||
if ($result->merged->annotations->offsetExists($annotation) === false) {
|
||||
$result->unmerged->annotations->offsetSet($annotation, $this->annotations[$annotation]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function validate(): bool
|
||||
{
|
||||
if (!$this->openapi instanceof OA\OpenApi) {
|
||||
$this->context->logger->warning('No openapi target set. Run the MergeIntoOpenApi processor before validate()');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$isValid = true;
|
||||
$version = $this->openapi->openapi;
|
||||
$context = new \stdClass();
|
||||
|
||||
foreach ($this->collectAnnotations($this->openapi) as $annotation) {
|
||||
$isValid = $annotation->validate($this, $version, $context) && $isValid;
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<OA\AbstractAnnotation>
|
||||
*/
|
||||
protected function collectAnnotations(OA\AbstractAnnotation $root): array
|
||||
{
|
||||
$annotations = [$root];
|
||||
|
||||
foreach (get_object_vars($root) as $field => $value) {
|
||||
if (null === $value || Generator::isDefault($value) || is_scalar($value) || in_array($field, $root::$_blacklist)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value instanceof OA\AbstractAnnotation) {
|
||||
$annotations = array_merge($annotations, $this->collectAnnotations($value));
|
||||
} elseif (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
if ($item instanceof OA\AbstractAnnotation) {
|
||||
$annotations = array_merge($annotations, $this->collectAnnotations($item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,712 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Context;
|
||||
use OpenApi\Generator;
|
||||
use OpenApi\OpenApiException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* The openapi annotation base class.
|
||||
*/
|
||||
abstract class AbstractAnnotation implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* While the OpenAPI Specification tries to accommodate most use cases, additional data can be added to extend the specification at certain points.
|
||||
* For further details see https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions
|
||||
* The keys inside the array will be prefixed with <code>x-</code>.
|
||||
*
|
||||
* @var array<string,mixed>
|
||||
*/
|
||||
public $x = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Arbitrary attachables for this annotation.
|
||||
* These will be ignored but can be used for custom processing.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $attachables = Generator::UNDEFINED;
|
||||
|
||||
public Context $_context;
|
||||
|
||||
/**
|
||||
* Annotations that couldn't be merged by mapping or postprocessing.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $_unmerged = [];
|
||||
|
||||
/**
|
||||
* The properties which are required by [the spec](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md).
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public static $_required = [];
|
||||
|
||||
/**
|
||||
* Specify the type of the property.
|
||||
*
|
||||
* Examples:
|
||||
* 'name' => 'string' // a string
|
||||
* 'required' => 'boolean', // true or false
|
||||
* 'tags' => '[string]', // string array
|
||||
* 'in' => ["query", "header", "path", "formData", "body"] // must be one on these
|
||||
* 'oneOf' => [Schema::class] // array of schema objects.
|
||||
*
|
||||
* @var array<string,string|array<string>>
|
||||
*/
|
||||
public static $_types = [];
|
||||
|
||||
/**
|
||||
* Declarative mapping of Annotation types to properties.
|
||||
*
|
||||
* Examples:
|
||||
* Info::class => 'info', // Set @OA\Info annotation as the info property.
|
||||
* Parameter::class => ['parameters'], // Append @OA\Parameter annotations the parameters list.
|
||||
* PathItem::class => ['paths', 'path'], // Add @OA\PathItem annotation to the `paths` map and use `path` as key.
|
||||
*
|
||||
* @var array<class-string<AbstractAnnotation>,string|array<string>>
|
||||
*/
|
||||
public static $_nested = [];
|
||||
|
||||
/**
|
||||
* Reverse mapping of $_nested with the allowed parent annotations.
|
||||
*
|
||||
* @var array<class-string<AbstractAnnotation>>
|
||||
*/
|
||||
public static $_parents = [];
|
||||
|
||||
/**
|
||||
* Properties that are blacklisted from the JSON output.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public static $_blacklist = ['_context', '_unmerged', '_analysis', 'attachables'];
|
||||
|
||||
public function __construct(array $properties)
|
||||
{
|
||||
if (isset($properties['_context'])) {
|
||||
$this->_context = $properties['_context'];
|
||||
unset($properties['_context']);
|
||||
} elseif (Generator::$context) {
|
||||
$this->_context = Generator::$context;
|
||||
} else {
|
||||
$this->_context = new Context(['generated' => true]);
|
||||
}
|
||||
|
||||
if ($this->_context->is('annotations') === false) {
|
||||
$this->_context->annotations = [];
|
||||
}
|
||||
|
||||
$this->_context->annotations[] = $this;
|
||||
$nestedContext = new Context(['nested' => $this], $this->_context);
|
||||
foreach ($properties as $property => $value) {
|
||||
if (property_exists($this, $property)) {
|
||||
$this->{$property} = $value;
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $annotation) {
|
||||
if ($annotation instanceof AbstractAnnotation) {
|
||||
$this->{$property}[$key] = $this->nested($annotation, $nestedContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($property !== 'value') {
|
||||
$this->{$property} = $value;
|
||||
} elseif (is_array($value)) {
|
||||
$annotations = [];
|
||||
foreach ($value as $annotation) {
|
||||
if ($annotation instanceof AbstractAnnotation) {
|
||||
$annotations[] = $annotation;
|
||||
} else {
|
||||
$this->_context->logger->warning('Unexpected field in ' . $this->identity() . ' in ' . $this->_context);
|
||||
}
|
||||
}
|
||||
$this->merge($annotations);
|
||||
} elseif (is_object($value)) {
|
||||
$this->merge([$value]);
|
||||
} else {
|
||||
if (!Generator::isDefault($value)) {
|
||||
$this->_context->logger->warning('Unexpected parameter "' . $property . '" in ' . $this->identity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge given annotations to their mapped properties configured in static::$_nested.
|
||||
*
|
||||
* Annotations that couldn't be merged are added to the _unmerged array.
|
||||
*
|
||||
* @param list<AbstractAnnotation> $annotations
|
||||
* @param bool $ignore Ignore unmerged annotations
|
||||
*
|
||||
* @return list<AbstractAnnotation> The unmerged annotations
|
||||
*/
|
||||
public function merge(array $annotations, bool $ignore = false): array
|
||||
{
|
||||
$unmerged = [];
|
||||
$nestedContext = new Context(['nested' => $this], $this->_context);
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
$mapped = false;
|
||||
if ($details = $this->matchNested($annotation)) {
|
||||
$property = $details->value;
|
||||
if (is_array($property)) {
|
||||
$property = $property[0];
|
||||
if (Generator::isDefault($this->{$property})) {
|
||||
$this->{$property} = [];
|
||||
}
|
||||
$this->{$property}[] = $this->nested($annotation, $nestedContext);
|
||||
$mapped = true;
|
||||
} elseif (Generator::isDefault($this->{$property})) {
|
||||
// ignore duplicate nested if only one expected
|
||||
$this->{$property} = $this->nested($annotation, $nestedContext);
|
||||
$mapped = true;
|
||||
}
|
||||
}
|
||||
if (!$mapped) {
|
||||
$unmerged[] = $annotation;
|
||||
}
|
||||
}
|
||||
if (!$ignore) {
|
||||
foreach ($unmerged as $annotation) {
|
||||
$this->_unmerged[] = $this->nested($annotation, $nestedContext);
|
||||
}
|
||||
}
|
||||
|
||||
return $unmerged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the properties from the given object into this annotation.
|
||||
* Prevents overwriting properties that are already configured.
|
||||
*
|
||||
* @param object $object
|
||||
*/
|
||||
public function mergeProperties($object): void
|
||||
{
|
||||
$currentValues = get_object_vars($this);
|
||||
foreach ($object as $property => $value) {
|
||||
if ($property === '_context') {
|
||||
continue;
|
||||
}
|
||||
if (Generator::isDefault($currentValues[$property])) {
|
||||
// Overwrite default values
|
||||
$this->{$property} = $value;
|
||||
continue;
|
||||
}
|
||||
if ($property === '_unmerged') {
|
||||
$this->_unmerged = array_merge($this->_unmerged, $value);
|
||||
continue;
|
||||
}
|
||||
if ($currentValues[$property] !== $value) {
|
||||
// New value is not the same?
|
||||
if (Generator::isDefault($value)) {
|
||||
continue;
|
||||
}
|
||||
$identity = method_exists($object, 'identity') ? $object->identity() : $object::class;
|
||||
$context1 = $this->_context;
|
||||
$context2 = property_exists($object, '_context') ? $object->_context : 'unknown';
|
||||
if ($this->{$property} instanceof AbstractAnnotation) {
|
||||
$context1 = $this->{$property}->_context;
|
||||
}
|
||||
$this->_context->logger->error('Multiple definitions for ' . $identity . '->' . $property . "\n Using: " . $context1 . "\n Skipping: " . $context2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the documentation in YAML format.
|
||||
*
|
||||
* @param int-mask-of<Yaml::PARSE_*>|null $flags A bit field of PARSE_* constants to customize the YAML parser behavior
|
||||
*/
|
||||
public function toYaml(?int $flags = null): string
|
||||
{
|
||||
if ($flags === null) {
|
||||
$flags = Yaml::DUMP_OBJECT_AS_MAP ^ Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE;
|
||||
}
|
||||
|
||||
return Yaml::dump(json_decode($this->toJson(JSON_INVALID_UTF8_IGNORE)), 10, 2, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the documentation in JSON format.
|
||||
*/
|
||||
public function toJson(?int $flags = null): string
|
||||
{
|
||||
if ($flags === null) {
|
||||
$flags = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_IGNORE;
|
||||
}
|
||||
|
||||
return json_encode($this, $flags);
|
||||
}
|
||||
|
||||
public function __debugInfo()
|
||||
{
|
||||
$properties = [];
|
||||
foreach (get_object_vars($this) as $property => $value) {
|
||||
if (!Generator::isDefault($value)) {
|
||||
$properties[$property] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = new \stdClass();
|
||||
|
||||
// Strip undefined values.
|
||||
foreach (get_object_vars($this) as $property => $value) {
|
||||
if (!Generator::isDefault($value)) {
|
||||
$data->{$property} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip properties that are for internal (swagger-php) use.
|
||||
foreach (static::$_blacklist as $property) {
|
||||
unset($data->{$property});
|
||||
}
|
||||
|
||||
// Correct empty array to empty objects.
|
||||
foreach (static::$_types as $property => $type) {
|
||||
if ($type === 'object' && is_array($data->{$property}) && $data->{$property} === []) {
|
||||
$data->{$property} = new \stdClass();
|
||||
}
|
||||
}
|
||||
|
||||
// Inject vendor properties.
|
||||
unset($data->x);
|
||||
if (is_array($this->x)) {
|
||||
foreach ($this->x as $property => $value) {
|
||||
$prefixed = 'x-' . $property;
|
||||
$data->{$prefixed} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Map nested keys
|
||||
foreach (static::$_nested as $nested) {
|
||||
if (is_string($nested) || count($nested) === 1) {
|
||||
continue;
|
||||
}
|
||||
$property = $nested[0];
|
||||
if (Generator::isDefault($this->{$property})) {
|
||||
continue;
|
||||
}
|
||||
$keyField = $nested[1];
|
||||
$object = new \stdClass();
|
||||
foreach ($this->{$property} as $key => $item) {
|
||||
if (is_numeric($key) === false && is_array($item)) {
|
||||
$object->{$key} = $item;
|
||||
} else {
|
||||
$key = $item->{$keyField};
|
||||
if (!Generator::isDefault($key) && empty($object->{$key})) {
|
||||
$object->{$key} = $item instanceof \JsonSerializable ? $item->jsonSerialize() : $item;
|
||||
unset($object->{$key}->{$keyField});
|
||||
}
|
||||
}
|
||||
}
|
||||
$data->{$property} = $object;
|
||||
}
|
||||
|
||||
// $ref
|
||||
if (isset($data->ref)) {
|
||||
// Only specific https://github.com/OAI/OpenAPI-Specification/blob/3.1.0/versions/3.1.0.md#reference-object
|
||||
$ref = ['$ref' => $data->ref];
|
||||
if (!$this->_context->isVersion('3.0.x')) {
|
||||
foreach (['summary', 'description'] as $prop) {
|
||||
if (property_exists($data, $prop)) {
|
||||
$ref[$prop] = $data->{$prop};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (property_exists($this, 'nullable') && $this->nullable === true) {
|
||||
$ref = ['oneOf' => [$ref]];
|
||||
if (!$this->_context->isVersion('3.0.x')) {
|
||||
$ref['oneOf'][] = ['type' => 'null'];
|
||||
} else {
|
||||
$ref['nullable'] = $data->nullable;
|
||||
}
|
||||
unset($data->ref, $data->nullable);
|
||||
|
||||
// preserve other properties
|
||||
foreach (get_object_vars($data) as $property => $value) {
|
||||
$ref[$property] = $value;
|
||||
}
|
||||
}
|
||||
$data = (object) $ref;
|
||||
}
|
||||
|
||||
if ($this->_context->isVersion('3.0.x')) {
|
||||
if (isset($data->exclusiveMinimum) && is_numeric($data->exclusiveMinimum)) {
|
||||
$data->minimum = $data->exclusiveMinimum;
|
||||
$data->exclusiveMinimum = true;
|
||||
}
|
||||
|
||||
if (isset($data->exclusiveMaximum) && is_numeric($data->exclusiveMaximum)) {
|
||||
$data->maximum = $data->exclusiveMaximum;
|
||||
$data->exclusiveMaximum = true;
|
||||
}
|
||||
|
||||
if (isset($data->type) && is_array($data->type)) {
|
||||
if (in_array('null', $data->type)) {
|
||||
$data->nullable = true;
|
||||
$data->type = array_filter($data->type, static fn ($v): bool => $v !== 'null');
|
||||
if (1 === count($data->type)) {
|
||||
$data->type = array_pop($data->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($data->type) && is_array($data->type)) {
|
||||
if (1 === count($data->type)) {
|
||||
$data->type = array_pop($data->type);
|
||||
} else {
|
||||
unset($data->type);
|
||||
}
|
||||
}
|
||||
|
||||
unset($data->unevaluatedProperties);
|
||||
}
|
||||
|
||||
if (!$this->_context->isVersion('3.0.x')) {
|
||||
if (isset($data->nullable)) {
|
||||
if (true === $data->nullable) {
|
||||
if (isset($data->oneOf)) {
|
||||
$data->oneOf[] = ['type' => 'null'];
|
||||
} elseif (isset($data->anyOf)) {
|
||||
$data->anyOf[] = ['type' => 'null'];
|
||||
} elseif (isset($data->allOf)) {
|
||||
$data->allOf[] = ['type' => 'null'];
|
||||
} elseif (isset($data->type)) {
|
||||
$data->type = (array) $data->type;
|
||||
$data->type[] = 'null';
|
||||
}
|
||||
}
|
||||
unset($data->nullable);
|
||||
}
|
||||
|
||||
if (isset($data->minimum) && isset($data->exclusiveMinimum)) {
|
||||
if (true === $data->exclusiveMinimum) {
|
||||
$data->exclusiveMinimum = $data->minimum;
|
||||
unset($data->minimum);
|
||||
} elseif (false === $data->exclusiveMinimum) {
|
||||
unset($data->exclusiveMinimum);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data->maximum) && isset($data->exclusiveMaximum)) {
|
||||
if (true === $data->exclusiveMaximum) {
|
||||
$data->exclusiveMaximum = $data->maximum;
|
||||
unset($data->maximum);
|
||||
} elseif (false === $data->exclusiveMaximum) {
|
||||
unset($data->exclusiveMaximum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a given value against a `_$type` definition.
|
||||
*/
|
||||
private function validateValueType(string $type, mixed $value): bool
|
||||
{
|
||||
if (str_starts_with($type, '[') && str_ends_with($type, ']')) {
|
||||
// $value must be an array
|
||||
if (!$this->validateValueType('array', $value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$itemType = substr($type, 1, -1);
|
||||
foreach ($value as $item) {
|
||||
if (!$this->validateValueType($itemType, $item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_subclass_of($type, AbstractAnnotation::class)) {
|
||||
$type = 'object';
|
||||
}
|
||||
|
||||
$isValidType = fn (string $type, mixed $value): bool => match ($type) {
|
||||
'string' => is_string($value),
|
||||
'boolean' => is_bool($value),
|
||||
'integer' => is_int($value),
|
||||
'number' => is_numeric($value),
|
||||
'object' => is_object($value),
|
||||
'array' => is_array($value) && array_is_list($value),
|
||||
'scheme' => in_array($value, ['http', 'https', 'ws', 'wss'], strict: true),
|
||||
default => throw new OpenApiException('Invalid type "' . $type . '"'),
|
||||
};
|
||||
|
||||
foreach (explode('|', $type) as $tt) {
|
||||
if ($isValidType(trim($tt), $value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function validate(?Analysis $analysis = null, string $version = OpenApi::DEFAULT_VERSION, ?object $context = null): bool
|
||||
{
|
||||
$isValid = true;
|
||||
|
||||
// validate unmerged
|
||||
foreach ($this->_unmerged as $annotation) {
|
||||
if (!is_object($annotation)) {
|
||||
$this->_context->logger->warning('Unexpected type: "' . gettype($annotation) . '" in ' . $this->identity() . '->_unmerged, expecting a Annotation object');
|
||||
break;
|
||||
}
|
||||
|
||||
if ($details = $this->matchNested($annotation)) {
|
||||
$property = $details->value;
|
||||
if (is_array($property)) {
|
||||
$this->_context->logger->warning('Only one ' . $annotation->identity([]) . ' allowed for ' . $this->identity() . ' multiple found, skipped: ' . $annotation->_context);
|
||||
} else {
|
||||
$this->_context->logger->warning('Only one ' . $annotation->identity([]) . ' allowed for ' . $this->identity() . " multiple found in:\n Using: " . $this->{$property}->_context . "\n Skipped: " . $annotation->_context);
|
||||
}
|
||||
} elseif ($annotation instanceof AbstractAnnotation) {
|
||||
$message = 'Unexpected ' . $annotation->identity();
|
||||
if ($annotation::$_parents) {
|
||||
$message .= ', expected to be inside ' . implode(', ', AbstractAnnotation::shorten($annotation::$_parents));
|
||||
}
|
||||
$this->_context->logger->warning($message . ' in ' . $annotation->_context);
|
||||
}
|
||||
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
// validate conflicting keys
|
||||
foreach ($this::$_nested as $annotationClass => $nested) {
|
||||
if (is_string($nested) || count($nested) === 1) {
|
||||
continue;
|
||||
}
|
||||
$property = $nested[0];
|
||||
if (Generator::isDefault($this->{$property})) {
|
||||
continue;
|
||||
}
|
||||
$keys = [];
|
||||
$keyField = $nested[1];
|
||||
/** @var AbstractAnnotation $item */
|
||||
foreach ($this->{$property} as $key => $item) {
|
||||
if (is_array($item) && !is_numeric($key)) {
|
||||
$this->_context->logger->warning($this->identity() . '->' . $property . ' is an object literal, use nested ' . AbstractAnnotation::shorten($annotationClass) . '() annotation(s) in ' . $this->_context);
|
||||
$keys[$key] = $item;
|
||||
} elseif (Generator::isDefault($item->{$keyField})) {
|
||||
$this->_context->logger->error($item->identity() . ' is missing key-field: "' . $keyField . '" in ' . $item->_context);
|
||||
} elseif (isset($keys[$item->{$keyField}])) {
|
||||
$this->_context->logger->error('Multiple ' . $item->identity([]) . ' with the same ' . $keyField . '="' . $item->{$keyField} . "\":\n " . $item->_context . "\n " . $keys[$item->{$keyField}]->_context);
|
||||
} else {
|
||||
$keys[$item->{$keyField}] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate refs
|
||||
if ($analysis?->openapi && property_exists($this, 'ref') && !Generator::isDefault($this->ref) && is_string($this->ref)) {
|
||||
if (str_starts_with($this->ref, '#/')) {
|
||||
try {
|
||||
$analysis->openapi->ref($this->ref);
|
||||
} catch (\Exception $e) {
|
||||
$this->_context->logger->warning($e->getMessage() . ' for ' . $this->identity() . ' in ' . $this->_context, ['exception' => $e]);
|
||||
$isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate required properties
|
||||
if (!property_exists($this, 'ref') || Generator::isDefault($this->ref) || !is_string($this->ref)) {
|
||||
foreach ($this::$_required as $property) {
|
||||
if (Generator::isDefault($this->{$property})) {
|
||||
$message = 'Missing required field "' . $property . '" for ' . $this->identity() . ' in ' . $this->_context;
|
||||
foreach ($this::$_nested as $class => $nested) {
|
||||
$nestedProperty = is_array($nested) ? $nested[0] : $nested;
|
||||
if ($property === $nestedProperty) {
|
||||
if ($this instanceof OpenApi) {
|
||||
$message = 'Required ' . AbstractAnnotation::shorten($class) . '() not found';
|
||||
} elseif (is_array($nested)) {
|
||||
$message = $this->identity() . ' requires at least one ' . AbstractAnnotation::shorten($class) . '() in ' . $this->_context;
|
||||
} else {
|
||||
$message = $this->identity() . ' requires a ' . AbstractAnnotation::shorten($class) . '() in ' . $this->_context;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->_context->logger->warning($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate types
|
||||
foreach ($this::$_types as $property => $type) {
|
||||
$value = $this->{$property};
|
||||
if (Generator::isDefault($value) || $value === null) {
|
||||
continue;
|
||||
}
|
||||
if (is_string($type)) {
|
||||
if (!$this->validateValueType($type, $value)) {
|
||||
$this->_context->logger->warning($this->identity() . '->' . $property . ' is a "' . gettype($value) . '", expecting a "' . $type . '" in ' . $this->_context);
|
||||
$isValid = false;
|
||||
}
|
||||
} elseif (is_array($type)) { // enum?
|
||||
if (!in_array($value, $type)) {
|
||||
$this->_context->logger->warning($this->identity() . '->' . $property . ' "' . $value . '" is invalid, expecting "' . implode('", "', $type) . '" in ' . $this->_context);
|
||||
}
|
||||
} else {
|
||||
throw new OpenApiException('Invalid ' . static::class . '::$_types[' . $property . ']');
|
||||
}
|
||||
}
|
||||
|
||||
// validate example/examples
|
||||
if (property_exists($this, 'example') && property_exists($this, 'examples')) {
|
||||
if (!Generator::isDefault($this->example) && !Generator::isDefault($this->examples)) {
|
||||
$this->_context->logger->warning($this->identity() . ': "example" and "examples" are mutually exclusive');
|
||||
|
||||
$isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a simple string representation of the annotation.
|
||||
*
|
||||
* @param array|null $properties the properties to include in the string representation
|
||||
* @example "@OA\Response(response=200)"
|
||||
*/
|
||||
public function identity(?array $properties = null): string
|
||||
{
|
||||
$class = static::class;
|
||||
|
||||
if (null === $properties) {
|
||||
$properties = [];
|
||||
/** @var class-string<AbstractAnnotation> $parent */
|
||||
foreach (static::$_parents as $parent) {
|
||||
foreach ($parent::$_nested as $annotationClass => $entry) {
|
||||
if ($annotationClass === $class && is_array($entry) && !Generator::isDefault($this->{$entry[1]})) {
|
||||
$properties[] = $entry[1];
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$details = [];
|
||||
foreach ($properties as $property) {
|
||||
$value = $this->{$property};
|
||||
if ($value !== null && !Generator::isDefault($value)) {
|
||||
$details[] = $property . '=' . (is_string($value) ? '"' . $value . '"' : $value);
|
||||
}
|
||||
}
|
||||
|
||||
return static::shorten(static::class) . '(' . implode(',', $details) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if <code>$other</code> can be nested, and if so, return details about where/how.
|
||||
*
|
||||
* @param AbstractAnnotation $other the other annotation
|
||||
*
|
||||
* @return null|object key/value object or <code>null</code>
|
||||
*/
|
||||
public function matchNested($other)
|
||||
{
|
||||
if ($other instanceof AbstractAnnotation && array_key_exists($root = $other->getRoot(), static::$_nested)) {
|
||||
return (object) ['key' => $root, 'value' => static::$_nested[$root]];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root annotation.
|
||||
*
|
||||
* This is used for resolving type equality and nesting rules to allow those rules to also work for custom,
|
||||
* derived annotation classes.
|
||||
*
|
||||
* @return class-string the root annotation class in the <code>OpenApi\\Annotations</code> namespace
|
||||
*/
|
||||
public function getRoot(): string
|
||||
{
|
||||
$class = static::class;
|
||||
|
||||
do {
|
||||
if (str_starts_with($class, 'OpenApi\\Annotations\\')) {
|
||||
break;
|
||||
}
|
||||
} while ($class = get_parent_class($class));
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the annotation root.
|
||||
*
|
||||
* @param class-string $thisClass the root class to match
|
||||
*/
|
||||
public function isRoot(string $thisClass): bool
|
||||
{
|
||||
return static::class === $thisClass || $this->getRoot() === $thisClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the context with a reference to the annotation it is nested in.
|
||||
*/
|
||||
protected function nested(AbstractAnnotation $annotation, Context $nestedContext): self
|
||||
{
|
||||
if (property_exists($annotation, '_context') && $annotation->_context === $this->_context) {
|
||||
$annotation->_context = $nestedContext;
|
||||
}
|
||||
|
||||
return $annotation;
|
||||
}
|
||||
|
||||
protected function combine(...$args): array
|
||||
{
|
||||
$combined = [];
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
$combined = array_merge($combined, $arg);
|
||||
} else {
|
||||
$combined[] = $arg;
|
||||
}
|
||||
}
|
||||
|
||||
return array_filter($combined, static fn ($value): bool => !Generator::isDefault($value) && $value !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten class name(s).
|
||||
*
|
||||
* @param array|object|string $classes Class(es) to shorten
|
||||
*
|
||||
* @return string|list<string> One or more shortened class names
|
||||
*/
|
||||
protected static function shorten($classes)
|
||||
{
|
||||
$short = [];
|
||||
foreach ((array) $classes as $class) {
|
||||
$short[] = '@' . str_replace([
|
||||
'OpenApi\\Annotations\\',
|
||||
'OpenApi\\Attributes\\',
|
||||
], 'OA\\', (string) $class);
|
||||
}
|
||||
|
||||
return is_array($classes) ? $short : array_pop($short);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class AdditionalProperties extends Schema
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Schema::class,
|
||||
Property::class,
|
||||
Items::class,
|
||||
JsonContent::class,
|
||||
XmlContent::class,
|
||||
AdditionalProperties::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Discriminator::class => 'discriminator',
|
||||
Items::class => 'items',
|
||||
Property::class => ['properties', 'property'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Examples::class => ['examples', 'example'],
|
||||
Xml::class => 'xml',
|
||||
AdditionalProperties::class => 'additionalProperties',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* A container for custom data to be attached to an annotation.
|
||||
*
|
||||
* These will be ignored by `swagger-php` but can be used for custom processing.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Attachable extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
AdditionalProperties::class,
|
||||
Components::class,
|
||||
Contact::class,
|
||||
Delete::class,
|
||||
Discriminator::class,
|
||||
Encoding::class,
|
||||
Examples::class,
|
||||
ExternalDocumentation::class,
|
||||
Flow::class,
|
||||
Get::class,
|
||||
Head::class,
|
||||
Header::class,
|
||||
Info::class,
|
||||
Items::class,
|
||||
JsonContent::class,
|
||||
License::class,
|
||||
Link::class,
|
||||
MediaType::class,
|
||||
OpenApi::class,
|
||||
Operation::class,
|
||||
Options::class,
|
||||
Parameter::class,
|
||||
Patch::class,
|
||||
PathItem::class,
|
||||
PathParameter::class,
|
||||
Post::class,
|
||||
Property::class,
|
||||
Put::class,
|
||||
RequestBody::class,
|
||||
Response::class,
|
||||
Schema::class,
|
||||
SecurityScheme::class,
|
||||
Server::class,
|
||||
ServerVariable::class,
|
||||
Tag::class,
|
||||
Trace::class,
|
||||
Webhook::class,
|
||||
Xml::class,
|
||||
XmlContent::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Allows to type-hint a specific parent annotation class.
|
||||
*
|
||||
* Container to allow custom annotations that are limited to a subset of potential parent
|
||||
* annotation classes.
|
||||
*
|
||||
* @return array<class-string>|null List of valid parent annotation classes. If <code>null</code>, the default nesting rules apply.
|
||||
*/
|
||||
public function allowedParents(): ?array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Holds a set of reusable objects for different aspects of the OA.
|
||||
*
|
||||
* All objects defined within the components object will have no effect on the API unless they are explicitly
|
||||
* referenced from properties outside the components object.
|
||||
*
|
||||
* @see [Components Object](https://spec.openapis.org/oas/v3.1.1.html#components-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Components extends AbstractAnnotation
|
||||
{
|
||||
public const COMPONENTS_PREFIX = '#/components/';
|
||||
|
||||
/**
|
||||
* Schema reference.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const SCHEMA_REF = '#/components/schemas/';
|
||||
|
||||
/**
|
||||
* Reusable Schemas.
|
||||
*
|
||||
* @var array<Schema|\OpenApi\Attributes\Schema>
|
||||
*/
|
||||
public $schemas = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Responses.
|
||||
*
|
||||
* @var list<Response>
|
||||
*/
|
||||
public $responses = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Parameters.
|
||||
*
|
||||
* @var list<Parameter>
|
||||
*/
|
||||
public $parameters = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Examples.
|
||||
*
|
||||
* @var array<Examples>
|
||||
*/
|
||||
public $examples = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Request Bodies.
|
||||
*
|
||||
* @var list<RequestBody>
|
||||
*/
|
||||
public $requestBodies = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Headers.
|
||||
*
|
||||
* @var list<Header>
|
||||
*/
|
||||
public $headers = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Security Schemes.
|
||||
*
|
||||
* @var list<SecurityScheme>
|
||||
*/
|
||||
public $securitySchemes = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Links.
|
||||
*
|
||||
* @var list<Link>
|
||||
*/
|
||||
public $links = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Reusable Callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $callbacks = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
OpenApi::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Response::class => ['responses', 'response'],
|
||||
Parameter::class => ['parameters', 'parameter'],
|
||||
PathParameter::class => ['parameters', 'parameter'],
|
||||
RequestBody::class => ['requestBodies', 'request'],
|
||||
Examples::class => ['examples', 'example'],
|
||||
Header::class => ['headers', 'header'],
|
||||
SecurityScheme::class => ['securitySchemes', 'securityScheme'],
|
||||
Link::class => ['links', 'link'],
|
||||
Schema::class => ['schemas', 'schema'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns a list of component annotation types.
|
||||
*
|
||||
* Each may be used as a root to resolve component refs
|
||||
*/
|
||||
public static function componentTypes(): array
|
||||
{
|
||||
return array_filter(array_keys(self::$_nested), static fn (string $value): bool => $value !== Attachable::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a <code>#/components/...</code> reference for the given annotation.
|
||||
*
|
||||
* A <code>string</code> component value always assumes type <code>Schema</code>.
|
||||
*
|
||||
* @param AbstractAnnotation|string $component
|
||||
*/
|
||||
public static function ref($component, bool $encode = true): string
|
||||
{
|
||||
if ($component instanceof AbstractAnnotation) {
|
||||
foreach (Components::$_nested as $type => $nested) {
|
||||
// exclude attachables
|
||||
if (2 == count($nested)) {
|
||||
if ($component instanceof $type) {
|
||||
$type = $nested[0];
|
||||
$name = $component->{$nested[1]};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$type = 'schemas';
|
||||
$name = $component;
|
||||
}
|
||||
|
||||
return self::COMPONENTS_PREFIX . $type . '/' . ($encode ? static::refEncode((string) $name) : $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes the special characters "/" and "~".
|
||||
*
|
||||
* https://swagger.io/docs/specification/using-ref/
|
||||
* https://tools.ietf.org/html/rfc6901#page-3
|
||||
*/
|
||||
public static function refEncode(string $raw): string
|
||||
{
|
||||
return str_replace('/', '~1', str_replace('~', '~0', $raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converted the escaped characters "~1" and "~" back to "/" and "~".
|
||||
*
|
||||
* https://swagger.io/docs/specification/using-ref/
|
||||
* https://tools.ietf.org/html/rfc6901#page-3
|
||||
*/
|
||||
public static function refDecode(string $encoded): string
|
||||
{
|
||||
return str_replace('~1', '/', str_replace('~0', '~', $encoded));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Contact information for the exposed API.
|
||||
*
|
||||
* @see [Contact Object](https://spec.openapis.org/oas/v3.1.1.html#components-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Contact extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The identifying name of the contact person/organization.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The URL pointing to the contact information.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The email address of the contact person/organization.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $email = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'name' => 'string',
|
||||
'url' => 'string',
|
||||
'email' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Info::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* A <code>@OA\Request</code> cookie parameter.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class CookieParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $in = 'cookie';
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Delete extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'delete';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* The discriminator is a specific object in a schema which is used to inform the consumer of
|
||||
* the specification of an alternative schema based on the value associated with it.
|
||||
*
|
||||
* This object is based on the [JSON Schema Specification](http://json-schema.org) and uses a predefined subset of it.
|
||||
* On top of this subset, there are extensions provided by this specification to allow for more complete documentation.
|
||||
*
|
||||
* @see [Discriminator Object](https://spec.openapis.org/oas/v3.1.1.html#discriminator-object)
|
||||
* @see [JSON Schema](http://json-schema.org/)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Discriminator extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The name of the property in the payload that will hold the discriminator value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $propertyName = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An object to hold mappings between payload values and schema names or references.
|
||||
*
|
||||
* @var array<string,string>
|
||||
*/
|
||||
public $mapping = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['propertyName'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'propertyName' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Schema::class,
|
||||
Property::class,
|
||||
AdditionalProperties::class,
|
||||
Items::class,
|
||||
JsonContent::class,
|
||||
XmlContent::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* A single encoding definition applied to a single schema property.
|
||||
*
|
||||
* @see [Encoding Object](https://spec.openapis.org/oas/v3.1.0.html#encoding-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Encoding extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The property name to which the encoding applies.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $property = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The content type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $contentType = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Additional headers.
|
||||
*
|
||||
* @var list<Header>
|
||||
*/
|
||||
public $headers = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $style = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $explode = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $allowReserved = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
JsonContent::class,
|
||||
XmlContent::class,
|
||||
MediaType::class,
|
||||
Property::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Header::class => ['headers', 'header'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'contentType' => 'string',
|
||||
];
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
unset($data->property);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Examples extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The relative or absolute path to an example.
|
||||
*
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The key into <code>#/components/examples</code>.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $example = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Short description for the example.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $summary = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Embedded literal example.
|
||||
*
|
||||
* The value field and externalValue field are mutually exclusive.
|
||||
*
|
||||
* To represent examples of media types that cannot naturally be represented
|
||||
* in JSON or YAML, use a string value to contain the example, escaping where necessary.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Embedded literal example.
|
||||
*
|
||||
* The value field and externalValue field are mutually exclusive.
|
||||
*
|
||||
* To represent examples of media types that cannot naturally be represented
|
||||
* in JSON or YAML, use a string value to contain the example, escaping where necessary.
|
||||
*
|
||||
* @var int|string|array
|
||||
*/
|
||||
public $value = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An URL that points to the literal example.
|
||||
*
|
||||
* This provides the capability to reference examples that cannot easily be included
|
||||
* in JSON or YAML documents.
|
||||
*
|
||||
* The value field and externalValue field are mutually exclusive.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $externalValue = Generator::UNDEFINED;
|
||||
|
||||
public static $_types = [
|
||||
'summary' => 'string',
|
||||
'description' => 'string',
|
||||
'externalValue' => 'string',
|
||||
];
|
||||
|
||||
public static $_required = ['summary'];
|
||||
|
||||
public static $_parents = [
|
||||
AdditionalProperties::class,
|
||||
Components::class,
|
||||
Items::class,
|
||||
Schema::class,
|
||||
Parameter::class,
|
||||
PathParameter::class,
|
||||
Property::class,
|
||||
MediaType::class,
|
||||
JsonContent::class,
|
||||
XmlContent::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Allows referencing an external resource for extended documentation.
|
||||
*
|
||||
* @see [External Documentation Object](https://spec.openapis.org/oas/v3.1.1.html#external-documentation-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ExternalDocumentation extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* A short description of the target documentation. GFM syntax can be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The URL for the target documentation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'description' => 'string',
|
||||
'url' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['url'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
OpenApi::class,
|
||||
Tag::class,
|
||||
Schema::class,
|
||||
AdditionalProperties::class,
|
||||
Property::class,
|
||||
Operation::class,
|
||||
Get::class,
|
||||
Post::class,
|
||||
Put::class,
|
||||
Delete::class,
|
||||
Patch::class,
|
||||
Head::class,
|
||||
Options::class,
|
||||
Trace::class,
|
||||
Items::class,
|
||||
JsonContent::class,
|
||||
XmlContent::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Configuration details for a supported OAuth flow.
|
||||
*
|
||||
* @see [OAuth Flow Object](https://spec.openapis.org/oas/v3.1.1.html#oauth-flow-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Flow extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The authorization url to be used for this flow.
|
||||
*
|
||||
* This must be in the form of an url.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $authorizationUrl = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The token URL to be used for this flow.
|
||||
*
|
||||
* This must be in the form of an url.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $tokenUrl = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The URL to be used for obtaining refresh tokens.
|
||||
*
|
||||
* This must be in the form of an url.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $refreshUrl = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Flow name.
|
||||
*
|
||||
* One of ['implicit', 'password', 'authorizationCode', 'clientCredentials'].
|
||||
*
|
||||
* @var 'authorizationCode'|'clientCredentials'|'implicit'|'password'
|
||||
*/
|
||||
public $flow = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The available scopes for the OAuth2 security scheme.
|
||||
*
|
||||
* A map between the scope name and a short description for it.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $scopes = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['scopes', 'flow'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'flow' => ['implicit', 'password', 'authorizationCode', 'clientCredentials'],
|
||||
'refreshUrl' => 'string',
|
||||
'authorizationUrl' => 'string',
|
||||
'tokenUrl' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
SecurityScheme::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
if ($this->scopes === []) {
|
||||
$this->scopes = new \stdClass();
|
||||
}
|
||||
|
||||
return parent::jsonSerialize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Get extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'get';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Head extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'head';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* @see [Header Object](https://spec.openapis.org/oas/v3.1.1.html#header-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Header extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The relative or absolute path to the endpoint.
|
||||
*
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $header = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A brief description of the parameter.
|
||||
*
|
||||
* This could contain examples of use.
|
||||
* CommonMark syntax MAY be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $required = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Schema object.
|
||||
*
|
||||
* @var Schema
|
||||
*/
|
||||
public $schema = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Specifies that a parameter is deprecated and SHOULD be transitioned out of usage.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $deprecated = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Sets the ability to pass empty-valued parameters.
|
||||
*
|
||||
* This is valid only for query parameters and allows sending a parameter with an empty value.
|
||||
*
|
||||
* Default value is false.
|
||||
*
|
||||
* If style is used, and if behavior is n/a (cannot be serialized), the value of allowEmptyValue SHALL be ignored.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $allowEmptyValue = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['header', 'schema'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'header' => 'string',
|
||||
'description' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Schema::class => 'schema',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Encoding::class,
|
||||
Components::class,
|
||||
Response::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
* A <code>@OA\Request</code> header parameter.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class HeaderParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $in = 'header';
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* The object provides metadata about the API.
|
||||
*
|
||||
* The metadata may be used by the clients if needed and may be presented in editing or documentation generation tools for convenience.
|
||||
*
|
||||
* @see [Info Object](https://spec.openapis.org/oas/v3.1.1.html#info-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Info extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The title of the application.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $title = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A short description of the application.
|
||||
*
|
||||
* CommonMark syntax may be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An URL to the Terms of Service for the API.
|
||||
*
|
||||
* Must be in the format of an url.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $termsOfService = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The contact information for the exposed API.
|
||||
*
|
||||
* @var Contact
|
||||
*/
|
||||
public $contact = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The license information for the exposed API.
|
||||
*
|
||||
* @var License
|
||||
*/
|
||||
public $license = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API implementation version).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $version = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['title', 'version'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'title' => 'string',
|
||||
'version' => 'string',
|
||||
'description' => 'string',
|
||||
'termsOfService' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Contact::class => 'contact',
|
||||
License::class => 'license',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
OpenApi::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* The description of an item in a Schema with type <code>array</code>.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Items extends Schema
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Discriminator::class => 'discriminator',
|
||||
Items::class => 'items',
|
||||
Property::class => ['properties', 'property'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Examples::class => ['examples', 'example'],
|
||||
Xml::class => 'xml',
|
||||
AdditionalProperties::class => 'additionalProperties',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Property::class,
|
||||
AdditionalProperties::class,
|
||||
Schema::class,
|
||||
JsonContent::class,
|
||||
XmlContent::class,
|
||||
Items::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Shorthand for a json response.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
* @OA\JsonContent(
|
||||
* ref="#/components/schemas/user"
|
||||
* )
|
||||
* ```
|
||||
* vs.
|
||||
* ```php
|
||||
* @OA\MediaType(
|
||||
* mediaType="application/json",
|
||||
* @OA\Schema(
|
||||
* ref="#/components/schemas/user"
|
||||
* )
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class JsonContent extends Schema
|
||||
{
|
||||
/**
|
||||
* A map between a property name and its encoding information.
|
||||
*
|
||||
* @var list<Encoding>
|
||||
*/
|
||||
public $encoding = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Discriminator::class => 'discriminator',
|
||||
Items::class => 'items',
|
||||
Property::class => ['properties', 'property'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
AdditionalProperties::class => 'additionalProperties',
|
||||
Encoding::class => ['encoding', 'property'],
|
||||
Examples::class => ['examples', 'example'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Sets a default value to the parameter. The type of the value depends on the defined type.
|
||||
*
|
||||
* @see [JSON schema validation](http://json-schema.org/latest/json-schema-validation.html)
|
||||
*/
|
||||
trait JsonSchemaTrait
|
||||
{
|
||||
/**
|
||||
* Sets a default value to the parameter.
|
||||
*
|
||||
* The type of the value depends on the defined type.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $default = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The maximum value allowed for a numeric property. This value must be a number.
|
||||
*
|
||||
* @var int|float
|
||||
*/
|
||||
public $maximum = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A boolean indicating whether the maximum value is excluded from the set of valid values.
|
||||
*
|
||||
* When set to true, the maximum value is excluded, and when false or not specified, it is included.
|
||||
*
|
||||
* @var bool|int|float
|
||||
*/
|
||||
public $exclusiveMaximum = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The minimum value allowed for a numeric property. This value must be a number.
|
||||
*
|
||||
* @var int|float
|
||||
*/
|
||||
public $minimum = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A boolean indicating whether the minimum value is excluded from the set of valid values.
|
||||
*
|
||||
* When set to true, the minimum value is excluded, and when false or not specified, it is included.
|
||||
*
|
||||
* @var bool|int|float
|
||||
*/
|
||||
public $exclusiveMinimum = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The maximum length of a string property.
|
||||
*
|
||||
* A string instance is valid against this property if its length is less than, or equal to, the value of this
|
||||
* attribute.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $maxLength = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The minimum length of a string property.
|
||||
*
|
||||
* A string instance is valid against this property if its length is greater than, or equal to, the value of this
|
||||
* attribute.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $minLength = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The maximum number of items allowed in an array property.
|
||||
*
|
||||
* An array instance is valid against this property if its number of items is less than, or equal to, the value of
|
||||
* this attribute.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $maxItems = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The minimum number of items allowed in an array property.
|
||||
*
|
||||
* An array instance is valid against this property if its number of items is greater than, or equal to, the value
|
||||
* of this attribute.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $minItems = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A boolean value indicating whether all items in an array property must be unique.
|
||||
*
|
||||
* If this attribute is set to true, then all items in the array must be unique.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $uniqueItems = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A list of allowable values for a property.
|
||||
*
|
||||
* A property instance is valid against this attribute if its value is one of the values specified in this
|
||||
* list.
|
||||
*
|
||||
* @var list<string|int|float|bool|\UnitEnum>|class-string
|
||||
*/
|
||||
public $enum = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $not = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var bool|AdditionalProperties
|
||||
*/
|
||||
public $additionalProperties = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $additionalItems = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $contains = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $patternProperties = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $unevaluatedProperties = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $dependencies = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $propertyNames = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
* @since OpenAPI 3.1.0
|
||||
*/
|
||||
public $const = Generator::UNDEFINED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Template code to be used by all attributes extending OA\Schema.
|
||||
*
|
||||
*
|
||||
** TYPE-HINTS:
|
||||
|
||||
* @param list<string|int|float|bool|\UnitEnum|null>|class-string|null $enum
|
||||
|
||||
|
||||
** PARAMETERS:
|
||||
|
||||
// JSON Schema
|
||||
mixed $default = Generator::UNDEFINED,
|
||||
int|float|null $maximum = null,
|
||||
bool|int|float|null $exclusiveMaximum = null,
|
||||
int|float|null $minimum = null,
|
||||
bool|int|float|null $exclusiveMinimum = null,
|
||||
int|null $maxLength = null,
|
||||
int|null $minLength = null,
|
||||
int|null $maxItems = null,
|
||||
int|null $minItems = null,
|
||||
bool|null $uniqueItems = null,
|
||||
array|string|null $enum = null,
|
||||
mixed $not = Generator::UNDEFINED,
|
||||
bool|AdditionalProperties|null $additionalProperties = null,
|
||||
array|null $additionalItems = null,
|
||||
array|null $contains = null,
|
||||
array|null $patternProperties = null,
|
||||
array|null $unevaluatedProperties = null,
|
||||
mixed $dependencies = Generator::UNDEFINED,
|
||||
mixed $propertyNames = Generator::UNDEFINED,
|
||||
mixed $const = Generator::UNDEFINED,
|
||||
|
||||
|
||||
** PARENT-PARAMS:
|
||||
|
||||
// JSON Schema
|
||||
'default' => $default,
|
||||
'maximum' => $maximum ?? Generator::UNDEFINED,
|
||||
'exclusiveMaximum' => $exclusiveMaximum ?? Generator::UNDEFINED,
|
||||
'minimum' => $minimum ?? Generator::UNDEFINED,
|
||||
'exclusiveMinimum' => $exclusiveMinimum ?? Generator::UNDEFINED,
|
||||
'maxLength' => $maxLength ?? Generator::UNDEFINED,
|
||||
'minLength' => $minLength ?? Generator::UNDEFINED,
|
||||
'maxItems' => $maxItems ?? Generator::UNDEFINED,
|
||||
'minItems' => $minItems ?? Generator::UNDEFINED,
|
||||
'uniqueItems' => $uniqueItems ?? Generator::UNDEFINED,
|
||||
'enum' => $enum ?? Generator::UNDEFINED,
|
||||
'not' => $not,
|
||||
'additionalProperties' => $additionalProperties ?? Generator::UNDEFINED,
|
||||
'additionalItems' => $additionalItems ?? Generator::UNDEFINED,
|
||||
'contains' => $contains ?? Generator::UNDEFINED,
|
||||
'patternProperties' => $patternProperties ?? Generator::UNDEFINED,
|
||||
'unevaluatedProperties' => $unevaluatedProperties ?? Generator::UNDEFINED,
|
||||
'dependencies' => $dependencies,
|
||||
'propertyNames' => $propertyNames,
|
||||
'const' => $const,
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* License information for the exposed API.
|
||||
*
|
||||
* @see [License Object](https://spec.openapis.org/oas/v3.1.1.html#license-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class License extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The license name used for the API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An SPDX license expression for the API. The <code>identifier</code> field is mutually exclusive of the <code>url</code> field.
|
||||
*
|
||||
* @since OpenAPI 3.1.0
|
||||
* @var string
|
||||
*/
|
||||
public $identifier = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A URL to the license used for the API. This MUST be in the form of a URL.
|
||||
*
|
||||
* The <code>url</code> field is mutually exclusive of the <code>identifier</code> field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'name' => 'string',
|
||||
'identifier' => 'string',
|
||||
'url' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['name'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Info::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
if ($this->_context->isVersion('3.0.x')) {
|
||||
unset($data->identifier);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function validate(?Analysis $analysis = null, string $version = OpenApi::DEFAULT_VERSION, ?object $context = null): bool
|
||||
{
|
||||
$isValid = parent::validate($analysis, $version, $context);
|
||||
|
||||
if (!OpenApi::versionMatch($version, '3.0.x')) {
|
||||
if (!Generator::isDefault($this->url) && !Generator::isDefault($this->identifier)) {
|
||||
$this->_context->logger->warning($this->identity() . ' url and identifier are mutually exclusive in ' . $this->_context);
|
||||
$isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* The Link object represents a possible design-time link for a response.
|
||||
*
|
||||
* The presence of a link does not guarantee the caller's ability to successfully invoke it, rather it provides a known
|
||||
* relationship and traversal mechanism between responses and other operations.
|
||||
*
|
||||
* Unlike dynamic links (i.e. links provided in the response payload), the OA linking mechanism does not require
|
||||
* link information in the runtime response.
|
||||
*
|
||||
* For computing links, and providing instructions to execute them, a runtime expression is used for
|
||||
* accessing values in an operation and using them as parameters while invoking the linked operation.
|
||||
*
|
||||
* @see [Link Object](https://spec.openapis.org/oas/v3.1.1.html#link-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Link extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The key into MediaType->links array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $link = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A relative or absolute reference to an OA operation.
|
||||
*
|
||||
* This field is mutually exclusive of the <code>operationId</code> field, and must point to an Operation object.
|
||||
*
|
||||
* Relative values may be used to locate an existing Operation object in the OpenAPI definition.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $operationRef = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The name of an existing, resolvable OA operation, as defined with a unique <code>operationId</code>.
|
||||
*
|
||||
* This field is mutually exclusive of the <code>operationRef</code> field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $operationId = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map representing parameters to pass to an operation as specified with operationId or identified via
|
||||
* operationRef.
|
||||
*
|
||||
* The key is the parameter name to be used, whereas the value can be a constant or an expression to
|
||||
* be evaluated and passed to the linked operation.
|
||||
* The parameter name can be qualified using the parameter location [{in}.]{name} for operations
|
||||
* that use the same parameter name in different locations (e.g. path.id).
|
||||
*
|
||||
* @var array<string,mixed>
|
||||
*/
|
||||
public $parameters = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A literal value or {expression} to use as a request body when calling the target operation.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $requestBody = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A description of the link.
|
||||
*
|
||||
* CommonMark syntax may be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A server object to be used by the target operation.
|
||||
*
|
||||
* @var Server
|
||||
*/
|
||||
public $server = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Server::class => 'server',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Components::class,
|
||||
Response::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Each Media Type object provides schema and examples for the media type identified by its key.
|
||||
*
|
||||
* Parameter encodings can be set either here, or on nested `Property` annotations directly.
|
||||
*
|
||||
* @see [Media Type Object](https://spec.openapis.org/oas/v3.1.1.html#media-type-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class MediaType extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The key into Operation->content array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mediaType = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The schema defining the type used for the request body.
|
||||
*
|
||||
* @var Schema
|
||||
*/
|
||||
public $schema = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Example of the media type.
|
||||
*
|
||||
* The example object should be in the correct format as specified by the media type.
|
||||
* The example object is mutually exclusive of the examples object.
|
||||
*
|
||||
* Furthermore, if referencing a schema which contains an example,
|
||||
* the example value shall override the example provided by the schema.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $example = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Examples of the media type.
|
||||
*
|
||||
* Each example should contain a value in the correct format as specified in the parameter encoding.
|
||||
* The examples object is mutually exclusive of the example object.
|
||||
* Furthermore, if referencing a schema which contains an example, the examples value shall override the example provided by the schema.
|
||||
*
|
||||
* @var array<Examples>
|
||||
*/
|
||||
public $examples = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map between a property name and its encoding information.
|
||||
*
|
||||
* The key, being the property name, must exist in the schema as a property.
|
||||
*
|
||||
* The encoding object shall only apply to requestBody objects when the media type is multipart or
|
||||
* application/x-www-form-urlencoded.
|
||||
*
|
||||
* @var list<Encoding>
|
||||
*/
|
||||
public $encoding = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Schema::class => 'schema',
|
||||
Examples::class => ['examples', 'example'],
|
||||
Encoding::class => ['encoding', 'property'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Response::class,
|
||||
RequestBody::class,
|
||||
];
|
||||
|
||||
protected function encodingCompat($encoding, callable $factory)
|
||||
{
|
||||
if (!is_array($encoding)) {
|
||||
return $encoding;
|
||||
}
|
||||
|
||||
$compat = [];
|
||||
foreach ($encoding as $name => $value) {
|
||||
$compat[] = is_array($value) ? $factory([...$value, 'property' => $name]) : $value;
|
||||
}
|
||||
|
||||
return $compat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Generator;
|
||||
use OpenApi\OpenApiException;
|
||||
|
||||
/**
|
||||
* This is the root document object for the API specification.
|
||||
*
|
||||
* @see [OpenApi Object](https://spec.openapis.org/oas/v3.1.1.html#openapi-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class OpenApi extends AbstractAnnotation
|
||||
{
|
||||
public const VERSION_3_0_0 = '3.0.0';
|
||||
|
||||
public const VERSION_3_1_0 = '3.1.0';
|
||||
|
||||
public const VERSION_3_2_0 = '3.2.0';
|
||||
|
||||
public const DEFAULT_VERSION = self::VERSION_3_0_0;
|
||||
|
||||
public const SUPPORTED_VERSIONS = [
|
||||
self::VERSION_3_0_0, '3.0.1', '3.0.2', '3.0.3', '3.0.4',
|
||||
self::VERSION_3_1_0, '3.1.1', '3.1.2',
|
||||
self::VERSION_3_2_0,
|
||||
];
|
||||
|
||||
/**
|
||||
* The semantic version number of the OpenAPI Specification version that the OpenAPI document uses.
|
||||
*
|
||||
* The openapi field should be used by tooling specifications and clients to interpret the OpenAPI document.
|
||||
*
|
||||
* A version specified via <code>Generator::setVersion()</code> will overwrite this value.
|
||||
*
|
||||
* NOTE: This is not related to the API info::version string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $openapi = self::DEFAULT_VERSION;
|
||||
|
||||
/**
|
||||
* Provides metadata about the API. The metadata may be used by tooling as required.
|
||||
*
|
||||
* @var Info
|
||||
*/
|
||||
public $info = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An array of <code>@Server</code> objects, which provide connectivity information to a target server.
|
||||
*
|
||||
* If not provided, or is an empty array, the default value would be a Server Object with an url value of <code>/</code>.
|
||||
*
|
||||
* @var list<Server>
|
||||
*/
|
||||
public $servers = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The available paths and operations for the API.
|
||||
*
|
||||
* @var array<PathItem>
|
||||
*/
|
||||
public $paths = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An element to hold various components for the specification.
|
||||
*
|
||||
* @var Components
|
||||
*/
|
||||
public $components = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A declaration of which security mechanisms can be used across the API.
|
||||
*
|
||||
* The list of values includes alternative security requirement objects that can be used.
|
||||
* Only one of the security requirement objects need to be satisfied to authorize a request.
|
||||
* Individual operations can override this definition.
|
||||
* To make security optional, an empty security requirement (<code>{}</code>) can be included in the array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $security = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A list of tags used by the specification with additional metadata.
|
||||
*
|
||||
* The order of the tags can be used to reflect on their order by the parsing tools.
|
||||
* Not all tags that are used by the Operation Object must be declared.
|
||||
* The tags that are not declared may be organized randomly or based on the tools' logic.
|
||||
* Each tag name in the list must be unique.
|
||||
*
|
||||
* @var list<Tag>
|
||||
*/
|
||||
public $tags = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Additional external documentation.
|
||||
*
|
||||
* @var ExternalDocumentation
|
||||
*/
|
||||
public $externalDocs = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The available webhooks for the API.
|
||||
*
|
||||
* @since OpenAPI 3.1.0
|
||||
* @var list<Webhook>
|
||||
*/
|
||||
public $webhooks = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var Analysis
|
||||
*/
|
||||
public $_analysis = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['openapi', 'info'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Info::class => 'info',
|
||||
Server::class => ['servers'],
|
||||
PathItem::class => ['paths', 'path'],
|
||||
Components::class => 'components',
|
||||
Tag::class => ['tags'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Webhook::class => ['webhooks', 'webhook'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [];
|
||||
|
||||
public function __construct(array $properties)
|
||||
{
|
||||
parent::__construct($properties);
|
||||
|
||||
if ($this->_context->root()->version) {
|
||||
// override via `Generator::setVersion()`
|
||||
$this->openapi = $this->_context->root()->version;
|
||||
} else {
|
||||
$this->_context->root()->version = $this->openapi;
|
||||
}
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function validate(?Analysis $analysis = null, string $version = OpenApi::DEFAULT_VERSION, ?object $context = null): bool
|
||||
{
|
||||
$isValid = parent::validate($analysis, $version, $context);
|
||||
|
||||
if (!in_array($this->openapi, OpenApi::SUPPORTED_VERSIONS)) {
|
||||
$this->_context->logger->warning('Unsupported OpenAPI version "' . $this->openapi . '". Allowed versions are: ' . implode(', ', OpenApi::SUPPORTED_VERSIONS));
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
/* paths is optional in 3.1.x */
|
||||
if (OpenApi::versionMatch($version, '3.0.x') && Generator::isDefault($this->paths)) {
|
||||
$this->_context->logger->warning('Required @OA\PathItem() not found');
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
if (OpenApi::versionMatch($version, '3.1.x')
|
||||
&& Generator::isDefault($this->paths)
|
||||
&& Generator::isDefault($this->webhooks)
|
||||
&& Generator::isDefault($this->components)
|
||||
) {
|
||||
$this->_context->logger->warning('At least one of @OA\PathItem(), @OA\Components() or @OA\Webhook() required');
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare OpenApi version numbers.
|
||||
*
|
||||
* Allows patch version placeholder `x`; e.g. `3.1.x`.
|
||||
*/
|
||||
public static function versionMatch(string $version1, string $version2): bool
|
||||
{
|
||||
$expand = static function (string $v): array {
|
||||
if (!str_ends_with($v, '.x')) {
|
||||
return [$v];
|
||||
}
|
||||
$minor = str_replace('.x', '', $v);
|
||||
|
||||
return array_filter(self::SUPPORTED_VERSIONS, static fn (string $sv): bool => str_starts_with($sv, $minor));
|
||||
};
|
||||
$versions1 = $expand($version1);
|
||||
$versions2 = $expand($version2);
|
||||
|
||||
return array_intersect($versions1, $versions2) !== [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the OpenAPI documentation to a file.
|
||||
*/
|
||||
public function saveAs(string $filename, string $format = 'auto'): void
|
||||
{
|
||||
if ($format === 'auto') {
|
||||
$format = strtolower(substr($filename, -5)) === '.json' ? 'json' : 'yaml';
|
||||
}
|
||||
|
||||
$content = strtolower($format) === 'json' ? $this->toJson() : $this->toYaml();
|
||||
|
||||
if (file_put_contents($filename, $content) === false) {
|
||||
throw new OpenApiException('Failed to saveAs("' . $filename . '", "' . $format . '")');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an annotation with a $ref url.
|
||||
*
|
||||
* @param string $ref The $ref value; example: "#/components/schemas/Product"
|
||||
*/
|
||||
public function ref(string $ref)
|
||||
{
|
||||
if (!str_starts_with($ref, '#/')) {
|
||||
throw new OpenApiException('Unsupported $ref "' . $ref . '", it should start with "#/"');
|
||||
}
|
||||
|
||||
return self::resolveRef($ref, '#/', $this, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper for ref().
|
||||
*
|
||||
* @param array|AbstractAnnotation $container
|
||||
* @param array<class-string<AbstractAnnotation>,string|array<string>> $mapping
|
||||
*/
|
||||
private static function resolveRef(string $ref, string $resolved, $container, array $mapping)
|
||||
{
|
||||
if ($ref === $resolved) {
|
||||
return $container;
|
||||
}
|
||||
$path = substr($ref, strlen($resolved));
|
||||
$slash = strpos($path, '/');
|
||||
|
||||
$subpath = $slash === false ? $path : substr($path, 0, $slash);
|
||||
$property = Components::refDecode($subpath);
|
||||
$unresolved = $slash === false ? $resolved . $subpath : $resolved . $subpath . '/';
|
||||
|
||||
if (is_object($container)) {
|
||||
// support use x-* in ref
|
||||
$xKey = str_starts_with($property, 'x-') ? substr($property, 2) : null;
|
||||
if ($xKey) {
|
||||
if (!is_array($container->x) || !array_key_exists($xKey, $container->x)) {
|
||||
$xKey = null;
|
||||
}
|
||||
}
|
||||
if (property_exists($container, $property) === false && !$xKey) {
|
||||
throw new OpenApiException('$ref "' . $ref . '" not found');
|
||||
}
|
||||
|
||||
$nextContainer = $xKey ? $container->x[$xKey] : $container->{$property};
|
||||
|
||||
if ($slash === false) {
|
||||
return $nextContainer;
|
||||
}
|
||||
$mapping = [];
|
||||
foreach ($container::$_nested as $nestedClass => $nested) {
|
||||
if (is_string($nested) === false && count($nested) === 2 && $nested[0] === $property) {
|
||||
$mapping[$nestedClass] = $nested[1];
|
||||
}
|
||||
}
|
||||
|
||||
return self::resolveRef($ref, $unresolved, $nextContainer, $mapping);
|
||||
} elseif (is_array($container)) {
|
||||
if (array_key_exists($property, $container)) {
|
||||
return self::resolveRef($ref, $unresolved, $container[$property], []);
|
||||
}
|
||||
foreach ($mapping as $nestedClass => $keyField) {
|
||||
foreach ($container as $key => $item) {
|
||||
if (is_numeric($key) && is_object($item) && $item instanceof $nestedClass && (string) $item->{$keyField} === $property) {
|
||||
return self::resolveRef($ref, $unresolved, $item, []);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new OpenApiException('$ref "' . $unresolved . '" not found');
|
||||
}
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
if ($this->_context->isVersion('3.0.x')) {
|
||||
unset($data->webhooks);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Base class for <code>@OA\Get</code>, <code>@OA\Post</code>, <code>@OA\Put</code>, etc.
|
||||
*
|
||||
* Describes a single API operation on a path.
|
||||
*
|
||||
* @see [Operation Object](https://spec.openapis.org/oas/v3.1.1.html#operation-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
abstract class Operation extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* Key in the OpenApi "Paths Object" for this operation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $path = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A list of tags for API documentation control.
|
||||
*
|
||||
* Tags can be used for logical grouping of operations by resources or any other qualifier.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public $tags = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Key in the OpenApi "Path Item Object" for this operation.
|
||||
*
|
||||
* Allowed values: 'get', 'post', put', 'patch', 'delete', 'options', 'head' and 'trace'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $method = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A short summary of what the operation does.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $summary = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A verbose explanation of the operation behavior.
|
||||
*
|
||||
* CommonMark syntax MAY be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Additional external documentation for this operation.
|
||||
*
|
||||
* @var ExternalDocumentation
|
||||
*/
|
||||
public $externalDocs = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Unique string used to identify the operation.
|
||||
*
|
||||
* The id must be unique among all operations described in the API.
|
||||
* Tools and libraries may use the operationId to uniquely identify an operation, therefore, it is recommended to
|
||||
* follow common programming naming conventions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $operationId = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A list of parameters that are applicable for this operation.
|
||||
*
|
||||
* If a parameter is already defined at the Path Item, the new definition will override it but can never remove it.
|
||||
* The list must not include duplicated parameters.
|
||||
*
|
||||
* A unique parameter is defined by a combination of a name and location.
|
||||
*
|
||||
* The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object's
|
||||
* components/parameters.
|
||||
*
|
||||
* @var list<Parameter>
|
||||
*/
|
||||
public $parameters = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The request body applicable for this operation.
|
||||
*
|
||||
* The requestBody is only supported in HTTP methods where the HTTP 1.1 specification RFC7231 has explicitly
|
||||
* defined semantics for request bodies. In other cases where the HTTP spec is vague, requestBody shall be ignored
|
||||
* by consumers.
|
||||
*
|
||||
* @var RequestBody
|
||||
*/
|
||||
public $requestBody = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The list of possible responses as they are returned from executing this operation.
|
||||
*
|
||||
* @var list<Response>
|
||||
*/
|
||||
public $responses = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map of possible out-of band callbacks related to the parent operation.
|
||||
*
|
||||
* The key is a unique identifier for the Callback Object.
|
||||
*
|
||||
* Each value in the map is a Callback Object that describes a request that may be initiated by the API provider
|
||||
* and the expected responses. The key value used to identify the callback object is an expression, evaluated at
|
||||
* runtime, that identifies a URL to use for the callback operation.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $callbacks = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Declares this operation to be deprecated.
|
||||
*
|
||||
* Consumers should refrain from usage of the declared operation.
|
||||
*
|
||||
* Default value is false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $deprecated = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A declaration of which security mechanisms can be used for this operation.
|
||||
*
|
||||
* The list of values includes alternative security requirement objects that can be used.
|
||||
*
|
||||
* Only one of the security requirement objects need to be satisfied to authorize a request.
|
||||
*
|
||||
* This definition overrides any declared top-level security.
|
||||
* To remove a top-level security declaration, an empty array can be used.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $security = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An alternative server array to service this operation.
|
||||
*
|
||||
* If an alternative server object is specified at the Path Item Object or Root level, it will be overridden by
|
||||
* this value.
|
||||
*
|
||||
* @var list<Server>
|
||||
*/
|
||||
public $servers = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['responses'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'path' => 'string',
|
||||
'method' => 'string',
|
||||
'tags' => '[string]',
|
||||
'summary' => 'string',
|
||||
'description' => 'string',
|
||||
'deprecated' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Parameter::class => ['parameters'],
|
||||
PathParameter::class => ['parameters'],
|
||||
Response::class => ['responses', 'response'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Server::class => ['servers'],
|
||||
RequestBody::class => 'requestBody',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
unset($data->method);
|
||||
unset($data->path);
|
||||
|
||||
// ensure security elements are object
|
||||
if (isset($data->security) && is_array($data->security)) {
|
||||
foreach ($data->security as $key => $scheme) {
|
||||
$data->security[$key] = (object) $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function validate(?Analysis $analysis = null, string $version = OpenApi::DEFAULT_VERSION, ?object $context = null): bool
|
||||
{
|
||||
$isValid = parent::validate($analysis, $version, $context);
|
||||
|
||||
if (!Generator::isDefault($this->responses)) {
|
||||
foreach ($this->responses as $response) {
|
||||
if (!Generator::isDefault($response->response) && $response->response !== 'default' && preg_match('/^([12345]{1}\d{2})|([12345]{1}XX)$/', (string) $response->response) === 0) {
|
||||
$this->_context->logger->warning('Invalid value "' . $response->response . '" for ' . $response->identity([]) . '->response, expecting "default", a HTTP Status Code or HTTP Status Code range definition in ' . $response->_context);
|
||||
$isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Generator::isDefault($this->operationId)) {
|
||||
if (!property_exists($context, 'operationIds')) {
|
||||
$context->operationIds = [];
|
||||
}
|
||||
|
||||
if (in_array($this->operationId, $context->operationIds)) {
|
||||
$this->_context->logger->warning('operationId must be unique. Duplicate value found: "' . $this->operationId . '"');
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
$context->operationIds[] = $this->operationId;
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Options extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'options';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Describes a single operation parameter.
|
||||
*
|
||||
* A unique parameter is defined by a combination of a name and location.
|
||||
*
|
||||
* @see [Parameter Object](https://spec.openapis.org/oas/v3.1.1.html#parameter-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Parameter extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The relative or absolute path to the endpoint.
|
||||
*
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The key into <code>Components::parameters</code> or <code>PathItem::parameters</code> array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $parameter = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The (case-sensitive) name of the parameter.
|
||||
*
|
||||
* If in is "path", the name field must correspond to the associated path segment from the path field in the Paths Object.
|
||||
*
|
||||
* If in is "header" and the name field is "Accept", "Content-Type" or "Authorization", the parameter definition shall be ignored.
|
||||
* For all other cases, the name corresponds to the parameter name used by the in property.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The location of the parameter.
|
||||
*
|
||||
* Possible values are "query", "header", "path" or "cookie".
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $in = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A brief description of the parameter.
|
||||
*
|
||||
* This could contain examples of use.
|
||||
*
|
||||
* CommonMark syntax may be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Determines whether this parameter is mandatory.
|
||||
*
|
||||
* If the parameter location is "path", this property is required and its value must be true.
|
||||
* Otherwise, the property may be included and its default value is false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $required = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Specifies that a parameter is deprecated and should be transitioned out of usage.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $deprecated = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Sets the ability to pass empty-valued parameters.
|
||||
*
|
||||
* This is valid only for query parameters and allows sending a parameter with an empty value.
|
||||
*
|
||||
* Default value is false.
|
||||
*
|
||||
* If style is used, and if behavior is n/a (cannot be serialized), the value of allowEmptyValue shall be ignored.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $allowEmptyValue = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Describes how the parameter value will be serialized depending on the type of the parameter value.
|
||||
*
|
||||
* Default values (based on value of in): for query - form; for path - simple; for header - simple; for cookie - form.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $style = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* When this is true, parameter values of type array or object generate separate parameters for each value of the array or key-value pair of the map.
|
||||
*
|
||||
* For other types of parameters this property has no effect.
|
||||
*
|
||||
* When style is form, the default value is true.
|
||||
* For all other styles, the default value is false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $explode = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Determines whether the parameter value should allow reserved characters, as defined by RFC3986 :/?#[]@!$&'()*+,;= to be included without percent-encoding.
|
||||
*
|
||||
* This property only applies to parameters with an in value of query.
|
||||
*
|
||||
* The default value is false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $allowReserved = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The schema defining the type used for the parameter.
|
||||
*
|
||||
* @var Schema
|
||||
*/
|
||||
public $schema = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Example of the media type.
|
||||
*
|
||||
* The example should match the specified schema and encoding properties if present.
|
||||
* The example object is mutually exclusive of the examples object.
|
||||
* Furthermore, if referencing a schema which contains an example, the example value shall override the example provided by the schema.
|
||||
* To represent examples of media types that cannot naturally be represented in JSON or YAML, a string value can contain the example with escaping where necessary.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $example = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Examples of the parameter.
|
||||
*
|
||||
* Each example should contain a value in the correct format as specified in the parameter encoding.
|
||||
* The examples object is mutually exclusive of the example object.
|
||||
* Furthermore, if referencing a schema which contains an example, the examples value shall override the example provided by the schema.
|
||||
*
|
||||
* @var array<Examples>
|
||||
*/
|
||||
public $examples = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map containing the representations for the parameter.
|
||||
*
|
||||
* The key is the media type and the value describes it.
|
||||
* The map must only contain one entry.
|
||||
*
|
||||
* @var array<MediaType>|JsonContent|XmlContent|Attachable
|
||||
*/
|
||||
public $content = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Path-style parameters defined by RFC6570.
|
||||
*
|
||||
* @see [RFC6570](https://tools.ietf.org/html/rfc6570#section-3.2.7)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $matrix = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Label style parameters defined by RFC6570.
|
||||
*
|
||||
* @see [RFC6570](https://tools.ietf.org/html/rfc6570#section-3.2.5)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $label = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Form style parameters defined by RFC6570.
|
||||
*
|
||||
* This option replaces collectionFormat with a csv (when explode is false) or multi (when explode is true) value from OpenAPI 2.0.
|
||||
*
|
||||
* @see [RFC6570](https://tools.ietf.org/html/rfc6570#section-3.2.8)
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $form = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Simple style parameters defined by RFC6570.
|
||||
*
|
||||
* This option replaces collectionFormat with a csv value from OpenAPI 2.0.
|
||||
*
|
||||
* @see [RFC6570](https://tools.ietf.org/html/rfc6570#section-3.2.2)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $simple = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Space separated array values.
|
||||
*
|
||||
* This option replaces collectionFormat equal to ssv from OpenAPI 2.0.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $spaceDelimited = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Pipe separated array values.
|
||||
*
|
||||
* This option replaces collectionFormat equal to pipes from OpenAPI 2.0.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $pipeDelimited = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Provides a simple way of rendering nested objects using form parameters.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $deepObject = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['name', 'in'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'name' => 'string',
|
||||
'in' => ['query', 'header', 'path', 'cookie'],
|
||||
'description' => 'string',
|
||||
'style' => ['matrix', 'label', 'form', 'simple', 'spaceDelimited', 'pipeDelimited', 'deepObject'],
|
||||
'required' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Schema::class => 'schema',
|
||||
Examples::class => ['examples', 'example'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Components::class,
|
||||
PathItem::class,
|
||||
Operation::class,
|
||||
Get::class,
|
||||
Post::class,
|
||||
Put::class,
|
||||
Delete::class,
|
||||
Patch::class,
|
||||
Head::class,
|
||||
Options::class,
|
||||
Trace::class,
|
||||
];
|
||||
|
||||
#[\Override]
|
||||
public function validate(?Analysis $analysis = null, string $version = OpenApi::DEFAULT_VERSION, ?object $context = null): bool
|
||||
{
|
||||
$isValid = parent::validate($analysis, $version, $context);
|
||||
|
||||
if (Generator::isDefault($this->ref)) {
|
||||
if ($this->in === 'body') {
|
||||
if (Generator::isDefault($this->schema)) {
|
||||
$this->_context->logger->warning('Field "schema" is required when ' . $this->identity() . ' is in "' . $this->in . '" in ' . $this->_context);
|
||||
$isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function identity(?array $properties = []): string
|
||||
{
|
||||
return parent::identity(['name', 'in']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Patch extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'patch';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Describes the operations available on a single path.
|
||||
*
|
||||
* A Path Item may be empty, due to ACL constraints.
|
||||
* The path itself is still exposed to the documentation viewer, but they will not know which operations and parameters are available.
|
||||
*
|
||||
* @see [Path Item Object](https://spec.openapis.org/oas/v3.1.1.html#path-item-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class PathItem extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An optional, string summary, intended to apply to all operations in this path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $summary = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An optional, string description, intended to apply to all operations in this path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Key for the Path Object (OpenApi->paths array).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $path = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a GET operation on this path.
|
||||
*
|
||||
* @var Get
|
||||
*/
|
||||
public $get = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a PUT operation on this path.
|
||||
*
|
||||
* @var Put
|
||||
*/
|
||||
public $put = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a POST operation on this path.
|
||||
*
|
||||
* @var Post
|
||||
*/
|
||||
public $post = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a DELETE operation on this path.
|
||||
*
|
||||
* @var Delete
|
||||
*/
|
||||
public $delete = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a OPTIONS operation on this path.
|
||||
*
|
||||
* @var Options
|
||||
*/
|
||||
public $options = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a HEAD operation on this path.
|
||||
*
|
||||
* @var Head
|
||||
*/
|
||||
public $head = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a PATCH operation on this path.
|
||||
*
|
||||
* @var Patch
|
||||
*/
|
||||
public $patch = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a TRACE operation on this path.
|
||||
*
|
||||
* @var Trace
|
||||
*/
|
||||
public $trace = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A definition of a QUERY operation on this path.
|
||||
*
|
||||
* @since OpenAPI 3.2.0
|
||||
* @var Query
|
||||
*/
|
||||
public $query = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An alternative server array to service all operations in this path.
|
||||
*
|
||||
* @var list<Server>
|
||||
*/
|
||||
public $servers = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A list of parameters that are applicable for all the operations described under this path.
|
||||
*
|
||||
* These parameters can be overridden at the operation level, but cannot be removed there.
|
||||
* The list must not include duplicated parameters.
|
||||
* A unique parameter is defined by a combination of a name and location.
|
||||
* The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object's components/parameters.
|
||||
*
|
||||
* @var list<Parameter>
|
||||
*/
|
||||
public $parameters = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'path' => 'string',
|
||||
'summary' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Get::class => 'get',
|
||||
Post::class => 'post',
|
||||
Put::class => 'put',
|
||||
Delete::class => 'delete',
|
||||
Patch::class => 'patch',
|
||||
Trace::class => 'trace',
|
||||
Head::class => 'head',
|
||||
Options::class => 'options',
|
||||
Query::class => 'query',
|
||||
Parameter::class => ['parameters'],
|
||||
PathParameter::class => ['parameters'],
|
||||
Server::class => ['servers'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
OpenApi::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns a list of all operations (all methods) for this path item.
|
||||
*
|
||||
* @return list<Operation>
|
||||
*/
|
||||
public function operations(): array
|
||||
{
|
||||
$operations = [];
|
||||
foreach (PathItem::$_nested as $className => $property) {
|
||||
if (is_subclass_of($className, Operation::class) && !Generator::isDefault($this->{$property})) {
|
||||
$operations[] = $this->{$property};
|
||||
}
|
||||
}
|
||||
|
||||
return $operations;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
if ($this->_context->isVersion(['3.0.x', '3.1.x'])) {
|
||||
unset($data->query);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
* A <code>@OA\Request</code> path parameter.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class PathParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $in = 'path';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $required = true;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['name'];
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Post extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'post';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Property extends Schema
|
||||
{
|
||||
/**
|
||||
* The key into Schema->properties array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $property = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @var Encoding
|
||||
*/
|
||||
public $encoding = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
AdditionalProperties::class,
|
||||
Schema::class,
|
||||
JsonContent::class,
|
||||
XmlContent::class,
|
||||
Property::class,
|
||||
Items::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Discriminator::class => 'discriminator',
|
||||
Items::class => 'items',
|
||||
Property::class => ['properties', 'property'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Examples::class => ['examples', 'example'],
|
||||
Xml::class => 'xml',
|
||||
AdditionalProperties::class => 'additionalProperties',
|
||||
Encoding::class => 'encoding',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
unset($data->encoding);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Put extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'put';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @since OpenAPI 3.2.0
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Query extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'query';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
* A <code>@OA\Request</code> query parameter.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class QueryParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* This takes 'query' as the default location
|
||||
*/
|
||||
public $in = 'query';
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Attributes\JsonContent;
|
||||
use OpenApi\Attributes\XmlContent;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Describes a single request body.
|
||||
*
|
||||
* @see [Request Body Object](https://spec.openapis.org/oas/v3.1.1.html#request-body-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class RequestBody extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The relative or absolute path to a request body.
|
||||
*
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The key into Components->requestBodies array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $request = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A brief description of the parameter.
|
||||
*
|
||||
* This could contain examples of use.
|
||||
*
|
||||
* CommonMark syntax may be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Determines whether this parameter is mandatory.
|
||||
*
|
||||
* If the parameter location is "path", this property is required and its value must be true.
|
||||
* Otherwise, the property may be included and its default value is false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $required = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The content of the request body.
|
||||
*
|
||||
* The key is a media type or media type range and the value describes it. For requests that match multiple keys,
|
||||
* only the most specific key is applicable. e.g. text/plain overrides text/*.
|
||||
*
|
||||
* @var array<MediaType|JsonContent|XmlContent>|MediaType|JsonContent|XmlContent|Attachable
|
||||
*/
|
||||
public $content = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'description' => 'string',
|
||||
'required' => 'boolean',
|
||||
'request' => 'string',
|
||||
];
|
||||
|
||||
public static $_parents = [
|
||||
Components::class,
|
||||
Delete::class,
|
||||
Get::class,
|
||||
Head::class,
|
||||
Operation::class,
|
||||
Options::class,
|
||||
Patch::class,
|
||||
Post::class,
|
||||
Trace::class,
|
||||
Put::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
MediaType::class => ['content', 'mediaType'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
unset($data->request);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Describes a single response from an API Operation, including design-time,
|
||||
* static links to operations based on the response.
|
||||
*
|
||||
* @see [Response Object](https://spec.openapis.org/oas/v3.1.1.html#response-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Response extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The relative or absolute path to a response.
|
||||
*
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The key into Operations->responses array.
|
||||
*
|
||||
* A HTTP status code or <code>default</code>.
|
||||
*
|
||||
* @var string|int
|
||||
*/
|
||||
public $response = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A short description of the response.
|
||||
*
|
||||
* CommonMark syntax may be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Maps a header name to its definition.
|
||||
*
|
||||
* RFC7230 states header names are case-insensitive.
|
||||
*
|
||||
* If a response header is defined with the name "Content-Type", it shall be ignored.
|
||||
*
|
||||
* @see [RFC7230](https://tools.ietf.org/html/rfc7230#page-22)
|
||||
*
|
||||
* @var list<Header>
|
||||
*/
|
||||
public $headers = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map containing descriptions of potential response payloads.
|
||||
*
|
||||
* The key is a media type or media type range and the value describes it.
|
||||
*
|
||||
* For responses that match multiple keys, only the most specific key is applicable;
|
||||
* e.g. <code>text/plain</code> overrides <code>text/*</code>.
|
||||
*
|
||||
* @var MediaType|JsonContent|XmlContent|Attachable|array<MediaType|JsonContent|XmlContent|Attachable>
|
||||
*/
|
||||
public $content = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map of operations links that can be followed from the response.
|
||||
*
|
||||
* The key of the map is a short name for the link, following the naming constraints of the names for Component
|
||||
* Objects.
|
||||
*
|
||||
* @var list<Link>
|
||||
*/
|
||||
public $links = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'description' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
MediaType::class => ['content', 'mediaType'],
|
||||
Header::class => ['headers', 'header'],
|
||||
Link::class => ['links', 'link'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Components::class,
|
||||
Operation::class,
|
||||
Get::class,
|
||||
Post::class,
|
||||
Put::class,
|
||||
Patch::class,
|
||||
Delete::class,
|
||||
Head::class,
|
||||
Options::class,
|
||||
Trace::class,
|
||||
];
|
||||
|
||||
#[\Override]
|
||||
public function validate(?Analysis $analysis = null, string $version = OpenApi::DEFAULT_VERSION, ?object $context = null): bool
|
||||
{
|
||||
$isValid = parent::validate($analysis, $version, $context);
|
||||
|
||||
if (Generator::isDefault($this->description) && Generator::isDefault($this->ref)) {
|
||||
$this->_context->logger->warning($this->identity() . ' One of description or ref is required in ' . $this->_context);
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Analysis;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* The definition of input and output data types.
|
||||
*
|
||||
* These types can be objects, but also primitives and arrays.
|
||||
*
|
||||
* This object is based on the [JSON Schema Specification](http://json-schema.org) and uses a predefined subset of it.
|
||||
* On top of this subset, there are extensions provided by this specification to allow for more complete documentation.
|
||||
*
|
||||
* @see [Schema Object](https://spec.openapis.org/oas/v3.1.1.html#schema-object)
|
||||
* @see [JSON Schema](http://json-schema.org/)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Schema extends AbstractAnnotation
|
||||
{
|
||||
use JsonSchemaTrait;
|
||||
|
||||
/**
|
||||
* The relative or absolute path to the endpoint.
|
||||
*
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The key into Components->schemas array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $schema = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Can be used to decorate a user interface with information about the data produced by this user interface.
|
||||
*
|
||||
* Preferably short; use <code>description</code> for more details.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $title = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A description will provide explanation about the purpose of the instance described by this schema.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The maximum number of properties allowed in an object instance.
|
||||
* An object instance is valid against this property if its number of properties is less than, or equal to, the
|
||||
* value of this attribute.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $maxProperties = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The minimum number of properties allowed in an object instance.
|
||||
* An object instance is valid against this property if its number of properties is greater than, or equal to, the
|
||||
* value of this attribute.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $minProperties = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An object instance is valid against this property if its property set contains all elements in this property's
|
||||
* array value.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public $required = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A collection of properties to define for an object.
|
||||
*
|
||||
* Each property is represented as an instance of the <a href="#property">Property</a> class.
|
||||
*
|
||||
* @var list<Property>
|
||||
*/
|
||||
public $properties = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The type of the schema/property.
|
||||
*
|
||||
* OpenApi v3.0: The value MUST be one of "string", "number", "integer", "boolean", "array" or "object".
|
||||
*
|
||||
* Since OpenApi v3.1 an array of types may be used.
|
||||
*
|
||||
* @var string|non-empty-array<string>
|
||||
*/
|
||||
public $type = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The extending format for the previously mentioned type.
|
||||
*
|
||||
* @see [Data Types](https://spec.openapis.org/oas/v3.1.1.html#data-types)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $format = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Required if type is "array". Describes the type of items in the array.
|
||||
*
|
||||
* @var Items
|
||||
*/
|
||||
public $items = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Determines the format of the array if type array is used.
|
||||
*
|
||||
* Possible values are:
|
||||
* - csv: comma separated values foo,bar.
|
||||
* - ssv: space separated values foo bar.
|
||||
* - tsv: tab separated values foo\tbar.
|
||||
* - pipes: pipe separated values foo|bar.
|
||||
* - multi: corresponds to multiple parameter instances instead of multiple values for a single instance
|
||||
* foo=bar&foo=baz. This is valid only for parameters of type <code>query</code> or <code>formData</code>. Default
|
||||
* value is csv.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $collectionFormat = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A string instance is considered valid if the regular expression matches the instance successfully.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $pattern = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A numeric instance is valid against "multipleOf" if the result of the division of the instance by this
|
||||
* property's value is an integer.
|
||||
*
|
||||
* @var int|float
|
||||
*/
|
||||
public $multipleOf = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Adds support for polymorphism.
|
||||
*
|
||||
* The discriminator is an object name that is used to differentiate between other schemas which may satisfy the
|
||||
* payload description. See Composition and Inheritance for more details.
|
||||
*
|
||||
* @var Discriminator
|
||||
*/
|
||||
public $discriminator = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Declares the property as "read only".
|
||||
*
|
||||
* Relevant only for Schema "properties" definitions.
|
||||
*
|
||||
* This means that it may be sent as part of a response but should not be sent as part of the request.
|
||||
* If the property is marked as readOnly being true and is in the required list, the required will take effect on
|
||||
* the response only. A property must not be marked as both readOnly and writeOnly being true. Default value is
|
||||
* false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $readOnly = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Declares the property as "write only".
|
||||
*
|
||||
* Relevant only for Schema "properties" definitions.
|
||||
* Therefore, it may be sent as part of a request but should not be sent as part of the response.
|
||||
* If the property is marked as writeOnly being true and is in the required list, the required will take effect on
|
||||
* the request only. A property must not be marked as both readOnly and writeOnly being true. Default value is
|
||||
* false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $writeOnly = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* This may be used only on properties schemas.
|
||||
*
|
||||
* It has no effect on root schemas.
|
||||
* Adds additional metadata to describe the XML representation of this property.
|
||||
*
|
||||
* @var Xml
|
||||
*/
|
||||
public $xml = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Additional external documentation for this schema.
|
||||
*
|
||||
* @var ExternalDocumentation
|
||||
*/
|
||||
public $externalDocs = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A free-form property to include an example of an instance for this schema.
|
||||
*
|
||||
* To represent examples that cannot naturally be represented in JSON or YAML, a string value can be used to
|
||||
* contain the example with escaping where necessary.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $example = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Examples of the schema.
|
||||
*
|
||||
* Each example should contain a value in the correct format as specified in the parameter encoding.
|
||||
* The examples object is mutually exclusive of the example object.
|
||||
* Furthermore, if referencing a schema which contains an example, the examples value shall override the example provided by the schema.
|
||||
*
|
||||
* @since OpenAPI 3.1.0
|
||||
* @var array<Examples>
|
||||
*/
|
||||
public $examples = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Allows sending a null value for the defined schema.
|
||||
* Default value is false.
|
||||
*
|
||||
* This must not be used when using OpenApi version 3.1,
|
||||
* instead make the "type" property an array and add "null" as a possible type.
|
||||
*
|
||||
* @var bool
|
||||
*
|
||||
* @see https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
|
||||
*/
|
||||
public $nullable = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Specifies that a schema is deprecated and should be transitioned out of usage.
|
||||
* Default value is false.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $deprecated = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An instance validates successfully against this property if it validates successfully against all schemas
|
||||
* defined by this property's value.
|
||||
*
|
||||
* @var array<Schema|\OpenApi\Attributes\Schema>
|
||||
*/
|
||||
public $allOf = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An instance validates successfully against this property if it validates successfully against at least one
|
||||
* schema defined by this property's value.
|
||||
*
|
||||
* @var array<Schema|\OpenApi\Attributes\Schema>
|
||||
*/
|
||||
public $anyOf = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An instance validates successfully against this property if it validates successfully against exactly one schema
|
||||
* defined by this property's value.
|
||||
*
|
||||
* @var array<Schema|\OpenApi\Attributes\Schema>
|
||||
*/
|
||||
public $oneOf = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* https://spec.openapis.org/oas/v3.1.0.html#considerations-for-file-uploads
|
||||
* https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.8.3.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $contentEncoding = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* https://spec.openapis.org/oas/v3.1.0.html#considerations-for-file-uploads
|
||||
* https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.8.4.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $contentMediaType = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'title' => 'string',
|
||||
'description' => 'string',
|
||||
'required' => '[string]',
|
||||
'format' => 'string',
|
||||
'collectionFormat' => ['csv', 'ssv', 'tsv', 'pipes', 'multi'],
|
||||
'maximum' => 'number',
|
||||
'exclusiveMaximum' => 'boolean|number',
|
||||
'minimum' => 'number',
|
||||
'exclusiveMinimum' => 'boolean|number',
|
||||
'maxLength' => 'integer',
|
||||
'minLength' => 'integer',
|
||||
'pattern' => 'string',
|
||||
'maxItems' => 'integer',
|
||||
'minItems' => 'integer',
|
||||
'uniqueItems' => 'boolean',
|
||||
'multipleOf' => 'integer',
|
||||
'allOf' => '[' . Schema::class . ']',
|
||||
'oneOf' => '[' . Schema::class . ']',
|
||||
'anyOf' => '[' . Schema::class . ']',
|
||||
'contentEncoding' => 'string',
|
||||
'contentMediaType' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Discriminator::class => 'discriminator',
|
||||
Items::class => 'items',
|
||||
Property::class => ['properties', 'property'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Examples::class => ['examples', 'example'],
|
||||
Xml::class => 'xml',
|
||||
AdditionalProperties::class => 'additionalProperties',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Components::class,
|
||||
Parameter::class,
|
||||
PathParameter::class,
|
||||
MediaType::class,
|
||||
Header::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Type safe nullable check.
|
||||
*
|
||||
* Defaults to `false` when nullable is not set.
|
||||
*/
|
||||
public function isNullable(): bool
|
||||
{
|
||||
return !Generator::isDefault($this->nullable) && $this->nullable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given type is valid for this schema.
|
||||
*/
|
||||
public function hasType(string $type): bool
|
||||
{
|
||||
return in_array($type, (array) $this->type, strict: true);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
if ($this->_context->isVersion('3.0.x')) {
|
||||
unset($data->examples);
|
||||
if (isset($data->const)) {
|
||||
$data->enum = [$data->const];
|
||||
unset($data->const);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function validate(?Analysis $analysis = null, string $version = OpenApi::DEFAULT_VERSION, ?object $context = null): bool
|
||||
{
|
||||
$isValid = parent::validate($analysis, $version, $context);
|
||||
|
||||
if ($this->hasType('array') && Generator::isDefault($this->items)) {
|
||||
$this->_context->logger->warning('@OA\\Items() is required when ' . $this->identity() . ' has type "array" in ' . $this->_context);
|
||||
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
if (OpenApi::versionMatch($version, '3.0.x')) {
|
||||
if (!Generator::isDefault($this->examples)) {
|
||||
$this->_context->logger->warning(static::shorten(static::class) . '::examples is only allowed as of 3.1.0 in ' . $this->_context);
|
||||
$isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* @see [Security Scheme Object](https://spec.openapis.org/oas/v3.1.1.html#security-scheme-object-0)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class SecurityScheme extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The relative or absolute path to a security scheme.
|
||||
*
|
||||
* @see [Reference Object](https://spec.openapis.org/oas/v3.1.1.html#reference-object)
|
||||
*
|
||||
* @var string|class-string|object
|
||||
*/
|
||||
public $ref = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The key into OpenApi->security array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $securityScheme = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The type of the security scheme.
|
||||
*
|
||||
* @var string|non-empty-array<string>
|
||||
*/
|
||||
public $type = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A short description for security scheme.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The name of the header or query parameter to be used.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Required The location of the API key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $in = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The flow used by the OAuth2 security scheme.
|
||||
*
|
||||
* @var list<Flow>
|
||||
*/
|
||||
public $flows = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A hint to the client to identify how the bearer token is formatted.
|
||||
*
|
||||
* Bearer tokens are usually generated by an authorization server, so this information is primarily for documentation purposes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $bearerFormat = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The name of the HTTP Authorization scheme.
|
||||
*
|
||||
* @see [RFC7235](https://tools.ietf.org/html/rfc7235#section-5.1)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $scheme = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of a URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $openIdConnectUrl = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['securityScheme', 'type'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'type' => ['http', 'apiKey', 'oauth2', 'openIdConnect'],
|
||||
'description' => 'string',
|
||||
'name' => 'string',
|
||||
'bearerFormat' => 'string',
|
||||
'in' => ['query', 'header', 'cookie'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Flow::class => ['flows', 'flow'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Components::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function merge(array $annotations, bool $ignore = false): array
|
||||
{
|
||||
$unmerged = parent::merge($annotations, $ignore);
|
||||
|
||||
if ($this->type === 'oauth2') {
|
||||
$this->name = Generator::UNDEFINED;
|
||||
}
|
||||
|
||||
return $unmerged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* An object representing a server.
|
||||
*
|
||||
* @see [Server Object](https://spec.openapis.org/oas/v3.1.1.html#server-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Server extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* An URL to the target host.
|
||||
*
|
||||
* This URL supports Server Variables and may be relative,
|
||||
* to indicate that the host location is relative to the location where the OpenAPI document is being served.
|
||||
* Variable substitutions will be made when a variable is named in {brackets}.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An optional string describing the host designated by the URL.
|
||||
*
|
||||
* CommonMark syntax may be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map between a variable name and its value.
|
||||
*
|
||||
* The value is used for substitution in the server's URL template.
|
||||
*
|
||||
* @var list<ServerVariable>
|
||||
*/
|
||||
public $variables = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
OpenApi::class,
|
||||
PathItem::class,
|
||||
Operation::class,
|
||||
Get::class,
|
||||
Post::class,
|
||||
Put::class,
|
||||
Delete::class,
|
||||
Patch::class,
|
||||
Head::class,
|
||||
Options::class,
|
||||
Trace::class,
|
||||
Link::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
ServerVariable::class => ['variables', 'serverVariable'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['url'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'url' => 'string',
|
||||
'description' => 'string',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* An object representing a server variable for server URL template substitution.
|
||||
*
|
||||
* @see [Server Variable Object](https://spec.openapis.org/oas/v3.1.1.html#server-variable-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class ServerVariable extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The key into Server->variables array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $serverVariable = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An enumeration of values to be used if the substitution options are from a limited set.
|
||||
*
|
||||
* @var list<string|int|float|bool|\UnitEnum>|class-string
|
||||
*/
|
||||
public $enum = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The default value to use for substitution, and to send, if an alternate value is not supplied.
|
||||
*
|
||||
* Unlike the Schema Object's default, this value must be provided by the consumer.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $default = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A map between a variable name and its value.
|
||||
*
|
||||
* The value is used for substitution in the server's URL template.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $variables = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* An optional description for the server variable.
|
||||
*
|
||||
* CommonMark syntax MAY be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
Server::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['default'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'default' => 'string',
|
||||
'description' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* @see [Tag Object](https://spec.openapis.org/oas/v3.1.1.html#tag-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Tag extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* The name of the tag.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A short description for the tag. GFM syntax can be used for rich text representation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* A short summary for display purposes.
|
||||
*
|
||||
* @since OpenAPI 3.2.0
|
||||
* @var string
|
||||
*/
|
||||
public $summary = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Additional external documentation for this tag.
|
||||
*
|
||||
* @var ExternalDocumentation
|
||||
*/
|
||||
public $externalDocs = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Name of the parent tag.
|
||||
*
|
||||
* @since OpenAPI 3.2.0
|
||||
* @var string
|
||||
*/
|
||||
public $parent = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Machine-readable category.
|
||||
*
|
||||
* @since OpenAPI 3.2.0
|
||||
* @var string
|
||||
*/
|
||||
public $kind = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['name'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'name' => 'string',
|
||||
'description' => 'string',
|
||||
'summary' => 'string',
|
||||
'parent' => 'string',
|
||||
'kind' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
OpenApi::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
|
||||
public function jsonSerialize(): \stdClass
|
||||
{
|
||||
$data = parent::jsonSerialize();
|
||||
|
||||
if ($this->_context->isVersion(['3.0.x', '3.1.x'])) {
|
||||
unset($data->summary);
|
||||
unset($data->parent);
|
||||
unset($data->kind);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Trace extends Operation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $method = 'trace';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
PathItem::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Acts like a <code>PathItem</code> with the main difference being that it requires <code>webhook</code> instead of <code>path</code>.
|
||||
*
|
||||
* @since OpenAPI 3.1.0
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Webhook extends PathItem
|
||||
{
|
||||
/**
|
||||
* Key for the webhooks map.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $webhook = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_required = ['webhook'];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
OpenApi::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'webhook' => 'string',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* @see [XML Object](https://spec.openapis.org/oas/v3.1.1.html#xml-object)
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Xml extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* Replaces the name of the element/attribute used for the described schema property.
|
||||
*
|
||||
* When defined within the Items Object (items), it will affect the name of the individual XML elements within the list.
|
||||
* When defined alongside type being array (outside the items), it will affect the wrapping element
|
||||
* and only if wrapped is <code>true</code>.
|
||||
*
|
||||
* If wrapped is <code>false</code>, it will be ignored.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The URL of the namespace definition. Value SHOULD be in the form of a URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $namespace = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* The prefix to be used for the name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $prefix = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* Declares whether the property definition translates to an attribute instead of an element.
|
||||
*
|
||||
* Default value is <code>false</code>.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $attribute = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* MAY be used only for an array definition.
|
||||
*
|
||||
* Signifies whether the array is wrapped (for example <code><books><book/><book/></books></code>)
|
||||
* or unwrapped (<code><book/><book/></code>).
|
||||
*
|
||||
* Default value is false. The definition takes effect only when defined alongside type being array (outside the items).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $wrapped = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_types = [
|
||||
'name' => 'string',
|
||||
'namespace' => 'string',
|
||||
'prefix' => 'string',
|
||||
'attribute' => 'boolean',
|
||||
'wrapped' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [
|
||||
AdditionalProperties::class,
|
||||
Schema::class,
|
||||
Property::class,
|
||||
Schema::class,
|
||||
Items::class,
|
||||
XmlContent::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Annotations;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Shorthand for a xml response.
|
||||
*
|
||||
* Use as <code>@OA\Schema</code> inside a <code>Response</code> and <code>MediaType</code>-><code>'application/xml'</code> will be generated.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class XmlContent extends Schema
|
||||
{
|
||||
/**
|
||||
* A map between a property name and its encoding information.
|
||||
*
|
||||
* @var list<Encoding>
|
||||
*/
|
||||
public $encoding = Generator::UNDEFINED;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_parents = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static $_nested = [
|
||||
Discriminator::class => 'discriminator',
|
||||
Items::class => 'items',
|
||||
Property::class => ['properties', 'property'],
|
||||
ExternalDocumentation::class => 'externalDocs',
|
||||
Xml::class => 'xml',
|
||||
AdditionalProperties::class => 'additionalProperties',
|
||||
Encoding::class => ['encoding', 'property'],
|
||||
Examples::class => ['examples', 'example'],
|
||||
Attachable::class => ['attachables'],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class AdditionalProperties extends OA\AdditionalProperties
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param list<string> $required
|
||||
* @param list<Property> $properties
|
||||
* @param string|non-empty-array<string>|null $type
|
||||
* @param array<Examples> $examples
|
||||
* @param array<Schema|OA\Schema> $allOf
|
||||
* @param array<Schema|OA\Schema> $anyOf
|
||||
* @param array<Schema|OA\Schema> $oneOf
|
||||
* @param list<string|int|float|bool|\UnitEnum|null>|class-string|null $enum
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
// Schema
|
||||
string|object|null $ref = null,
|
||||
?string $schema = null,
|
||||
?string $title = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?int $maxProperties = null,
|
||||
?int $minProperties = null,
|
||||
?array $required = null,
|
||||
?array $properties = null,
|
||||
string|array|null $type = null,
|
||||
?string $format = null,
|
||||
?Items $items = null,
|
||||
?string $collectionFormat = null,
|
||||
?string $pattern = null,
|
||||
?Discriminator $discriminator = null,
|
||||
?bool $readOnly = null,
|
||||
?bool $writeOnly = null,
|
||||
?Xml $xml = null,
|
||||
?ExternalDocumentation $externalDocs = null,
|
||||
mixed $example = Generator::UNDEFINED,
|
||||
?array $examples = null,
|
||||
?bool $nullable = null,
|
||||
?bool $deprecated = null,
|
||||
?array $allOf = null,
|
||||
?array $anyOf = null,
|
||||
?array $oneOf = null,
|
||||
?string $contentEncoding = null,
|
||||
?string $contentMediaType = null,
|
||||
|
||||
// JSON Schema
|
||||
mixed $default = Generator::UNDEFINED,
|
||||
int|float|null $maximum = null,
|
||||
bool|int|float|null $exclusiveMaximum = null,
|
||||
int|float|null $minimum = null,
|
||||
bool|int|float|null $exclusiveMinimum = null,
|
||||
int|null $maxLength = null,
|
||||
int|null $minLength = null,
|
||||
int|null $maxItems = null,
|
||||
int|null $minItems = null,
|
||||
bool|null $uniqueItems = null,
|
||||
array|string|null $enum = null,
|
||||
mixed $not = Generator::UNDEFINED,
|
||||
bool|AdditionalProperties|null $additionalProperties = null,
|
||||
array|null $additionalItems = null,
|
||||
array|null $contains = null,
|
||||
array|null $patternProperties = null,
|
||||
array|null $unevaluatedProperties = null,
|
||||
mixed $dependencies = Generator::UNDEFINED,
|
||||
mixed $propertyNames = Generator::UNDEFINED,
|
||||
mixed $const = Generator::UNDEFINED,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
// Schema
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'schema' => $schema ?? Generator::UNDEFINED,
|
||||
'title' => $title ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'maxProperties' => $maxProperties ?? Generator::UNDEFINED,
|
||||
'minProperties' => $minProperties ?? Generator::UNDEFINED,
|
||||
'required' => $required ?? Generator::UNDEFINED,
|
||||
'properties' => $properties ?? Generator::UNDEFINED,
|
||||
'type' => $type ?? Generator::UNDEFINED,
|
||||
'format' => $format ?? Generator::UNDEFINED,
|
||||
'collectionFormat' => $collectionFormat ?? Generator::UNDEFINED,
|
||||
'pattern' => $pattern ?? Generator::UNDEFINED,
|
||||
'readOnly' => $readOnly ?? Generator::UNDEFINED,
|
||||
'writeOnly' => $writeOnly ?? Generator::UNDEFINED,
|
||||
'xml' => $xml ?? Generator::UNDEFINED,
|
||||
'example' => $example,
|
||||
'nullable' => $nullable ?? Generator::UNDEFINED,
|
||||
'deprecated' => $deprecated ?? Generator::UNDEFINED,
|
||||
'allOf' => $allOf ?? Generator::UNDEFINED,
|
||||
'anyOf' => $anyOf ?? Generator::UNDEFINED,
|
||||
'oneOf' => $oneOf ?? Generator::UNDEFINED,
|
||||
'contentEncoding' => $contentEncoding ?? Generator::UNDEFINED,
|
||||
'contentMediaType' => $contentMediaType ?? Generator::UNDEFINED,
|
||||
|
||||
// JSON Schema
|
||||
'default' => $default,
|
||||
'maximum' => $maximum ?? Generator::UNDEFINED,
|
||||
'exclusiveMaximum' => $exclusiveMaximum ?? Generator::UNDEFINED,
|
||||
'minimum' => $minimum ?? Generator::UNDEFINED,
|
||||
'exclusiveMinimum' => $exclusiveMinimum ?? Generator::UNDEFINED,
|
||||
'maxLength' => $maxLength ?? Generator::UNDEFINED,
|
||||
'minLength' => $minLength ?? Generator::UNDEFINED,
|
||||
'maxItems' => $maxItems ?? Generator::UNDEFINED,
|
||||
'minItems' => $minItems ?? Generator::UNDEFINED,
|
||||
'uniqueItems' => $uniqueItems ?? Generator::UNDEFINED,
|
||||
'enum' => $enum ?? Generator::UNDEFINED,
|
||||
'not' => $not,
|
||||
'additionalProperties' => $additionalProperties ?? Generator::UNDEFINED,
|
||||
'additionalItems' => $additionalItems ?? Generator::UNDEFINED,
|
||||
'contains' => $contains ?? Generator::UNDEFINED,
|
||||
'patternProperties' => $patternProperties ?? Generator::UNDEFINED,
|
||||
'unevaluatedProperties' => $unevaluatedProperties ?? Generator::UNDEFINED,
|
||||
'dependencies' => $dependencies,
|
||||
'propertyNames' => $propertyNames,
|
||||
'const' => $const,
|
||||
|
||||
// abstract annotation
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($items, $discriminator, $externalDocs, $examples),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_ALL | \Attribute::IS_REPEATABLE)]
|
||||
class Attachable extends OA\Attachable
|
||||
{
|
||||
public function __construct(array $properties = [])
|
||||
{
|
||||
parent::__construct($properties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Components extends OA\Components
|
||||
{
|
||||
/**
|
||||
* @param array<Schema|OA\Schema>|null $schemas
|
||||
* @param list<Response>|null $responses
|
||||
* @param list<Parameter>|null $parameters
|
||||
* @param list<RequestBody>|null $requestBodies
|
||||
* @param array<Examples>|null $examples
|
||||
* @param list<Header>|null $headers
|
||||
* @param list<SecurityScheme>|null $securitySchemes
|
||||
* @param list<Link>|null $links
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?array $schemas = null,
|
||||
?array $responses = null,
|
||||
?array $parameters = null,
|
||||
?array $requestBodies = null,
|
||||
?array $examples = null,
|
||||
?array $headers = null,
|
||||
?array $securitySchemes = null,
|
||||
?array $links = null,
|
||||
?array $callbacks = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'callbacks' => $callbacks ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($schemas, $responses, $parameters, $examples, $requestBodies, $headers, $securitySchemes, $links),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Contact extends OA\Contact
|
||||
{
|
||||
/**
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
?string $url = null,
|
||||
?string $email = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'name' => $name ?? Generator::UNDEFINED,
|
||||
'url' => $url ?? Generator::UNDEFINED,
|
||||
'email' => $email ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)]
|
||||
class CookieParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $in = 'cookie';
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Delete extends OA\Delete
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Discriminator extends OA\Discriminator
|
||||
{
|
||||
/**
|
||||
* @param array<string,string>|null $mapping
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $propertyName = null,
|
||||
?array $mapping = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'propertyName' => $propertyName ?? Generator::UNDEFINED,
|
||||
'mapping' => $mapping ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Encoding extends OA\Encoding
|
||||
{
|
||||
/**
|
||||
* @param list<Header> $headers
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $property = null,
|
||||
?string $contentType = null,
|
||||
?array $headers = null,
|
||||
?string $style = null,
|
||||
?bool $explode = null,
|
||||
?bool $allowReserved = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'property' => $property ?? Generator::UNDEFINED,
|
||||
'contentType' => $contentType ?? Generator::UNDEFINED,
|
||||
'style' => $style ?? Generator::UNDEFINED,
|
||||
'explode' => $explode ?? Generator::UNDEFINED,
|
||||
'allowReserved' => $allowReserved ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($headers),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||
class Examples extends OA\Examples
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $example = null,
|
||||
?string $summary = Generator::UNDEFINED,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
int|string|array|null $value = null,
|
||||
?string $externalValue = null,
|
||||
string|object|null $ref = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'example' => $example ?? Generator::UNDEFINED,
|
||||
'summary' => $summary,
|
||||
'description' => $description,
|
||||
'value' => $value ?? Generator::UNDEFINED,
|
||||
'externalValue' => $externalValue ?? Generator::UNDEFINED,
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class ExternalDocumentation extends OA\ExternalDocumentation
|
||||
{
|
||||
/**
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?string $url = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'description' => $description,
|
||||
'url' => $url ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Flow extends OA\Flow
|
||||
{
|
||||
/**
|
||||
* @param 'implicit'|'password'|'authorizationCode'|'clientCredentials'|null $flow
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $authorizationUrl = null,
|
||||
?string $tokenUrl = null,
|
||||
?string $refreshUrl = null,
|
||||
?string $flow = null,
|
||||
?array $scopes = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'authorizationUrl' => $authorizationUrl ?? Generator::UNDEFINED,
|
||||
'tokenUrl' => $tokenUrl ?? Generator::UNDEFINED,
|
||||
'refreshUrl' => $refreshUrl ?? Generator::UNDEFINED,
|
||||
'flow' => $flow ?? Generator::UNDEFINED,
|
||||
'scopes' => $scopes ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Get extends OA\Get
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Head extends OA\Head
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Header extends OA\Header
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
string|object|null $ref = null,
|
||||
?string $header = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?bool $required = null,
|
||||
?Schema $schema = null,
|
||||
?bool $deprecated = null,
|
||||
?bool $allowEmptyValue = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'header' => $header ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'required' => $required ?? Generator::UNDEFINED,
|
||||
'deprecated' => $deprecated ?? Generator::UNDEFINED,
|
||||
'allowEmptyValue' => $allowEmptyValue ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($schema),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)]
|
||||
class HeaderParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $in = 'header';
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class Info extends OA\Info
|
||||
{
|
||||
/**
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $version = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?string $title = null,
|
||||
?string $termsOfService = null,
|
||||
?Contact $contact = null,
|
||||
?License $license = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'version' => $version ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'title' => $title ?? Generator::UNDEFINED,
|
||||
'termsOfService' => $termsOfService ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($contact, $license),
|
||||
]);
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
|
||||
class Items extends OA\Items
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* * @param list<string> $required
|
||||
* * @param list<Property> $properties
|
||||
* * @param string|non-empty-array<string>|null $type
|
||||
* * @param array<Examples> $examples
|
||||
* * @param array<Schema|OA\Schema> $allOf
|
||||
* * @param array<Schema|OA\Schema> $anyOf
|
||||
* * @param array<Schema|OA\Schema> $oneOf
|
||||
* * @param list<string|int|float|bool|\UnitEnum|null>|class-string|null $enum
|
||||
* * @param array<string,mixed>|null $x
|
||||
* * @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
// Schema
|
||||
string|object|null $ref = null,
|
||||
?string $schema = null,
|
||||
?string $title = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?int $maxProperties = null,
|
||||
?int $minProperties = null,
|
||||
?array $required = null,
|
||||
?array $properties = null,
|
||||
string|array|null $type = null,
|
||||
?string $format = null,
|
||||
?Items $items = null,
|
||||
?string $collectionFormat = null,
|
||||
?string $pattern = null,
|
||||
?Discriminator $discriminator = null,
|
||||
?bool $readOnly = null,
|
||||
?bool $writeOnly = null,
|
||||
?Xml $xml = null,
|
||||
?ExternalDocumentation $externalDocs = null,
|
||||
mixed $example = Generator::UNDEFINED,
|
||||
?array $examples = null,
|
||||
?bool $nullable = null,
|
||||
?bool $deprecated = null,
|
||||
?array $allOf = null,
|
||||
?array $anyOf = null,
|
||||
?array $oneOf = null,
|
||||
?string $contentEncoding = null,
|
||||
?string $contentMediaType = null,
|
||||
|
||||
// JSON Schema
|
||||
mixed $default = Generator::UNDEFINED,
|
||||
int|float|null $maximum = null,
|
||||
bool|int|float|null $exclusiveMaximum = null,
|
||||
int|float|null $minimum = null,
|
||||
bool|int|float|null $exclusiveMinimum = null,
|
||||
int|null $maxLength = null,
|
||||
int|null $minLength = null,
|
||||
int|null $maxItems = null,
|
||||
int|null $minItems = null,
|
||||
bool|null $uniqueItems = null,
|
||||
array|string|null $enum = null,
|
||||
mixed $not = Generator::UNDEFINED,
|
||||
bool|AdditionalProperties|null $additionalProperties = null,
|
||||
array|null $additionalItems = null,
|
||||
array|null $contains = null,
|
||||
array|null $patternProperties = null,
|
||||
array|null $unevaluatedProperties = null,
|
||||
mixed $dependencies = Generator::UNDEFINED,
|
||||
mixed $propertyNames = Generator::UNDEFINED,
|
||||
mixed $const = Generator::UNDEFINED,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
// Schema
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'schema' => $schema ?? Generator::UNDEFINED,
|
||||
'title' => $title ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'maxProperties' => $maxProperties ?? Generator::UNDEFINED,
|
||||
'minProperties' => $minProperties ?? Generator::UNDEFINED,
|
||||
'required' => $required ?? Generator::UNDEFINED,
|
||||
'properties' => $properties ?? Generator::UNDEFINED,
|
||||
'type' => $type ?? Generator::UNDEFINED,
|
||||
'format' => $format ?? Generator::UNDEFINED,
|
||||
'collectionFormat' => $collectionFormat ?? Generator::UNDEFINED,
|
||||
'pattern' => $pattern ?? Generator::UNDEFINED,
|
||||
'readOnly' => $readOnly ?? Generator::UNDEFINED,
|
||||
'writeOnly' => $writeOnly ?? Generator::UNDEFINED,
|
||||
'xml' => $xml ?? Generator::UNDEFINED,
|
||||
'example' => $example,
|
||||
'nullable' => $nullable ?? Generator::UNDEFINED,
|
||||
'deprecated' => $deprecated ?? Generator::UNDEFINED,
|
||||
'allOf' => $allOf ?? Generator::UNDEFINED,
|
||||
'anyOf' => $anyOf ?? Generator::UNDEFINED,
|
||||
'oneOf' => $oneOf ?? Generator::UNDEFINED,
|
||||
'contentEncoding' => $contentEncoding ?? Generator::UNDEFINED,
|
||||
'contentMediaType' => $contentMediaType ?? Generator::UNDEFINED,
|
||||
|
||||
// JSON Schema
|
||||
'default' => $default,
|
||||
'maximum' => $maximum ?? Generator::UNDEFINED,
|
||||
'exclusiveMaximum' => $exclusiveMaximum ?? Generator::UNDEFINED,
|
||||
'minimum' => $minimum ?? Generator::UNDEFINED,
|
||||
'exclusiveMinimum' => $exclusiveMinimum ?? Generator::UNDEFINED,
|
||||
'maxLength' => $maxLength ?? Generator::UNDEFINED,
|
||||
'minLength' => $minLength ?? Generator::UNDEFINED,
|
||||
'maxItems' => $maxItems ?? Generator::UNDEFINED,
|
||||
'minItems' => $minItems ?? Generator::UNDEFINED,
|
||||
'uniqueItems' => $uniqueItems ?? Generator::UNDEFINED,
|
||||
'enum' => $enum ?? Generator::UNDEFINED,
|
||||
'not' => $not,
|
||||
'additionalProperties' => $additionalProperties ?? Generator::UNDEFINED,
|
||||
'additionalItems' => $additionalItems ?? Generator::UNDEFINED,
|
||||
'contains' => $contains ?? Generator::UNDEFINED,
|
||||
'patternProperties' => $patternProperties ?? Generator::UNDEFINED,
|
||||
'unevaluatedProperties' => $unevaluatedProperties ?? Generator::UNDEFINED,
|
||||
'dependencies' => $dependencies,
|
||||
'propertyNames' => $propertyNames,
|
||||
'const' => $const,
|
||||
|
||||
// abstract annotation
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($items, $discriminator, $externalDocs, $examples),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
/**
|
||||
* Shorthand for a json response.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
* #[OA\JsonContent(
|
||||
* ref: '#/components/schemas/user'
|
||||
* )]
|
||||
* ```
|
||||
* vs.
|
||||
* ```php
|
||||
* #[OA\MediaType(
|
||||
* mediaType: 'application/json',
|
||||
* schema: new OA\Schema(
|
||||
* ref: '#/components/schemas/user'
|
||||
* )
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class JsonContent extends OA\JsonContent
|
||||
{
|
||||
/**
|
||||
* @param list<Encoding> $encoding
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param list<string> $required
|
||||
* @param list<Property> $properties
|
||||
* @param string|non-empty-array<string>|null $type
|
||||
* @param array<Examples> $examples
|
||||
* @param array<Schema|OA\Schema> $allOf
|
||||
* @param array<Schema|OA\Schema> $anyOf
|
||||
* @param array<Schema|OA\Schema> $oneOf
|
||||
* @param list<string|int|float|bool|\UnitEnum|null>|class-string|null $enum
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?array $encoding = null,
|
||||
|
||||
// Schema
|
||||
string|object|null $ref = null,
|
||||
?string $schema = null,
|
||||
?string $title = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?int $maxProperties = null,
|
||||
?int $minProperties = null,
|
||||
?array $required = null,
|
||||
?array $properties = null,
|
||||
string|array|null $type = null,
|
||||
?string $format = null,
|
||||
?Items $items = null,
|
||||
?string $collectionFormat = null,
|
||||
?string $pattern = null,
|
||||
?Discriminator $discriminator = null,
|
||||
?bool $readOnly = null,
|
||||
?bool $writeOnly = null,
|
||||
?Xml $xml = null,
|
||||
?ExternalDocumentation $externalDocs = null,
|
||||
mixed $example = Generator::UNDEFINED,
|
||||
?array $examples = null,
|
||||
?bool $nullable = null,
|
||||
?bool $deprecated = null,
|
||||
?array $allOf = null,
|
||||
?array $anyOf = null,
|
||||
?array $oneOf = null,
|
||||
?string $contentEncoding = null,
|
||||
?string $contentMediaType = null,
|
||||
|
||||
// JSON Schema
|
||||
mixed $default = Generator::UNDEFINED,
|
||||
int|float|null $maximum = null,
|
||||
bool|int|float|null $exclusiveMaximum = null,
|
||||
int|float|null $minimum = null,
|
||||
bool|int|float|null $exclusiveMinimum = null,
|
||||
int|null $maxLength = null,
|
||||
int|null $minLength = null,
|
||||
int|null $maxItems = null,
|
||||
int|null $minItems = null,
|
||||
bool|null $uniqueItems = null,
|
||||
array|string|null $enum = null,
|
||||
mixed $not = Generator::UNDEFINED,
|
||||
bool|AdditionalProperties|null $additionalProperties = null,
|
||||
array|null $additionalItems = null,
|
||||
array|null $contains = null,
|
||||
array|null $patternProperties = null,
|
||||
array|null $unevaluatedProperties = null,
|
||||
mixed $dependencies = Generator::UNDEFINED,
|
||||
mixed $propertyNames = Generator::UNDEFINED,
|
||||
mixed $const = Generator::UNDEFINED,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
// Schema
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'schema' => $schema ?? Generator::UNDEFINED,
|
||||
'title' => $title ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'maxProperties' => $maxProperties ?? Generator::UNDEFINED,
|
||||
'minProperties' => $minProperties ?? Generator::UNDEFINED,
|
||||
'required' => $required ?? Generator::UNDEFINED,
|
||||
'properties' => $properties ?? Generator::UNDEFINED,
|
||||
'type' => $type ?? Generator::UNDEFINED,
|
||||
'format' => $format ?? Generator::UNDEFINED,
|
||||
'collectionFormat' => $collectionFormat ?? Generator::UNDEFINED,
|
||||
'pattern' => $pattern ?? Generator::UNDEFINED,
|
||||
'readOnly' => $readOnly ?? Generator::UNDEFINED,
|
||||
'writeOnly' => $writeOnly ?? Generator::UNDEFINED,
|
||||
'xml' => $xml ?? Generator::UNDEFINED,
|
||||
'example' => $example,
|
||||
'nullable' => $nullable ?? Generator::UNDEFINED,
|
||||
'deprecated' => $deprecated ?? Generator::UNDEFINED,
|
||||
'allOf' => $allOf ?? Generator::UNDEFINED,
|
||||
'anyOf' => $anyOf ?? Generator::UNDEFINED,
|
||||
'oneOf' => $oneOf ?? Generator::UNDEFINED,
|
||||
'contentEncoding' => $contentEncoding ?? Generator::UNDEFINED,
|
||||
'contentMediaType' => $contentMediaType ?? Generator::UNDEFINED,
|
||||
|
||||
// JSON Schema
|
||||
'default' => $default,
|
||||
'maximum' => $maximum ?? Generator::UNDEFINED,
|
||||
'exclusiveMaximum' => $exclusiveMaximum ?? Generator::UNDEFINED,
|
||||
'minimum' => $minimum ?? Generator::UNDEFINED,
|
||||
'exclusiveMinimum' => $exclusiveMinimum ?? Generator::UNDEFINED,
|
||||
'maxLength' => $maxLength ?? Generator::UNDEFINED,
|
||||
'minLength' => $minLength ?? Generator::UNDEFINED,
|
||||
'maxItems' => $maxItems ?? Generator::UNDEFINED,
|
||||
'minItems' => $minItems ?? Generator::UNDEFINED,
|
||||
'uniqueItems' => $uniqueItems ?? Generator::UNDEFINED,
|
||||
'enum' => $enum ?? Generator::UNDEFINED,
|
||||
'not' => $not,
|
||||
'additionalProperties' => $additionalProperties ?? Generator::UNDEFINED,
|
||||
'additionalItems' => $additionalItems ?? Generator::UNDEFINED,
|
||||
'contains' => $contains ?? Generator::UNDEFINED,
|
||||
'patternProperties' => $patternProperties ?? Generator::UNDEFINED,
|
||||
'unevaluatedProperties' => $unevaluatedProperties ?? Generator::UNDEFINED,
|
||||
'dependencies' => $dependencies,
|
||||
'propertyNames' => $propertyNames,
|
||||
'const' => $const,
|
||||
|
||||
// abstract annotation
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($items, $discriminator, $externalDocs, $examples, $encoding),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class License extends OA\License
|
||||
{
|
||||
/**
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
?string $identifier = null,
|
||||
?string $url = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'name' => $name ?? Generator::UNDEFINED,
|
||||
'identifier' => $identifier ?? Generator::UNDEFINED,
|
||||
'url' => $url ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
|
||||
class Link extends OA\Link
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param array<string,mixed> $parameters
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $link = null,
|
||||
?string $operationRef = null,
|
||||
string|object|null $ref = null,
|
||||
?string $operationId = null,
|
||||
?array $parameters = null,
|
||||
mixed $requestBody = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?Server $server = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'link' => $link ?? Generator::UNDEFINED,
|
||||
'operationRef' => $operationRef ?? Generator::UNDEFINED,
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'operationId' => $operationId ?? Generator::UNDEFINED,
|
||||
'parameters' => $parameters ?? Generator::UNDEFINED,
|
||||
'requestBody' => $requestBody ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($server),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class MediaType extends OA\MediaType
|
||||
{
|
||||
/**
|
||||
* @param array<Examples> $examples
|
||||
* @param list<Encoding> $encoding
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $mediaType = null,
|
||||
?Schema $schema = null,
|
||||
mixed $example = Generator::UNDEFINED,
|
||||
?array $examples = null,
|
||||
?array $encoding = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'mediaType' => $mediaType ?? Generator::UNDEFINED,
|
||||
'example' => $example,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($schema, $examples, $encoding),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class OpenApi extends OA\OpenApi
|
||||
{
|
||||
/**
|
||||
* @param list<Server>|null $servers
|
||||
* @param list<Tag>|null $tags
|
||||
* @param array<PathItem>|null $paths
|
||||
* @param list<Webhook>|null $webhooks
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
string $openapi = self::DEFAULT_VERSION,
|
||||
?Info $info = null,
|
||||
?array $servers = null,
|
||||
?array $security = null,
|
||||
?array $tags = null,
|
||||
?ExternalDocumentation $externalDocs = null,
|
||||
?array $paths = null,
|
||||
?Components $components = null,
|
||||
?array $webhooks = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'openapi' => $openapi,
|
||||
'security' => $security ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($info, $servers, $tags, $externalDocs, $paths, $components, $webhooks),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
trait OperationTrait
|
||||
{
|
||||
/**
|
||||
* @param list<Server> $servers
|
||||
* @param list<string> $tags
|
||||
* @param list<Parameter> $parameters
|
||||
* @param list<Response> $responses
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $path = null,
|
||||
?string $operationId = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?string $summary = Generator::UNDEFINED,
|
||||
?array $security = null,
|
||||
?array $servers = null,
|
||||
?RequestBody $requestBody = null,
|
||||
?array $tags = null,
|
||||
?array $parameters = null,
|
||||
?array $responses = null,
|
||||
?array $callbacks = null,
|
||||
?ExternalDocumentation $externalDocs = null,
|
||||
?bool $deprecated = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'path' => $path ?? Generator::UNDEFINED,
|
||||
'operationId' => $operationId ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'summary' => $summary,
|
||||
'security' => $security ?? Generator::UNDEFINED,
|
||||
'servers' => $servers ?? Generator::UNDEFINED,
|
||||
'tags' => $tags ?? Generator::UNDEFINED,
|
||||
'callbacks' => $callbacks ?? Generator::UNDEFINED,
|
||||
'deprecated' => $deprecated ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($requestBody, $responses, $parameters, $externalDocs),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Options extends OA\Options
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)]
|
||||
class Parameter extends OA\Parameter
|
||||
{
|
||||
use ParameterTrait;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Generator;
|
||||
|
||||
trait ParameterTrait
|
||||
{
|
||||
/**
|
||||
* @param 'query'|'header'|'path'|'cookie'|null $in
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param array<Examples> $examples
|
||||
* @param array<MediaType>|JsonContent|XmlContent|Attachable|null $content
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $parameter = null,
|
||||
?string $name = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?string $in = null,
|
||||
?bool $required = null,
|
||||
?bool $deprecated = null,
|
||||
?bool $allowEmptyValue = null,
|
||||
string|object|null $ref = null,
|
||||
?Schema $schema = null,
|
||||
mixed $example = Generator::UNDEFINED,
|
||||
?array $examples = null,
|
||||
array|JsonContent|XmlContent|Attachable|null $content = null,
|
||||
?string $style = null,
|
||||
?bool $explode = null,
|
||||
?bool $allowReserved = null,
|
||||
?array $spaceDelimited = null,
|
||||
?array $pipeDelimited = null,
|
||||
mixed $deepObject = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'parameter' => $parameter ?? Generator::UNDEFINED,
|
||||
'name' => $name ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
// next two are special as we override the default value for specific Parameter subclasses
|
||||
'in' => $in ?? (Generator::isDefault($this->in) ? Generator::UNDEFINED : $this->in),
|
||||
'required' => $required ?? (Generator::isDefault($this->required) ? Generator::UNDEFINED : $this->required),
|
||||
'deprecated' => $deprecated ?? Generator::UNDEFINED,
|
||||
'allowEmptyValue' => $allowEmptyValue ?? Generator::UNDEFINED,
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'example' => $example,
|
||||
'style' => $style ?? Generator::UNDEFINED,
|
||||
'explode' => $explode ?? Generator::UNDEFINED,
|
||||
'allowReserved' => $allowReserved ?? Generator::UNDEFINED,
|
||||
'spaceDelimited' => $spaceDelimited ?? Generator::UNDEFINED,
|
||||
'pipeDelimited' => $pipeDelimited ?? Generator::UNDEFINED,
|
||||
'deepObject' => $deepObject ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($schema, $examples, $content),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Patch extends OA\Patch
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class PathItem extends OA\PathItem
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param list<Server>|null $servers
|
||||
* @param list<Parameter>|null $parameters
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $path = null,
|
||||
string|object|null $ref = null,
|
||||
?string $summary = Generator::UNDEFINED,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?Get $get = null,
|
||||
?Put $put = null,
|
||||
?Post $post = null,
|
||||
?Delete $delete = null,
|
||||
?Options $options = null,
|
||||
?Head $head = null,
|
||||
?Patch $patch = null,
|
||||
?Trace $trace = null,
|
||||
?Query $query = null,
|
||||
?array $servers = null,
|
||||
?array $parameters = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'path' => $path ?? Generator::UNDEFINED,
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'summary' => $summary,
|
||||
'description' => $description,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($get, $put, $post, $delete, $options, $head, $patch, $trace, $query, $servers, $parameters),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)]
|
||||
class PathParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $in = 'path';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $required = true;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Post extends OA\Post
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::TARGET_CLASS_CONSTANT | \Attribute::IS_REPEATABLE)]
|
||||
class Property extends OA\Property
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param list<string> $required
|
||||
* @param list<Property> $properties
|
||||
* @param string|non-empty-array<string>|null $type
|
||||
* @param array<Examples> $examples
|
||||
* @param array<Schema|OA\Schema> $allOf
|
||||
* @param array<Schema|OA\Schema> $anyOf
|
||||
* @param array<Schema|OA\Schema> $oneOf
|
||||
* @param list<string|int|float|bool|\UnitEnum|null>|class-string|null $enum
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
?string $property = null,
|
||||
?Encoding $encoding = null,
|
||||
|
||||
// Schema
|
||||
string|object|null $ref = null,
|
||||
?string $schema = null,
|
||||
?string $title = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?int $maxProperties = null,
|
||||
?int $minProperties = null,
|
||||
?array $required = null,
|
||||
?array $properties = null,
|
||||
string|array|null $type = null,
|
||||
?string $format = null,
|
||||
?Items $items = null,
|
||||
?string $collectionFormat = null,
|
||||
?string $pattern = null,
|
||||
?Discriminator $discriminator = null,
|
||||
?bool $readOnly = null,
|
||||
?bool $writeOnly = null,
|
||||
?Xml $xml = null,
|
||||
?ExternalDocumentation $externalDocs = null,
|
||||
mixed $example = Generator::UNDEFINED,
|
||||
?array $examples = null,
|
||||
?bool $nullable = null,
|
||||
?bool $deprecated = null,
|
||||
?array $allOf = null,
|
||||
?array $anyOf = null,
|
||||
?array $oneOf = null,
|
||||
?string $contentEncoding = null,
|
||||
?string $contentMediaType = null,
|
||||
|
||||
// JSON Schema
|
||||
mixed $default = Generator::UNDEFINED,
|
||||
int|float|null $maximum = null,
|
||||
bool|int|float|null $exclusiveMaximum = null,
|
||||
int|float|null $minimum = null,
|
||||
bool|int|float|null $exclusiveMinimum = null,
|
||||
int|null $maxLength = null,
|
||||
int|null $minLength = null,
|
||||
int|null $maxItems = null,
|
||||
int|null $minItems = null,
|
||||
bool|null $uniqueItems = null,
|
||||
array|string|null $enum = null,
|
||||
mixed $not = Generator::UNDEFINED,
|
||||
bool|AdditionalProperties|null $additionalProperties = null,
|
||||
array|null $additionalItems = null,
|
||||
array|null $contains = null,
|
||||
array|null $patternProperties = null,
|
||||
array|null $unevaluatedProperties = null,
|
||||
mixed $dependencies = Generator::UNDEFINED,
|
||||
mixed $propertyNames = Generator::UNDEFINED,
|
||||
mixed $const = Generator::UNDEFINED,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'property' => $property ?? Generator::UNDEFINED,
|
||||
|
||||
// Schema
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'schema' => $schema ?? Generator::UNDEFINED,
|
||||
'title' => $title ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'maxProperties' => $maxProperties ?? Generator::UNDEFINED,
|
||||
'minProperties' => $minProperties ?? Generator::UNDEFINED,
|
||||
'required' => $required ?? Generator::UNDEFINED,
|
||||
'properties' => $properties ?? Generator::UNDEFINED,
|
||||
'type' => $type ?? Generator::UNDEFINED,
|
||||
'format' => $format ?? Generator::UNDEFINED,
|
||||
'collectionFormat' => $collectionFormat ?? Generator::UNDEFINED,
|
||||
'pattern' => $pattern ?? Generator::UNDEFINED,
|
||||
'readOnly' => $readOnly ?? Generator::UNDEFINED,
|
||||
'writeOnly' => $writeOnly ?? Generator::UNDEFINED,
|
||||
'xml' => $xml ?? Generator::UNDEFINED,
|
||||
'example' => $example,
|
||||
'nullable' => $nullable ?? Generator::UNDEFINED,
|
||||
'deprecated' => $deprecated ?? Generator::UNDEFINED,
|
||||
'allOf' => $allOf ?? Generator::UNDEFINED,
|
||||
'anyOf' => $anyOf ?? Generator::UNDEFINED,
|
||||
'oneOf' => $oneOf ?? Generator::UNDEFINED,
|
||||
'contentEncoding' => $contentEncoding ?? Generator::UNDEFINED,
|
||||
'contentMediaType' => $contentMediaType ?? Generator::UNDEFINED,
|
||||
|
||||
// JSON Schema
|
||||
'default' => $default,
|
||||
'maximum' => $maximum ?? Generator::UNDEFINED,
|
||||
'exclusiveMaximum' => $exclusiveMaximum ?? Generator::UNDEFINED,
|
||||
'minimum' => $minimum ?? Generator::UNDEFINED,
|
||||
'exclusiveMinimum' => $exclusiveMinimum ?? Generator::UNDEFINED,
|
||||
'maxLength' => $maxLength ?? Generator::UNDEFINED,
|
||||
'minLength' => $minLength ?? Generator::UNDEFINED,
|
||||
'maxItems' => $maxItems ?? Generator::UNDEFINED,
|
||||
'minItems' => $minItems ?? Generator::UNDEFINED,
|
||||
'uniqueItems' => $uniqueItems ?? Generator::UNDEFINED,
|
||||
'enum' => $enum ?? Generator::UNDEFINED,
|
||||
'not' => $not,
|
||||
'additionalProperties' => $additionalProperties ?? Generator::UNDEFINED,
|
||||
'additionalItems' => $additionalItems ?? Generator::UNDEFINED,
|
||||
'contains' => $contains ?? Generator::UNDEFINED,
|
||||
'patternProperties' => $patternProperties ?? Generator::UNDEFINED,
|
||||
'unevaluatedProperties' => $unevaluatedProperties ?? Generator::UNDEFINED,
|
||||
'dependencies' => $dependencies,
|
||||
'propertyNames' => $propertyNames,
|
||||
'const' => $const,
|
||||
|
||||
// abstract annotation
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($items, $discriminator, $externalDocs, $encoding, $examples),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Put extends OA\Put
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
* @since OpenAPI 3.2.0
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Query extends OA\Query
|
||||
{
|
||||
use OperationTrait;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)]
|
||||
class QueryParameter extends Parameter
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $in = 'query';
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)]
|
||||
class RequestBody extends OA\RequestBody
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param array<MediaType|JsonContent|XmlContent>|MediaType|JsonContent|XmlContent|Attachable|null $content
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
string|object|null $ref = null,
|
||||
?string $request = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?bool $required = null,
|
||||
array|MediaType|JsonContent|XmlContent|Attachable|null $content = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'request' => $request ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'required' => $required ?? Generator::UNDEFINED,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($content),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @license Apache 2.0
|
||||
*/
|
||||
|
||||
namespace OpenApi\Attributes;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use OpenApi\Generator;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class Response extends OA\Response
|
||||
{
|
||||
/**
|
||||
* @param string|class-string|object|null $ref
|
||||
* @param list<Header> $headers
|
||||
* @param MediaType|JsonContent|XmlContent|Attachable|array<MediaType|JsonContent|XmlContent|Attachable> $content
|
||||
* @param list<Link> $links
|
||||
* @param array<string,mixed>|null $x
|
||||
* @param list<Attachable>|null $attachables
|
||||
*/
|
||||
public function __construct(
|
||||
string|object|null $ref = null,
|
||||
int|string|null $response = null,
|
||||
?string $description = Generator::UNDEFINED,
|
||||
?array $headers = null,
|
||||
MediaType|JsonContent|XmlContent|Attachable|array|null $content = null,
|
||||
?array $links = null,
|
||||
|
||||
// abstract annotation
|
||||
?array $x = null,
|
||||
?array $attachables = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'ref' => $ref ?? Generator::UNDEFINED,
|
||||
'response' => $response ?? Generator::UNDEFINED,
|
||||
'description' => $description,
|
||||
'x' => $x ?? Generator::UNDEFINED,
|
||||
'attachables' => $attachables ?? Generator::UNDEFINED,
|
||||
'value' => $this->combine($headers, $content, $links),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user