zircote/swagger-php
swagger-php generates OpenAPI 3.0/3.1/3.2 documentation from your PHP 8.2+ code using attributes (preferred) or optional Doctrine annotations. Use it via CLI or programmatically, with helpful error reporting and a full documentation site.
composer require doctrine/annotationsPathParameter was added for improved framework support.Attachable was added to simplify custom processing.
Attachable can be used to attach arbitrary data to any given annotation.\Openapi\Analysis::processors()\Openapi\Analyser::$whitelist\Openapi\Analyser::$defaultImports\Openapi\LoggerTokenAnalyserGenerator classWhile 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.
use OpenApi\Annotations as OA;
/**
* [@OA](https://github.com/OA)\Info(
* version="1.0.0",
* title="My API",
* [@OA](https://github.com/OA)\License(name="MIT"),
* [@OA](https://github.com/OA)\Attachable()
* )
*/
class OpenApiSpec
{
}
use OpenApi\Attributes as OA;
#[OA\Info(
version: '1.0.0',
title: 'My API',
attachables: [new OA\Attachable()]
)]
#[OA\License(name: 'MIT')]
class OpenApiSpec
{
}
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.
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 structural element. 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.
PathParameter annotationAs annotation this is just a short form for
[@OA](https://github.com/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
class MyController
{
#[OA\Get(path: '/products/{product_id}')]
public function getProduct(
#[OA\PathParameter] string $product_id)
{
}
}
Here it avoids having to duplicate details about the $product_id parameter and the simple use of the attribute
will pick up typehints automatically.
Attachable annotationTechnically 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
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 extending 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).
\Openapi\Analysis::processors()Processors have been moved into the Generator class incl. some new convenience methods.
\Openapi\Analyser::$whitelistThis has been replaced with the Generator namespaces property.
\Openapi\Analyser::$defaultImportsThis has been replaced with the Generator aliases property.
\Openapi\LoggerThis class has been removed completely. Instead, you may configure a PSR-3 logger.
Generator classThe 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:
$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;
});
How can I help you explore Laravel packages today?