Skip to content

Commit

Permalink
Allow to annotate class constants as properties (#1193)
Browse files Browse the repository at this point in the history
  • Loading branch information
DerManoMann committed Apr 12, 2022
1 parent b327c9c commit 2f66ec8
Show file tree
Hide file tree
Showing 19 changed files with 131 additions and 31 deletions.
5 changes: 4 additions & 1 deletion Examples/polymorphism/Employee.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
*/
final class Employee extends AbstractResponsible
{
protected const TYPE = 'employee';
/**
* @OA\Property(property="type")
*/
protected const TYPE = 'Virtual';

/**
* @OA\Property(nullable=false)
Expand Down
3 changes: 3 additions & 0 deletions Examples/polymorphism/polymorphism-3.1.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ components:
properties:
property2:
type: string
type:
type: string
const: 'Virtual'
FlResponsible:
allOf:
-
Expand Down
4 changes: 4 additions & 0 deletions Examples/polymorphism/polymorphism.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ components:
property2:
type: string
nullable: false
type:
type: string
enum:
- Virtual
FlResponsible:
allOf:
-
Expand Down
5 changes: 5 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
"phpunit",
"@lint"
],
"testlegacy": "export PHPUNIT_ANALYSER=legacy && phpunit",
"testall": [
"@test",
"@testlegacy"
],
"analyse": [
"phpstan analyse --memory-limit=2G",
"psalm --show-info=true"
Expand Down
33 changes: 33 additions & 0 deletions docs/guide/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -655,3 +655,36 @@ If you are only interested in annotations you canleave out the attribute setup l

Furthermore, your custom annotations should extend from the `OpenApi\Annotations` namespace.
:::

## Annotating class constants
```php
use OpenApi\Attributes as OA;

#[OA\Schema()]
class Airport
{
#[OA\Property(property='kind')]
public const KIND = 'Airport';
}
```
The `const` property is supported in OpenApi 3.1.0.
```yaml
components:
schemas:
Airport:
properties:
kind:
type: string
const: Airport
```
For 3.0.0 this is serialized into a single value `enum`.
```yaml
components:
schemas:
Airport:
properties:
kind:
type: string
enum:
- Airport
```
10 changes: 9 additions & 1 deletion docs/guide/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ These limits are dictated by the PHP reflection API, specifically where it provi

This means stand-alone annotations are no longer supported and ignored as `swagger-php` cannot 'see' them any more.

Most commonly this manifests with a warning about the required `@OA\Info` not being found. While most annotations have specifc
Supported locations:
* class
* interface
* trait
* method
* property
* class/interface const

Most commonly this manifests with a warning about the required `@OA\Info` not being found. While most annotations have specific
related code, the info annotation (and a few more) is kind of global.

The simplest solution to avoid this issue is to add a 'dummy' class to the docblock and add
Expand Down
3 changes: 1 addition & 2 deletions docs/guide/migrating-to-v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* As of PHP 8.1 annotations may be used as
[PHP attributes](https://www.php.net/manual/en/language.attributes.overview.php) instead.
That means all references to annotations in this document also apply to attributes.
* Annotations now **must be** associated with either a class/trait/interface,
method or property.
* Annotations now **must be** associated with a structural element (class, trait, interface), a method, property or const.
* A new annotation `PathParameter` was added for improved framework support.
* A new annotation `Attachable` was added to simplify custom processing.
`Attachable` can be used to attach arbitrary data to any given annotation.
Expand Down
22 changes: 22 additions & 0 deletions src/Analysers/ReflectionAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
namespace OpenApi\Analysers;

use OpenApi\Analysis;
use OpenApi\Annotations\Property;
use OpenApi\Context;
use OpenApi\Generator;

Expand Down Expand Up @@ -156,6 +157,27 @@ protected function analyzeFqdn(string $fqdn, Analysis $analysis, array $details)
}
}

foreach ($rc->getReflectionConstants() as $constant) {
foreach ($this->annotationFactories as $annotationFactory) {
$definition['constants'][$constant->getName()] = $ctx = new Context([
'constant' => $constant->getName(),
'comment' => $constant->getDocComment() ?: Generator::UNDEFINED,
'annotations' => [],
], $context);
foreach ($annotationFactory->build($constant, $ctx) as $annotation) {
if ($annotation instanceof Property) {
if (Generator::isDefault($annotation->property)) {
$annotation->property = $constant->getName();
}
if (Generator::isDefault($annotation->const)) {
$annotation->const = $constant->getValue();
}
$analysis->addAnnotation($annotation, $ctx);
}
}
}
}

$addDefinition = 'add' . ucfirst($contextType) . 'Definition';
$analysis->{$addDefinition}($definition);

Expand Down
2 changes: 0 additions & 2 deletions src/Annotations/AbstractAnnotation.php
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,6 @@ public function __debugInfo()
}

/**
* Customize the way json_encode() renders the annotations.
*
* @return mixed
*/
#[\ReturnTypeWillChange]
Expand Down
4 changes: 3 additions & 1 deletion src/Annotations/Flow.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ class Flow extends AbstractAnnotation
Attachable::class => ['attachables'],
];

/** @inheritdoc */
/**
* @inheritdoc
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
Expand Down
22 changes: 21 additions & 1 deletion src/Annotations/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,9 @@ class Schema extends AbstractAnnotation
public $propertyNames = Generator::UNDEFINED;

/**
* http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.24.
* http://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.1.3.
*
* @var mixed
*/
public $const = Generator::UNDEFINED;

Expand Down Expand Up @@ -404,6 +406,24 @@ class Schema extends AbstractAnnotation
Header::class,
];

