Merge pull request #945 from nelmio/REMOVEAPIDOC

[3.0] Remove the `@ApiDoc` annotation
This commit is contained in:
Guilhem N 2017-01-14 17:01:15 +01:00 committed by GitHub
commit 936b8390f2
7 changed files with 50 additions and 664 deletions

View File

@ -1,483 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Annotation;
use Symfony\Component\Routing\Route;
/**
* @Annotation
*/
class ApiDoc
{
/**
* Requirements are mandatory parameters in a route.
*
* @var array
*/
private $requirements = array();
/**
* Filters are optional parameters in the query string.
*
* @var array
*/
private $filters = array();
/**
* Parameters are data a client can send.
*
* @var array
*/
private $parameters = array();
/**
* Headers that client can send.
*
* @var array
*/
private $headers = array();
/**
* @var string
*/
private $input = null;
/**
* @var string
*/
private $output = null;
/**
* @var string
*/
private $link = null;
/**
* Most of the time, a single line of text describing the action.
*
* @var string
*/
private $description = null;
/**
* @var array
*/
private $response = array();
/**
* @var bool
*/
private $authentication = false;
/**
* @var array
*/
private $authenticationRoles = array();
/**
* @var bool
*/
private $deprecated = false;
/**
* @var array
*/
private $statusCodes = array();
/**
* @var array
*/
private $responseMap = array();
/**
* @var array
*/
private $tags = array();
public function __construct(array $data)
{
if (isset($data['description'])) {
$this->description = $data['description'];
}
if (isset($data['input'])) {
$this->input = $data['input'];
}
if (isset($data['filters'])) {
foreach ($data['filters'] as $filter) {
if (!isset($filter['name'])) {
throw new \InvalidArgumentException('A "filter" element has to contain a "name" attribute');
}
$name = $filter['name'];
unset($filter['name']);
$this->addFilter($name, $filter);
}
}
if (isset($data['requirements'])) {
foreach ($data['requirements'] as $requirement) {
if (!isset($requirement['name'])) {
throw new \InvalidArgumentException('A "requirement" element has to contain a "name" attribute');
}
$name = $requirement['name'];
unset($requirement['name']);
$this->addRequirement($name, $requirement);
}
}
if (isset($data['parameters'])) {
foreach ($data['parameters'] as $parameter) {
if (!isset($parameter['name'])) {
throw new \InvalidArgumentException('A "parameter" element has to contain a "name" attribute');
}
if (!isset($parameter['dataType'])) {
throw new \InvalidArgumentException(sprintf(
'"%s" parameter element has to contain a "dataType" attribute',
$parameter['name']
));
}
$name = $parameter['name'];
unset($parameter['name']);
$this->addParameter($name, $parameter);
}
}
if (isset($data['headers'])) {
foreach ($data['headers'] as $header) {
if (!isset($header['name'])) {
throw new \InvalidArgumentException('A "header" element has to contain a "name" attribute');
}
$name = $header['name'];
unset($header['name']);
$this->addHeader($name, $header);
}
}
if (isset($data['output'])) {
$this->output = $data['output'];
}
if (isset($data['statusCodes'])) {
foreach ($data['statusCodes'] as $statusCode => $description) {
$this->addStatusCode($statusCode, $description);
}
}
if (isset($data['authentication'])) {
$this->setAuthentication((bool) $data['authentication']);
}
if (isset($data['authenticationRoles'])) {
foreach ($data['authenticationRoles'] as $key => $role) {
$this->authenticationRoles[] = $role;
}
}
if (isset($data['deprecated'])) {
$this->deprecated = $data['deprecated'];
}
if (isset($data['tags'])) {
if (is_array($data['tags'])) {
foreach ($data['tags'] as $tag => $colorCode) {
if (is_numeric($tag)) {
$this->addTag($colorCode);
} else {
$this->addTag($tag, $colorCode);
}
}
} else {
$this->tags[] = $data['tags'];
}
}
if (isset($data['responseMap'])) {
$this->responseMap = $data['responseMap'];
if (isset($this->responseMap[200])) {
$this->output = $this->responseMap[200];
}
}
}
/**
* @param string $name
* @param array $filter
*/
public function addFilter($name, array $filter)
{
$this->filters[$name] = $filter;
}
/**
* @param string $statusCode
* @param mixed $description
*/
public function addStatusCode($statusCode, $description)
{
$this->statusCodes[$statusCode] = !is_array($description) ? array($description) : $description;
}
/**
* @param string $tag
* @param string $colorCode
*/
public function addTag($tag, $colorCode = '#d9534f')
{
$this->tags[$tag] = $colorCode;
}
/**
* @param string $name
* @param array $requirement
*/
public function addRequirement($name, array $requirement)
{
$this->requirements[$name] = $requirement;
}
/**
* @param array $requirements
*/
public function setRequirements(array $requirements)
{
$this->requirements = array_merge($this->requirements, $requirements);
}
/**
* @return string|null
*/
public function getInput()
{
return $this->input;
}
/**
* @return string|null
*/
public function getOutput()
{
return $this->output;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* @param string $link
*/
public function setLink($link)
{
$this->link = $link;
}
/**
* @param string $name
* @param array $parameter
*/
public function addParameter($name, array $parameter)
{
$this->parameters[$name] = $parameter;
}
/**
* @param array $parameters
*/
public function setParameters(array $parameters)
{
$this->parameters = $parameters;
}
/**
* @param $name
* @param array $header
*/
public function addHeader($name, array $header)
{
$this->headers[$name] = $header;
}
/**
* Sets the response data as processed by the parsers - same format as parameters.
*
* @param array $response
*/
public function setResponse(array $response)
{
$this->response = $response;
}
/**
* @return bool
*/
public function getAuthentication()
{
return $this->authentication;
}
/**
* @param bool $authentication
*/
public function setAuthentication($authentication)
{
$this->authentication = $authentication;
}
/**
* @return array
*/
public function getAuthenticationRoles()
{
return $this->authenticationRoles;
}
/**
* @param array $authenticationRoles
*/
public function setAuthenticationRoles($authenticationRoles)
{
$this->authenticationRoles = $authenticationRoles;
}
/**
* @return bool
*/
public function getDeprecated()
{
return $this->deprecated;
}
/**
* @return array
*/
public function getFilters()
{
return $this->filters;
}
/**
* @return array
*/
public function getRequirements()
{
return $this->requirements;
}
/**
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
/**
* @param bool $deprecated
*
* @return $this
*/
public function setDeprecated($deprecated)
{
$this->deprecated = (bool) $deprecated;
return $this;
}
/**
* @return array
*/
public function toArray()
{
if ($description = $this->description) {
$data['description'] = $description;
}
if ($link = $this->link) {
$data['link'] = $link;
}
if ($filters = $this->filters) {
$data['filters'] = $filters;
}
if ($parameters = $this->parameters) {
$data['parameters'] = $parameters;
}
if ($headers = $this->headers) {
$data['headers'] = $headers;
}
if ($requirements = $this->requirements) {
$data['requirements'] = $requirements;
}
if ($response = $this->response) {
$data['response'] = $response;
}
if ($statusCodes = $this->statusCodes) {
$data['statusCodes'] = $statusCodes;
}
if ($tags = $this->tags) {
$data['tags'] = $tags;
}
$data['authentication'] = $this->authentication;
$data['authenticationRoles'] = $this->authenticationRoles;
$data['deprecated'] = $this->deprecated;
return $data;
}
/**
* @return array
*/
public function getResponseMap()
{
if (!isset($this->responseMap[200]) && null !== $this->output) {
$this->responseMap[200] = $this->output;
}
return $this->responseMap;
}
}

View File

@ -36,7 +36,6 @@ final class NelmioApiDocExtension extends Extension
$routeCollectionBuilder->replaceArgument(0, $config['routes']['path_patterns']); $routeCollectionBuilder->replaceArgument(0, $config['routes']['path_patterns']);
// Import services needed for each library // Import services needed for each library
$loader->load('nelmio_apidoc.xml');
if (class_exists(DocBlockFactory::class)) { if (class_exists(DocBlockFactory::class)) {
$loader->load('php_doc.xml'); $loader->load('php_doc.xml');
} }

View File

@ -1,14 +0,0 @@
<?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="nelmio_api_doc.route_describers.nelmio_annotation" class="Nelmio\ApiDocBundle\RouteDescriber\NelmioAnnotationDescriber" public="false">
<argument type="service" id="annotation_reader" />
<tag name="nelmio_api_doc.route_describer" priority="-200" />
</service>
</services>
</container>

View File

@ -1,131 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\RouteDescriber;
use Doctrine\Common\Annotations\Reader;
use EXSyst\Component\Swagger\Parameter;
use EXSyst\Component\Swagger\Swagger;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Symfony\Component\Routing\Route;
final class NelmioAnnotationDescriber implements RouteDescriberInterface
{
use RouteDescriberTrait;
private $annotationReader;
public function __construct(Reader $annotationReader)
{
$this->annotationReader = $annotationReader;
}
public function describe(Swagger $api, Route $route, \ReflectionMethod $reflectionMethod)
{
$annotation = $this->annotationReader->getMethodAnnotation($reflectionMethod, ApiDoc::class);
if (null === $annotation) {
return;
}
// some fields aren't available otherwise
$annotationArray = $annotation->toArray();
foreach ($this->getOperations($api, $route) as $operation) {
if (null === $operation->getDescription()) {
$operation->setDescription($annotation->getDescription());
}
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']) && $configuration['required']) {
$parameter->setRequired(true);
}
$this->configureParameter($parameter, $configuration);
}
// Query/Path required parameters
$compiledRoute = $route->compile();
$pathVariables = $compiledRoute->getVariables();
$hostVariables = $compiledRoute->getHostVariables();
foreach ($annotation->getRequirements() as $name => $configuration) {
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);
}
// External docs
if (isset($annotationArray['link'])) {
$operation->getExternalDocs()->setUrl($annotationArray['link']);
}
// Responses
if (isset($annotationArray['statusCodes'])) {
$responses = $operation->getResponses();
foreach ($annotationArray['statusCodes'] as $statusCode => $description) {
$response = $responses->get($statusCode);
$response->setDescription($description);
}
}
}
}
private function configureParameter(Parameter $parameter, array $configuration)
{
$dataType = null;
if (isset($configuration['dataType'])) {
$dataType = $configuration['dataType'];
} elseif ($configuration['requirement']) {
$dataType = $configuration['requirement'];
}
if ('[]' === substr($requirement, -2)) {
$parameter->setType('array');
$items = $parameter;
do {
$items->setCollectionFormat('multi');
$requirement = substr($requirement, 0, -2);
$items = $items->getItems();
} while ('[]' === substr($requirement, -2));
$items->setType('string');
$items->setFormat($requirement);
} else {
$parameter->setType('string');
$parameter->setFormat($requirement);
}
if (isset($configuration['description'])) {
$parameter->setDescription($configuration['description']);
}
if (isset($configuration['default'])) {
$parameter->setDefault($configuration['default']);
}
}
}

