mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-09 02:59:27 +03:00
Make the document generated valid
This commit is contained in:
parent
d1adffe41f
commit
02601125bd
@ -12,7 +12,7 @@
|
||||
namespace EXSyst\Bundle\ApiDocBundle;
|
||||
|
||||
use EXSyst\Bundle\ApiDocBundle\Describer\DescriberInterface;
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
|
||||
class ApiDocGenerator
|
||||
{
|
||||
|
64
Describer/DefaultDescriber.php
Normal file
64
Describer/DefaultDescriber.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the ApiDocBundle package.
|
||||
*
|
||||
* (c) EXSyst
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\Describer;
|
||||
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
|
||||
/**
|
||||
* Makes the swagger documentation valid even if there are missing fields.
|
||||
*
|
||||
* @author Ener-Getick <egetick@gmail.com>
|
||||
*/
|
||||
class DefaultDescriber implements DescriberInterface
|
||||
{
|
||||
public function describe(Swagger $api)
|
||||
{
|
||||
// Info
|
||||
$info = $api->getInfo();
|
||||
if (null === $info->getTitle()) {
|
||||
$info->setTitle('');
|
||||
}
|
||||
if (null === $info->getVersion()) {
|
||||
$info->setVersion('0.0.0');
|
||||
}
|
||||
|
||||
// Paths
|
||||
$paths = $api->getPaths();
|
||||
foreach ($paths as $uri => $path) {
|
||||
// Path Parameters
|
||||
preg_match_all('/\{(.+)\}/SU', $uri, $matches);
|
||||
$pathParameters = $matches[1];
|
||||
|
||||
foreach ($path->getMethods() as $method) {
|
||||
$operation = $path->getOperation($method);
|
||||
$parameters = $operation->getParameters();
|
||||
|
||||
// Default Path Parameters
|
||||
foreach ($pathParameters as $pathParameter) {
|
||||
if ($parameters->has($pathParameter, 'path')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parameters->get($pathParameter, 'path')
|
||||
->setRequired(true)
|
||||
->setType('string');
|
||||
}
|
||||
|
||||
// Default Response
|
||||
if (0 === iterator_count($operation->getResponses())) {
|
||||
$defaultResponse = $operation->getResponses()->get('default');
|
||||
$defaultResponse->setDescription('');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\Describer;
|
||||
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
|
||||
interface DescriberInterface
|
||||
{
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\Describer;
|
||||
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
|
||||
class ExternalDocDescriber implements DescriberInterface
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ namespace EXSyst\Bundle\ApiDocBundle\Describer;
|
||||
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use EXSyst\Bundle\ApiDocBundle\RouteDescriber\RouteDescriberInterface;
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
@ -16,9 +16,22 @@ class SwaggerPhpDescriber extends ExternalDocDescriber
|
||||
public function __construct(string $projectPath, bool $overwrite = false)
|
||||
{
|
||||
parent::__construct(function () use ($projectPath) {
|
||||
$annotation = \Swagger\scan($projectPath);
|
||||
// Catch notices as the documentation can be completed by other describers
|
||||
$prevHandler = set_error_handler(function ($type, $message, $file, $line, $context) use (&$prevHandler) {
|
||||
if (E_USER_NOTICE === $type || E_USER_WARNING === $type) {
|
||||
return;
|
||||
}
|
||||
|
||||
return json_decode(json_encode($annotation));
|
||||
return null !== $prevHandler && call_user_func($prevHandler, $type, $message, $file, $line, $context);
|
||||
});
|
||||
|
||||
try {
|
||||
$annotation = \Swagger\scan($projectPath);
|
||||
|
||||
return json_decode(json_encode($annotation));
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}, $overwrite);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,10 @@
|
||||
<tag name="exsyst_api_doc.describer" priority="-100" />
|
||||
</service>
|
||||
|
||||
<service id="exsyst_api_doc.describers.default" class="EXSyst\Bundle\ApiDocBundle\Describer\DefaultDescriber" public="false">
|
||||
<tag name="exsyst_api_doc.describer" priority="-1000" />
|
||||
</service>
|
||||
|
||||
<!-- Routing Extractors -->
|
||||
<service id="exsyst_api_doc.route_describers.route_metadata" class="EXSyst\Bundle\ApiDocBundle\RouteDescriber\RouteMetadataDescriber" public="false">
|
||||
<tag name="exsyst_api_doc.route_describer" priority="-50" />
|
||||
|
@ -12,8 +12,8 @@
|
||||
namespace EXSyst\Bundle\ApiDocBundle\RouteDescriber;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use EXSyst\Swagger\Parameter;
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Parameter;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\RouteDescriber;
|
||||
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use phpDocumentor\Reflection\DocBlockFactoryInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
@ -48,10 +48,14 @@ class PhpDocDescriber implements RouteDescriberInterface
|
||||
if (null !== $docBlock) {
|
||||
$operation->setSummary($docBlock->getSummary());
|
||||
$operation->setDescription((string) $docBlock->getDescription());
|
||||
$operation->setDeprecated($operation->getDeprecated() || $docBlock->hasTag('deprecated'));
|
||||
if ($docBlock->hasTag('deprecated')) {
|
||||
$operation->setDeprecated(true);
|
||||
}
|
||||
}
|
||||
if (null !== $classDocBlock) {
|
||||
$operation->setDeprecated($operation->getDeprecated() || $classDocBlock->hasTag('deprecated'));
|
||||
if ($classDocBlock->hasTag('deprecated')) {
|
||||
$operation->setDeprecated(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\RouteDescriber;
|
||||
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
interface RouteDescriberInterface
|
||||
|
@ -11,8 +11,8 @@
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\RouteDescriber;
|
||||
|
||||
use EXSyst\Swagger\Operation;
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Operation;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
@ -27,7 +27,7 @@ trait RouteDescriberTrait
|
||||
*/
|
||||
private function getOperations(Swagger $api, Route $route)
|
||||
{
|
||||
$path = $api->getPaths()->get($route->getPath());
|
||||
$path = $api->getPaths()->get($this->normalizePath($route->getPath()));
|
||||
$methods = $route->getMethods() ?: Swagger::$METHODS;
|
||||
foreach ($methods as $method) {
|
||||
$method = strtolower($method);
|
||||
@ -40,4 +40,13 @@ trait RouteDescriberTrait
|
||||
|
||||
return $operations;
|
||||
}
|
||||
|
||||
private function normalizePath(string $path)
|
||||
{
|
||||
if (substr($path, -10) === '.{_format}') {
|
||||
$path = substr($path, 0, -10);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\RouteDescriber;
|
||||
|
||||
use EXSyst\Swagger\Swagger;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
class RouteMetadataDescriber implements RouteDescriberInterface
|
||||
|
27
Tests/Describer/AbstractDescriberTest.php
Normal file
27
Tests/Describer/AbstractDescriberTest.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the ApiDocBundle package.
|
||||
*
|
||||
* (c) EXSyst
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\Tests\Describer;
|
||||
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
|
||||
abstract class AbstractDescriberTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $describer;
|
||||
|
||||
protected function getSwaggerDoc(): Swagger
|
||||
{
|
||||
$api = new Swagger();
|
||||
$this->describer->describe($api);
|
||||
|
||||
return $api;
|
||||
}
|
||||
}
|
32
Tests/Describer/SwaggerPhpDescriberTest.php
Normal file
32
Tests/Describer/SwaggerPhpDescriberTest.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the ApiDocBundle package.
|
||||
*
|
||||
* (c) EXSyst
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace EXSyst\Bundle\ApiDocBundle\Tests\Describer;
|
||||
|
||||
use EXSyst\Bundle\ApiDocBundle\Describer\SwaggerPhpDescriber;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
|
||||
class SwaggerPhpDescriberTest extends AbstractDescriberTest
|
||||
{
|
||||
public function testDescribe()
|
||||
{
|
||||
$api = $this->getSwaggerDoc();
|
||||
$info = $api->getInfo();
|
||||
|
||||
$this->assertEquals('My Awesome App', $info->getTitle());
|
||||
$this->assertEquals('1.3', $info->getVersion());
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->describer = new SwaggerPhpDescriber(__DIR__.'/../Fixtures');
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ class ApiController
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/nelmio", methods={"POST"})
|
||||
* @Route("/nelmio/{foo}", methods={"POST"})
|
||||
* @ApiDoc(
|
||||
* description="This action is described."
|
||||
* )
|
||||
|
@ -22,7 +22,7 @@ class FunctionalTest extends WebTestCase
|
||||
$this->assertEquals(['https'], $operation->getSchemes());
|
||||
$this->assertEmpty($operation->getSummary());
|
||||
$this->assertEmpty($operation->getDescription());
|
||||
$this->assertFalse($operation->getDeprecated());
|
||||
$this->assertNull($operation->getDeprecated());
|
||||
|
||||
$parameters = $operation->getParameters();
|
||||
$this->assertTrue($parameters->has('user', 'path'));
|
||||
@ -35,10 +35,14 @@ class FunctionalTest extends WebTestCase
|
||||
|
||||
public function testNelmioAction()
|
||||
{
|
||||
$operation = $this->getOperation('/nelmio', 'post');
|
||||
$operation = $this->getOperation('/nelmio/{foo}', 'post');
|
||||
|
||||
$this->assertEquals('This action is described.', $operation->getDescription());
|
||||
$this->assertFalse($operation->getDeprecated());
|
||||
|
||||
$foo = $operation->getParameters()->get('foo', 'path');
|
||||
$this->assertTrue($foo->getRequired());
|
||||
$this->assertEquals('string', $foo->getType());
|
||||
}
|
||||
|
||||
public function testDeprecatedAction()
|
||||
@ -50,13 +54,12 @@ class FunctionalTest extends WebTestCase
|
||||
$this->assertTrue($operation->getDeprecated());
|
||||
}
|
||||
|
||||
public function testSwaggerPhpInfo()
|
||||
public function testApiPlatform()
|
||||
{
|
||||
$api = $this->getSwaggerDefinition();
|
||||
$info = $api->getInfo();
|
||||
|
||||
$this->assertEquals('My Awesome App', $info->getTitle());
|
||||
$this->assertEquals('1.3', $info->getVersion());
|
||||
$operation = $this->getOperation('/api/dummies', 'get');
|
||||
$operation = $this->getOperation('/api/foo', 'get');
|
||||
$operation = $this->getOperation('/api/foo', 'post');
|
||||
$operation = $this->getOperation('/api/dummies/{id}', 'get');
|
||||
}
|
||||
|
||||
private function getSwaggerDefinition()
|
||||
|
@ -11,7 +11,7 @@
|
||||
"require": {
|
||||
"php": "^7.0",
|
||||
"symfony/framework-bundle": "^3.2",
|
||||
"exsyst/swagger": "~0.1"
|
||||
"exsyst/swagger": "dev-master"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/validator": "^3.2",
|
||||
@ -24,7 +24,7 @@
|
||||
"phpdocumentor/reflection-docblock": "^3.1",
|
||||
"phpunit/phpunit": "^5.4",
|
||||
"zircote/swagger-php": "^2.0",
|
||||
"api-platform/core": "^2.0"
|
||||
"api-platform/core": "dev-master"
|
||||
},
|
||||
"suggest": {
|
||||
"nelmio/api-doc-bundle": "For using the ApiDoc annotation.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user