mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 15:51:48 +03:00
Add FOSRestBundle support
This commit is contained in:
parent
7a7f78a53f
commit
ffda7801f6
@ -39,15 +39,15 @@ class EXSystApiDocExtension extends Extension
|
||||
|
||||
$loader->load('services.xml');
|
||||
|
||||
// Removes useless services
|
||||
if (!class_exists(ApiDoc::class)) {
|
||||
$container->removeDefinition('exsyst_api_doc.route_describers.nelmio_annotation');
|
||||
// Import services needed for each library
|
||||
if (class_exists(ApiDoc::class)) {
|
||||
$loader->load('nelmio_apidoc.xml');
|
||||
}
|
||||
if (!class_exists(DocBlockFactory::class)) {
|
||||
$container->removeDefinition('exsyst_api_doc.route_describers.php_doc');
|
||||
if (class_exists(DocBlockFactory::class)) {
|
||||
$loader->load('php_doc.xml');
|
||||
}
|
||||
if (!class_exists(Swagger::class)) {
|
||||
$container->removeDefinition('exsyst_api_doc.describers.swagger_php');
|
||||
if (class_exists(Swagger::class)) {
|
||||
$loader->load('swagger_php.xml');
|
||||
}
|
||||
|
||||
$bundles = $container->getParameter('kernel.bundles');
|
||||
|
@ -34,24 +34,8 @@ class DefaultDescriber implements DescriberInterface
|
||||
// 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())) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
<argument type="service" id="exsyst_api_doc.describers.api_platform.documentation" />
|
||||
<argument type="service" id="api_platform.swagger.normalizer.documentation" />
|
||||
|
||||
<tag name="exsyst_api_doc.describer" priority="-150" />
|
||||
<tag name="exsyst_api_doc.describer" priority="-200" />
|
||||
</service>
|
||||
|
||||
<service id="exsyst_api_doc.describers.api_platform.documentation" class="ApiPlatform\Core\Documentation\Documentation" public="false">
|
||||
|
14
Resources/config/nelmio_apidoc.xml
Normal file
14
Resources/config/nelmio_apidoc.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<service id="exsyst_api_doc.route_describers.nelmio_annotation" class="EXSyst\Bundle\ApiDocBundle\RouteDescriber\NelmioAnnotationDescriber" public="false">
|
||||
<argument type="service" id="annotation_reader" />
|
||||
|
||||
<tag name="exsyst_api_doc.route_describer" priority="-250" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
12
Resources/config/php_doc.xml
Normal file
12
Resources/config/php_doc.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<service id="exsyst_api_doc.route_describers.php_doc" class="EXSyst\Bundle\ApiDocBundle\RouteDescriber\PhpDocDescriber" public="false">
|
||||
<tag name="exsyst_api_doc.route_describer" priority="-1000" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
@ -9,12 +9,6 @@
|
||||
</service>
|
||||
|
||||
<!-- Extractors -->
|
||||
<service id="exsyst_api_doc.describers.swagger_php" class="EXSyst\Bundle\ApiDocBundle\Describer\SwaggerPhpDescriber" public="false">
|
||||
<argument>%kernel.root_dir%</argument>
|
||||
|
||||
<tag name="exsyst_api_doc.describer" priority="-150" />
|
||||
</service>
|
||||
|
||||
<service id="exsyst_api_doc.describers.route" class="EXSyst\Bundle\ApiDocBundle\Describer\RouteDescriber" public="false">
|
||||
<argument type="service" id="service_container" />
|
||||
<argument type="service" id="router" />
|
||||
@ -30,16 +24,6 @@
|
||||
|
||||
<!-- 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" />
|
||||
</service>
|
||||
|
||||
<service id="exsyst_api_doc.route_describers.php_doc" class="EXSyst\Bundle\ApiDocBundle\RouteDescriber\PhpDocDescriber" public="false">
|
||||
<tag name="exsyst_api_doc.route_describer" priority="-70" />
|
||||
</service>
|
||||
|
||||
<service id="exsyst_api_doc.route_describers.nelmio_annotation" class="EXSyst\Bundle\ApiDocBundle\RouteDescriber\NelmioAnnotationDescriber" public="false">
|
||||
<argument type="service" id="annotation_reader" />
|
||||
|
||||
<tag name="exsyst_api_doc.route_describer" priority="-100" />
|
||||
</service>
|
||||
</services>
|
||||
|
14
Resources/config/swagger_php.xml
Normal file
14
Resources/config/swagger_php.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<service id="exsyst_api_doc.describers.swagger_php" class="EXSyst\Bundle\ApiDocBundle\Describer\SwaggerPhpDescriber" public="false">
|
||||
<argument>%kernel.root_dir%</argument>
|
||||
|
||||
<tag name="exsyst_api_doc.describer" priority="-300" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
82
RouteDescriber/FosRestDescriber.php
Normal file
82
RouteDescriber/FosRestDescriber.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?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\RouteDescriber;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use EXSyst\Component\Swagger\Parameter;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use FOS\RestBundle\Controller\Annotations\RequestParam;
|
||||
use FOS\RestBundle\Controller\Annotations\QueryParam;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Regex;
|
||||
|
||||
class FosRestDescriber implements RouteDescriberInterface
|
||||
{
|
||||
use RouteDescriberTrait;
|
||||
|
||||
private $annotationReader;
|
||||
|
||||
public function __construct(Reader $annotationReader)
|
||||
{
|
||||
$this->annotationReader = $annotationReader;
|
||||
}
|
||||
|
||||
public function describe(Swagger $api, Route $route, \ReflectionMethod $reflectionMethod)
|
||||
{
|
||||
$annotations = $this->annotationReader->getMethodAnnotations();
|
||||
$annotations = array_filter($annotations, function ($value) {
|
||||
return $value instanceof RequestParam || $value instanceof QueryParam;
|
||||
});
|
||||
|
||||
foreach ($this->getOperations($api, $route) as $operation) {
|
||||
foreach ($annotations as $annotation) {
|
||||
$in = $annotation instanceof QueryParam ? 'query' : 'formData';
|
||||
$parameter = $operation->getParameters()->get($annotation->getKey(), $in);
|
||||
|
||||
$parameter->setAllowEmptyValue($annotation->nullable && $annotation->allowBlank);
|
||||
$parameter->setType($annotation->map ? 'array' : 'string');
|
||||
$parameter->setDefault($annotation->getDefault());
|
||||
if (null === $parameter->getDescription()) {
|
||||
$parameter->setDescription($annotation->description);
|
||||
}
|
||||
|
||||
$normalizedRequirements = $this->normalizeRequirements($annotation->requirements);
|
||||
if (null !== $normalizedRequirements) {
|
||||
$parameter->setFormat($normalizedRequirements);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function normalizeRequirements($requirements)
|
||||
{
|
||||
// if pattern
|
||||
if (isset($requirements['rule'])) {
|
||||
return (string) $requirements['rule'];
|
||||
}
|
||||
if (is_string($requirements)) {
|
||||
return $requirements;
|
||||
}
|
||||
// if custom constraint
|
||||
if ($requirements instanceof Constraint) {
|
||||
if ($requirements instanceof Regex) {
|
||||
return $requirements->getHtmlPattern();
|
||||
}
|
||||
|
||||
$reflectionClass = new \ReflectionClass($requirements);
|
||||
|
||||
return $reflectionClass->getShortName();
|
||||
}
|
||||
}
|
||||
}
|
@ -39,28 +39,41 @@ class NelmioAnnotationDescriber implements RouteDescriberInterface
|
||||
$annotationArray = $annotation->toArray();
|
||||
|
||||
foreach ($this->getOperations($api, $route) as $operation) {
|
||||
if ($annotation->getDescription()) {
|
||||
if (null === $operation->getDescription()) {
|
||||
$operation->setDescription($annotation->getDescription());
|
||||
}
|
||||
$operation->setDeprecated($operation->getDeprecated() || $annotation->getDeprecated());
|
||||
if (null === $operation->getDeprecated() && $annotation->getDeprecated()) {
|
||||
$operation->setDeprecated(true);
|
||||
}
|
||||
|
||||
// Request parameters
|
||||
foreach ($annotation->getParameters() as $name => $configuration) {
|
||||
$parameter = $operation->getParameters()->get($name, 'formData');
|
||||
if (isset($configuration['required'])) {
|
||||
$parameter->setRequired($parameter->getRequired() || $configuration['required']);
|
||||
if (isset($configuration['required']) && $configuration['required']) {
|
||||
$parameter->setRequired(true);
|
||||
}
|
||||
|
||||
$this->configureParameter($parameter, $configuration);
|
||||
}
|
||||
|
||||
// Query parameters
|
||||
// Query/Path required parameters
|
||||
$compiledRoute = $route->compile();
|
||||
$pathVariables = $compiledRoute->getVariables();
|
||||
$hostVariables = $compiledRoute->getHostVariables();
|
||||
foreach ($annotation->getRequirements() as $name => $configuration) {
|
||||
$parameter = $operation->getParameters()->get($name, 'query');
|
||||
if (in_array($name, $pathVariables)) {
|
||||
$in = 'path';
|
||||
} elseif (!in_array($name, $hostVariables)) {
|
||||
$in = 'query';
|
||||
} else { // Host variables not supported
|
||||
continue;
|
||||
}
|
||||
$parameter = $operation->getParameters()->get($name, $in);
|
||||
$parameter->setRequired(true);
|
||||
|
||||
$this->configureParameter($parameter, $configuration);
|
||||
}
|
||||
// Optional Query parameters
|
||||
foreach ($annotation->getFilters() as $name => $configuration) {
|
||||
$parameter = $operation->getParameters()->get($name, 'query');
|
||||
$this->configureParameter($parameter, $configuration);
|
||||
|
@ -46,8 +46,12 @@ class PhpDocDescriber implements RouteDescriberInterface
|
||||
|
||||
foreach ($this->getOperations($api, $route) as $operation) {
|
||||
if (null !== $docBlock) {
|
||||
$operation->setSummary($docBlock->getSummary());
|
||||
$operation->setDescription((string) $docBlock->getDescription());
|
||||
if (null === $operation->getSummary() && '' !== $docBlock->getSummary()) {
|
||||
$operation->setSummary($docBlock->getSummary());
|
||||
}
|
||||
if (null === $operation->getDescription() && '' !== (string) $docBlock->getDescription()) {
|
||||
$operation->setDescription((string) $docBlock->getDescription());
|
||||
}
|
||||
if ($docBlock->hasTag('deprecated')) {
|
||||
$operation->setDeprecated(true);
|
||||
}
|
||||
|
@ -23,11 +23,18 @@ class RouteMetadataDescriber implements RouteDescriberInterface
|
||||
foreach ($this->getOperations($api, $route) as $operation) {
|
||||
$operation->merge(['schemes' => $route->getSchemes()]);
|
||||
|
||||
foreach ($route->getRequirements() as $parameterName => $requirement) {
|
||||
$parameter = $operation->getParameters()->get($parameterName, 'path');
|
||||
$requirements = $route->getRequirements();
|
||||
$compiledRoute = $route->compile();
|
||||
|
||||
// Don't include path variables
|
||||
foreach ($compiledRoute->getPathVariables() as $pathVariable) {
|
||||
$parameter = $operation->getParameters()->get($pathVariable, 'path');
|
||||
$parameter->setRequired(true);
|
||||
$parameter->setType('string');
|
||||
$parameter->setFormat($requirement);
|
||||
|
||||
if (isset($requirements[$pathVariable])) {
|
||||
$parameter->setFormat($requirements[$pathVariable]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class FunctionalTest extends WebTestCase
|
||||
$operation = $this->getOperation('/nelmio/{foo}', 'post');
|
||||
|
||||
$this->assertEquals('This action is described.', $operation->getDescription());
|
||||
$this->assertFalse($operation->getDeprecated());
|
||||
$this->assertNull($operation->getDeprecated());
|
||||
|
||||
$foo = $operation->getParameters()->get('foo', 'path');
|
||||
$this->assertTrue($foo->getRequired());
|
||||
|
@ -11,7 +11,7 @@
|
||||
"require": {
|
||||
"php": "^7.0",
|
||||
"symfony/framework-bundle": "^3.2",
|
||||
"exsyst/swagger": "dev-master"
|
||||
"exsyst/swagger": "~0.2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/validator": "^3.2",
|
||||
@ -20,17 +20,20 @@
|
||||
"symfony/cache": "^3.2",
|
||||
"symfony/phpunit-bridge": "^3.2",
|
||||
"sensio/framework-extra-bundle": "^3.0",
|
||||
"phpunit/phpunit": "^5.4",
|
||||
|
||||
"nelmio/api-doc-bundle": "^2.0",
|
||||
"phpdocumentor/reflection-docblock": "^3.1",
|
||||
"phpunit/phpunit": "^5.4",
|
||||
"zircote/swagger-php": "^2.0",
|
||||
"api-platform/core": "dev-master"
|
||||
"api-platform/core": "dev-master",
|
||||
"friendsofsymfony/rest-bundle": "^2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"nelmio/api-doc-bundle": "For using the ApiDoc annotation.",
|
||||
"phpdocumentor/reflection-docblock": "For parsing php docs.",
|
||||
"zircote/swagger-php": "For using swagger annotations.",
|
||||
"api-platform/core": "For using an API oriented framework."
|
||||
"api-platform/core": "For using an API oriented framework.",
|
||||
"friendsofsymfony/rest-bundle": "For using the parameters annotations."
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user