View File

@ -62,16 +62,6 @@ class ApiController
{ {
} }
/**
* @Route("/nelmio/{foo}", methods={"POST"})
* @ApiDoc(
* description="This action is described."
* )
*/
public function nelmioAction()
{
}
/** /**
* This action is deprecated. * This action is deprecated.
* *

View File

@ -92,18 +92,6 @@ class FunctionalTest extends WebTestCase
$this->assertFalse($parameters->has('_format', 'path')); $this->assertFalse($parameters->has('_format', 'path'));
} }
public function testNelmioAction()
{
$operation = $this->getOperation('/api/nelmio/{foo}', 'post');
$this->assertEquals('This action is described.', $operation->getDescription());
$this->assertNull($operation->getDeprecated());
$foo = $operation->getParameters()->get('foo', 'path');
$this->assertTrue($foo->getRequired());
$this->assertEquals('string', $foo->getType());
}
public function testDeprecatedAction() public function testDeprecatedAction()
{ {
$operation = $this->getOperation('/api/deprecated', 'get'); $operation = $this->getOperation('/api/deprecated', 'get');

View File

@ -2,20 +2,57 @@
NelmioApiDocBundle has been entirely refactored in 3.0 to focus on Swagger NelmioApiDocBundle has been entirely refactored in 3.0 to focus on Swagger
and most of it has changed. and most of it has changed.
However, we tried to keep its API as familiar as possible: the `@ApiDoc`
annotation is kept and the bundle remains the same (it is required the same
way it was in 2.0).
## Upgrade Your Annotations ## Upgrade Your Annotations
Some fields of the `@ApiDoc` annotation were removed as they are no The `@ApiDoc` annotation has been removed and you must now use
longer used by the bundle: [Swagger-php](https://github.com/zircote/swagger-php) annotations.
- `section` An upgrade example:
- `views` ```php
- `host` use Nelmio\ApiDocBundle\Annotation\ApiDoc;
- `cache`
- `resource` class YourController extends Controller
- `resourceDescription` {
- `https`, add a scheme requirement to your route instead /**
- `documentation`, use `description` instead * This is a description of your API method.
*
* @ApiDoc(
* filters={
* {"name"="a-filter", "dataType"="integer"},
* {"name"="another-filter", "dataType"="string", "pattern"="(foo|bar) ASC|DESC"}
* }
* )
*/
public function getAction()
{
}
}
```
will become:
```php
use Swagger\Annotations as SWG;
class YourController extends Controller
{
/**
* This is a description of your API method.
*
* @SWG\Parameter(
* name="a-filter",
* in="query",
* type="integer"
* )
* @SWG\Parameter(
* name="another-filter",
* in="query",
* type="string",
* format="(foo|bar) ASC|DESC"
* )
*/
public function getAction()
{
}
}
```