Skip to content

Commit

Permalink
Add/update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
DerManoMann committed Nov 28, 2021
1 parent 865cf1b commit 4312d4f
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 18 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ For a full list of supported annotations, please have look at the [`OpenApi\Anno
- Command-line interface available.
- [Documentation site](https://zircote.github.io/swagger-php/) with a getting started guide.
- Exceptional error reporting (with hints, context)
- As of PHP 8.1 all annotations are also available as PHP attributes

## Installation (with [Composer](https://getcomposer.org))

Expand Down
24 changes: 22 additions & 2 deletions docs/Getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ For cli usage from anywhere install swagger-php globally and add the `~/.compose
composer global require zircote/swagger-php
```

## Write annotations
## Document your code using annotations or PHP attributes

The goal of swagger-php is to generate a openapi.json using phpdoc annotations.
The goal of swagger-php is to generate a openapi.json using phpdoc annotations or PHP attributes.

#### When you write:

Expand Down Expand Up @@ -75,6 +75,24 @@ paths:
description: "An example resource"
```
#### PHP Attributes
This documentation uses annotations in its examples. However, as per PHP 8.1 you may also use all documented
annotations as attributes. Then the above example would look like this:
```php
#[OA\Info(title="My First API", version="0.1")]
class OpenApi {}

class Controller{
#[OA\Get(path: '/api/resource.json')]
#[OA\Response(response: '200', description: 'An example resource')]
public function getResource()
{
// ...
}
}
```

### Using variables

You can use constants inside doctrine annotations.
Expand Down Expand Up @@ -102,6 +120,8 @@ swagger-php will scan your project and merge all annotations into one @OA\OpenAp

The big benefit swagger-php provides is that the documentation lives close to the code implementing the API.

**As of swagger-php v4 all annotations or attributes must be associated with code (class, method, parameter)**

### Arrays and Objects

Doctrine annotation supports arrays, but uses `{` and `}` instead of `[` and `]`.
Expand Down
134 changes: 134 additions & 0 deletions docs/Migrating-to-v4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Migrating to Swagger-PHP v4.x

## Overview of changes
* 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.
* 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.
* Deprecated elements have been removed
* `\Openapi\Analysis::processors()`
* `\Openapi\Analyser::$whitelist`
* `\Openapi\Analyser::$defaultImports`
* `\Openapi\Logger`
* Legacy support is available via the previous `TokenAnalyser`
* Improvements to the `Generator` class

## Annotations as PHP attributes
While PHP attributes have been around since PHP 8.0 they were lacking the ability to be nested.
This changes with PHP 8.1 which allows to use `new` in initializers.

Swagger-php attributes also make use of named arguments, so attribute parameters can be (mostly) typed.
There are some limitations to type hints which can only be resolved once support for PHP 7.x is dropped.

### Example
**Using annotations**
```php
/**
* @OA\Info(
* version="1.0.0",
* title="My API",
* @OA\License(name="MIT"),
* @OA\Attachable()
* )
*/
class OpenApiSpec
{
}
```
**Using attributes**
```php
#[OA\Info(
version: '1.0.0',
title: 'My API',
attachables: [new OA\Attachable()]
)]
#[OA\License(name: 'MIT')]
class OpenApiSpec
{
}
```

#### Optional nesting
One of the few differences between annotations and attributes visible in the above example is that the `OA\License` attribute
is not nested within `OA\Info`. Nesting of attributes is possible and required in certain cases however, **in cases where there
is no ambiguity attributes may be all written on the top level** and swagger-php will do the rest.

## Annotations must be associated with code
The (now legacy) way of parsing PHP files meant that docblocks could live in a file without a single line
of actual PHP code.

PHP Attributes cannot exist in isolation; they need code to be associated with and then are available
via reflection on the associated code.
In order to allow to keep supporting annotations and the code simple it made sense to treat annotations and attributes
the same in this respect.

## The `PathParameter` annotation
As annotation this is just a short form for
```php
@OA\Parameter(in='body')
```

Things get more interesting when it comes to using it as attribute, though. In the context of
a controller you can now do something like
```php
class MyController
{
#[OA\Get(path: '/products/{product_id}')]
public function getProduct(
#[OA\PathParameter] string $product_id)
{
}
```
Here it avoid having to duplicate details about the `$product_id` parameter and the simple use of the attribute
will pick up typehints automatically.

## The `Attachable` annotation
Technically these were added in version 3.3.0, however they become really useful only with version 4.

The attachable annotation is similar to the OpenApi vendor extension `x=`. The main difference are that
1. Attachables allow complex structures and strong typing
2. **Attachables are not added to the generated spec.**

Their main purpose is to make customizing swagger-php easier by allowing to add arbitrary data to any annotation.

One possible use case could be custom annotations. Classes extnding `Attachable` are allowed to limit
the allowed parent annotations. This means it would be easy to create a new attribute to flag certain endpoints
as private and exclude them under certain conditions from the spec (via a custom processor).

## Removed deprecated elements
### `\Openapi\Analysis::processors()`
Processors have been moved into the `Generator` class incl. some new convenicen methods.
### `\Openapi\Analyser::$whitelist`
This has been replaced with the `Generator` `namespaces` property.
### `\Openapi\Analyser::$defaultImports`
This has been replaced with the `Generator` `aliases` property.
### `\Openapi\Logger`
This class has been removed completely. Instead, you may configure a [PSR-3 logger](https://www.php-fig.org/psr/psr-3/).

## Improvements to the `Generator` class
The removal of deprecated static config options means that the `Generator` class now is
the main entry point into swagger-php when used programmatically.

To make the migration as simple as possible a new `Generator::withContext(callable)` has been added.
This allows to use parts of the library (an `Analyser` instance, for example) within the context of a `Generator` instance.

Example:
```php
$analyser = createMyAnalyser();

$analysis = (new Generator())
->addAlias('fo', 'My\\Attribute\\Namespace')
->addNamespace('Other\\Annotations\\')
->withContext(function (Generator $generator, Analysis $analysis, Context $context) use ($analyser) {
$analyser->setGenerator($generator);
$analysis = $analyser->fromFile('my_code.php', $context);
$analysis->process($generator->getProcessors());

return $analysis;
});

```
18 changes: 18 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ Add annotations to your php files.
*/
```

Or, as of PHP 8.1 use attributes


```php
#[OA\Info(title="My First API", version="0.1")]
class OpenApi {}

class Controller{
#[OA\Get(path: '/api/resource.json')]
#[OA\Response(response: '200', description: 'An example resource')]
public function getResource()
{
// ...
}
}
```

And view and interact with your API using [Swagger UI ](https://swagger.io/tools/swagger-ui/)

## Links
Expand All @@ -51,6 +68,7 @@ And view and interact with your API using [Swagger UI ](https://swagger.io/tools
- [OpenApi Documentation](https://swagger.io/docs/)
- [OpenApi Specification](http://swagger.io/specification/)
- [Migration from 2.x to 3.x](Migrating-to-v3.md)
- [Migration from 3.x to 4.x](Migrating-to-v4.md)
- [Learn by example](https://github.com/zircote/swagger-php/tree/master/Examples) lots of example of how to generate
- [Related projects](Related-projects.md)
- [Swagger-php 2.x documentation](https://github.com/zircote/swagger-php/tree/2.x/docs) The docs for swagger-php v2
Expand Down
4 changes: 2 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ parameters:
processTimeout: 300.0
ignoreErrors:
- '#does not accept default value of type string#'
excludes_analyse:
- '#Access to an undefined property#'
excludePaths:
- 'tests/Fixtures/*'

1 change: 0 additions & 1 deletion src/Analysers/ReflectionAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ public function fromFqdn(string $fqdn, Analysis $analysis): Analysis

protected function analyzeFqdn(string $fqdn, Analysis $analysis, array $details): Analysis
{
// autoload if needed
if (!class_exists($fqdn) && !interface_exists($fqdn) && !trait_exists($fqdn)) {
return $analysis;
}
Expand Down
7 changes: 0 additions & 7 deletions src/Analysis.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@ class Analysis
*/
public $context;

/**
* Registry for the post-processing operations.
*
* @var callable[]
*/
private static $processors;

public function __construct(array $annotations = [], Context $context = null)
{
$this->annotations = new \SplObjectStorage();
Expand Down
13 changes: 7 additions & 6 deletions src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,11 @@ public function removeProcessor(callable $processor, bool $silent = false): Gene
*/
public function updateProcessor(callable $processor, ?callable $matcher = null): Generator
{
if (!$matcher) {
$matcher = $matcher ?: function ($other) use ($processor) {
$otherClass = get_class($other);
$matcher = $matcher ?: function ($other) use ($processor) {
$otherClass = get_class($other);

return $processor instanceof $otherClass;
};
}
return $processor instanceof $otherClass;
};

$processors = array_map(function ($other) use ($processor, $matcher) {
return $matcher($other) ? $processor : $other;
Expand Down Expand Up @@ -286,6 +284,9 @@ public static function scan(iterable $sources, array $options = []): ?OpenApi
/**
* Run code in the context of this generator.
*
* @param callable $callable Callable in the form of
* `function(Generator $generator, Analysis $analysis, Context $context): mixed`
*
* @return mixed the result of the `callable`
*/
public function withContext(callable $callable)
Expand Down

0 comments on commit 4312d4f

Please sign in to comment.