/**
* @inheritdoc
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
$data = parent::jsonSerialize();

if (isset($data->const)) {
if ($this->_context->isVersion(OpenApi::VERSION_3_0_0)) {
$data->enum = [$data->const];
unset($data->const);
}
}

return $data;
}

/**
* @inheritdoc
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Attributes/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use OpenApi\Generator;

#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER)]
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER | \Attribute::TARGET_CLASS_CONSTANT)]
class Property extends \OpenApi\Annotations\Property
{
/**
Expand Down
2 changes: 2 additions & 0 deletions src/Attributes/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public function __construct(
?array $anyOf = null,
?array $oneOf = null,
AdditionalProperties|bool|null $additionalProperties = null,
$const = Generator::UNDEFINED,
// annotation
?array $x = null,
?array $attachables = null
Expand Down Expand Up @@ -89,6 +90,7 @@ public function __construct(
'anyOf' => $anyOf ?? Generator::UNDEFINED,
'oneOf' => $oneOf ?? Generator::UNDEFINED,
'additionalProperties' => $additionalProperties ?? Generator::UNDEFINED,
'const' => $const,
'x' => $x ?? Generator::UNDEFINED,
'attachables' => $attachables ?? Generator::UNDEFINED,
'value' => $this->combine($items, $discriminator, $externalDocs, $attachables),
Expand Down
28 changes: 6 additions & 22 deletions src/Processors/AugmentProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,6 @@
*/
class AugmentProperties
{
public static $types = [
'array' => 'array',
'byte' => ['string', 'byte'],
'boolean' => 'boolean',
'bool' => 'boolean',
'int' => 'integer',
'integer' => 'integer',
'long' => ['integer', 'long'],
'float' => ['number', 'float'],
'double' => ['number', 'double'],
'string' => 'string',
'date' => ['string', 'date'],
'datetime' => ['string', 'date-time'],
'\\datetime' => ['string', 'date-time'],
'datetimeimmutable' => ['string', 'date-time'],
'\\datetimeimmutable' => ['string', 'date-time'],
'datetimeinterface' => ['string', 'date-time'],
'\\datetimeinterface' => ['string', 'date-time'],
'number' => 'number',
'object' => 'object',
];

public function __invoke(Analysis $analysis)
{
$refs = [];
Expand Down Expand Up @@ -168,6 +146,12 @@ protected function augmentType(Analysis $analysis, Property $property, Context $
}
}
}

if (!Generator::isDefault($property->const) && Generator::isDefault($property->type)) {
if (!Util::mapNativeType($property, gettype($property->const))) {
$property->type = Generator::UNDEFINED;
}
}
}

protected function isNullable(string $typeDescription): bool
Expand Down
3 changes: 3 additions & 0 deletions tests/ExamplesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ public function exampleMappings()

foreach ($examples as $ekey => $example) {
foreach ($analysers as $akey => $analyser) {
if (0 === strpos($ekey, 'polymorphism') && 'token' == $akey) {
continue;
}
if (\PHP_VERSION_ID < 80100 && 'using-refs' == $ekey) {
continue;
}
Expand Down
3 changes: 3 additions & 0 deletions tests/Fixtures/Apis/Attributes/basic.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class Product implements ProductInterface
{
use NameTrait;

#[OAT\Property(property: 'kind')]
public const KIND = 'Virtual';

#[OAT\Property(description: 'The id.', format: 'int64', example: 1)]
public $id;

Expand Down
5 changes: 5 additions & 0 deletions tests/Fixtures/Apis/DocBlocks/basic.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ class Product implements ProductInterface
*/
public $id;

/**
* @OA\Property(property="kind")
*/
public const KIND = 'Virtual';

public function __construct(
/**
* @OA\Property(type="string")
Expand Down
3 changes: 3 additions & 0 deletions tests/Fixtures/Apis/Mixed/basic.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class Product implements ProductInterface
{
use NameTrait;

#[OAT\Property(property: 'kind')]
public const KIND = 'Virtual';

/**
* The id.
*
Expand Down
3 changes: 3 additions & 0 deletions tests/Fixtures/Apis/basic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ components:
description: 'The id.'
format: int64
example: 1
kind:
type: string
const: Virtual
securitySchemes:
bearerAuth:
type: http
Expand Down

0 comments on commit 2f66ec8

Please sign in to comment.