Compare commits

..

15 commits

Author SHA1 Message Date
Ilyas Salikhov
10ee31bdaa
Merge pull request #24 from retailcrm/twig-deprecates
fix twig deprecates
2024-10-10 23:14:28 +03:00
Ilyas Salikhov
6946e8bdc9 fix twig deprecates 2024-10-10 23:07:49 +03:00
Ilyas Salikhov
a896abb3e2
Merge pull request #23 from retailcrm/attribute
Migrate annotation ApiDoc to attribute
2024-10-01 23:02:33 +03:00
Ilyas Salikhov
a9fceca8df Migrate annotation ApiDoc to attribute 2024-10-01 23:00:23 +03:00
Ilyas Salikhov
8135dec035
Merge pull request #22 from retailcrm/remove-unused-params
Remove unused params
2024-10-01 18:41:22 +03:00
Ilyas Salikhov
5db963666a remove unused cache annotation param 2024-10-01 18:38:58 +03:00
Ilyas Salikhov
990b781322 remove unused https annotation param 2024-10-01 18:33:15 +03:00
Ilyas Salikhov
e7c9fd4f56 remove unused authentication annotation param 2024-10-01 18:26:30 +03:00
Ilyas Salikhov
abbf032483 Remove unused argument 2024-10-01 17:43:18 +03:00
Ilyas Salikhov
49f4161b23
Merge pull request #21 from retailcrm/fos-rest-remove
Remove the support of FosRestBundle, DunglasApiBundle and JmsSecurityExtra
2024-10-01 17:35:38 +03:00
Ilyas Salikhov
3ef60f2926 remove JmsSecurityExtraHandler 2024-10-01 17:30:02 +03:00
Ilyas Salikhov
636eeb7cae Remove dunglasapibundle support 2024-10-01 17:26:49 +03:00
Ilyas Salikhov
e97eba7c1b Remove the support of fos-rest 2024-10-01 17:18:04 +03:00
Ilyas Salikhov
73f9b9e8a2
Merge pull request #20 from retailcrm/duglas-remove
remove the support of duglas
2024-10-01 16:42:22 +03:00
Ilyas Salikhov
4b6137f618 remove the support of duglas 2024-10-01 16:39:44 +03:00
56 changed files with 844 additions and 9468 deletions

View file

@ -1,41 +0,0 @@
dist: trusty
language: php
sudo: false
cache:
directories:
- $HOME/.composer/cache
matrix:
include:
- php: 5.4
env: SYMFONY_VERSION=2.3.*
- php: 5.5
env: SYMFONY_DEPRECATIONS_HELPER=weak
- php: 5.6
env: SYMFONY_VERSION=2.7.* COVERAGE=true
- php: 5.6
env: SYMFONY_VERSION=2.8.*
- php: 5.6
env: SYMFONY_VERSION=3.0.*
- php: 7.0
env: SYMFONY_DEPRECATIONS_HELPER=weak
- php: hhvm
env: SYMFONY_DEPRECATIONS_HELPER=weak
fast_finish: true
before_install:
- if [ "$COVERAGE" != "true" ] && [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then phpenv config-rm xdebug.ini; fi
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then echo "memory_limit=4096M" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi;
before_script:
- composer self-update
- if [ "$DEPENDENCIES" = "dev" ]; then perl -pi -e 's/^}$/,"minimum-stability":"dev"}/' composer.json; fi;
- if [ "$SYMFONY_VERSION" != "3.0.*" ] && [ "$SYMFONY_VERSION" != "2.8.*" ] && [ "$SYMFONY_VERSION" != "2.7.*" ]; then sed -i "/dunglas\/api-bundle/d;/symfony\/serializer/d" composer.json; fi;
- if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update; fi;
- composer update $COMPOSER_FLAGS
script:
- if [ "$COVERAGE" == "true" ]; then phpunit --coverage-text; else phpunit; fi

View file

@ -1,800 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* 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
{
public const DEFAULT_VIEW = 'default';
/**
* Requirements are mandatory parameters in a route.
*
* @var array
*/
private $requirements = [];
/**
* Which views is this route used. Defaults to "Default"
*
* @var array
*/
private $views = [];
/**
* Filters are optional parameters in the query string.
*
* @var array
*/
private $filters = [];
/**
* Parameters are data a client can send.
*
* @var array
*/
private $parameters = [];
/**
* Headers that client can send.
*
* @var array
*/
private $headers = [];
/**
* @var string
*/
private $input;
/**
* @var string
*/
private $inputs;
/**
* @var string
*/
private $output;
/**
* @var string
*/
private $link;
/**
* Most of the time, a single line of text describing the action.
*
* @var string
*/
private $description;
/**
* Section to group actions together.
*
* @var string
*/
private $section;
/**
* Extended documentation.
*
* @var string
*/
private $documentation;
/**
* @var bool
*/
private $resource = false;
/**
* @var string
*/
private $method;
/**
* @var string
*/
private $host;
/**
* @var string
*/
private $uri;
/**
* @var array
*/
private $response = [];
/**
* @var Route
*/
private $route;
/**
* @var bool
*/
private $https = false;
/**
* @var bool
*/
private $authentication = false;
/**
* @var array
*/
private $authenticationRoles = [];
/**
* @var int
*/
private $cache;
/**
* @var bool
*/
private $deprecated = false;
/**
* @var array
*/
private $statusCodes = [];
/**
* @var string|null
*/
private $resourceDescription;
/**
* @var array
*/
private $responseMap = [];
/**
* @var array
*/
private $parsedResponseMap = [];
/**
* @var array
*/
private $tags = [];
private ?string $scope = null;
public function __construct(array $data)
{
$this->resource = !empty($data['resource']) ? $data['resource'] : false;
if (isset($data['description'])) {
$this->description = $data['description'];
}
if (isset($data['input'])) {
$this->input = $data['input'];
}
if (isset($data['inputs'])) {
$this->inputs = $data['inputs'];
}
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['views'])) {
if (!is_array($data['views'])) {
$data['views'] = [$data['views']];
}
foreach ($data['views'] as $view) {
$this->addView($view);
}
}
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['cache'])) {
$this->setCache($data['cache']);
}
if (isset($data['section'])) {
$this->section = $data['section'];
}
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['https'])) {
$this->https = $data['https'];
}
if (isset($data['resourceDescription'])) {
$this->resourceDescription = $data['resourceDescription'];
}
if (isset($data['responseMap'])) {
$this->responseMap = $data['responseMap'];
if (isset($this->responseMap[200])) {
$this->output = $this->responseMap[200];
}
}
}
/**
* @param string $name
*/
public function addFilter($name, array $filter): void
{
$this->filters[$name] = $filter;
}
/**
* @param string $statusCode
*/
public function addStatusCode($statusCode, $description): void
{
$this->statusCodes[$statusCode] = !is_array($description) ? [$description] : $description;
}
/**
* @param string $tag
* @param string $colorCode
*/
public function addTag($tag, $colorCode = '#d9534f'): void
{
$this->tags[$tag] = $colorCode;
}
/**
* @param string $name
*/
public function addRequirement($name, array $requirement): void
{
$this->requirements[$name] = $requirement;
}
public function setRequirements(array $requirements): void
{
$this->requirements = array_merge($this->requirements, $requirements);
}
/**
* @return string|null
*/
public function getInput()
{
return $this->input;
}
/**
* @return array|null
*/
public function getInputs()
{
return $this->inputs;
}
/**
* @return string|null
*/
public function getOutput()
{
return $this->output;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription($description): void
{
$this->description = $description;
}
/**
* @param string $link
*/
public function setLink($link): void
{
$this->link = $link;
}
/**
* @param string $section
*/
public function setSection($section): void
{
$this->section = $section;
}
/**
* @return string
*/
public function getSection()
{
return $this->section;
}
/**
* @return array
*/
public function addView($view)
{
$this->views[] = $view;
}
/**
* @return array
*/
public function getViews()
{
return $this->views;
}
/**
* @param string $documentation
*/
public function setDocumentation($documentation): void
{
$this->documentation = $documentation;
}
/**
* @return string
*/
public function getDocumentation()
{
return $this->documentation;
}
/**
* @return bool
*/
public function isResource()
{
return (bool) $this->resource;
}
public function getResource()
{
return $this->resource && is_string($this->resource) ? $this->resource : false;
}
/**
* @param string $name
*/
public function addParameter($name, array $parameter): void
{
$this->parameters[$name] = $parameter;
}
public function setParameters(array $parameters): void
{
$this->parameters = $parameters;
}
public function addHeader($name, array $header): void
{
$this->headers[$name] = $header;
}
/**
* Sets the response data as processed by the parsers - same format as parameters
*/
public function setResponse(array $response): void
{
$this->response = $response;
}
public function setRoute(Route $route): void
{
$this->route = $route;
if (method_exists($route, 'getHost')) {
$this->host = $route->getHost() ?: null;
// replace route placeholders
foreach ($route->getDefaults() as $key => $value) {
if (null !== $this->host && is_string($value)) {
$this->host = str_replace('{' . $key . '}', $value, $this->host);
}
}
} else {
$this->host = null;
}
$this->uri = $route->getPath();
$this->method = $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY';
}
/**
* @return Route
*/
public function getRoute()
{
return $this->route;
}
/**
* @return string
*/
public function getHost()
{
return $this->host;
}
/**
* @param string $host
*/
public function setHost($host): void
{
$this->host = $host;
}
/**
* @return bool
*/
public function getHttps()
{
return $this->https;
}
/**
* @param bool $https
*/
public function setHttps($https): void
{
$this->https = $https;
}
/**
* @return bool
*/
public function getAuthentication()
{
return $this->authentication;
}
/**
* @param bool $authentication
*/
public function setAuthentication($authentication): void
{
$this->authentication = $authentication;
}
/**
* @return array
*/
public function getAuthenticationRoles()
{
return $this->authenticationRoles;
}
/**
* @param array $authenticationRoles
*/
public function setAuthenticationRoles($authenticationRoles): void
{
$this->authenticationRoles = $authenticationRoles;
}
/**
* @return int
*/
public function getCache()
{
return $this->cache;
}
/**
* @param int $cache
*/
public function setCache($cache): void
{
$this->cache = (int) $cache;
}
/**
* @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 string
*/
public function getMethod()
{
return $this->method;
}
public function setScope(string $scope): void
{
$this->scope = $scope;
}
public function getScope(): ?string
{
return $this->scope;
}
/**
* @return array
*/
public function toArray()
{
$data = [
'method' => $this->method,
'uri' => $this->uri,
];
if ($host = $this->host) {
$data['host'] = $host;
}
if ($description = $this->description) {
$data['description'] = $description;
}
if ($link = $this->link) {
$data['link'] = $link;
}
if ($documentation = $this->documentation) {
$data['documentation'] = $documentation;
}
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 ($views = $this->views) {
$data['views'] = $views;
}
if ($response = $this->response) {
$data['response'] = $response;
}
if ($parsedResponseMap = $this->parsedResponseMap) {
$data['parsedResponseMap'] = $parsedResponseMap;
}
if ($statusCodes = $this->statusCodes) {
$data['statusCodes'] = $statusCodes;
}
if ($section = $this->section) {
$data['section'] = $section;
}
if ($cache = $this->cache) {
$data['cache'] = $cache;
}
if ($tags = $this->tags) {
$data['tags'] = $tags;
}
if ($resourceDescription = $this->resourceDescription) {
$data['resourceDescription'] = $resourceDescription;
}
$data['https'] = $this->https;
$data['authentication'] = $this->authentication;
$data['authenticationRoles'] = $this->authenticationRoles;
$data['deprecated'] = $this->deprecated;
$data['scope'] = $this->scope;
return $data;
}
/**
* @return string|null
*/
public function getResourceDescription()
{
return $this->resourceDescription;
}
/**
* @return array
*/
public function getResponseMap()
{
if (!isset($this->responseMap[200]) && null !== $this->output) {
$this->responseMap[200] = $this->output;
}
return $this->responseMap;
}
/**
* @return array
*/
public function getParsedResponseMap()
{
return $this->parsedResponseMap;
}
/**
* @param int $statusCode
*/
public function setResponseForStatusCode($model, $type, $statusCode = 200): void
{
$this->parsedResponseMap[$statusCode] = ['type' => $type, 'model' => $model];
if (200 == $statusCode && $this->response !== $model) {
$this->response = $model;
}
}
}

500
Attribute/ApiDoc.php Normal file
View file

@ -0,0 +1,500 @@
<?php
namespace Nelmio\ApiDocBundle\Attribute;
use Symfony\Component\Routing\Route;
#[\Attribute(\Attribute::TARGET_METHOD)]
class ApiDoc
{
public const DEFAULT_VIEW = 'default';
/**
* Requirements are mandatory parameters in a route.
*
* @var array<string, array<string, string>>
*/
private array $requirements = [];
/**
* Which views is this route used. Defaults to "Default"
*
* @var string[]
*/
private array $views = [];
/**
* Filters are optional parameters in the query string.
*
* @var array<string, array<string, string>>
*/
private array $filters = [];
/**
* Parameters are data a client can send.
*
* @var array<string, array<string, mixed>>
*/
private array $parameters = [];
/**
* Headers that client can send.
*
* @var array<string, array<string, mixed>>
*/
private array $headers = [];
private ?string $link = null;
/**
* Extended documentation.
*/
private ?string $documentation = null;
private Route $route;
private ?string $host = null;
private string $method;
private string $uri;
private array $response = [];
/**
* @var array<int|string, string[]>
*/
private array $statusCodes = [];
/**
* @var array<int, array<mixed>>
*/
private array $responseMap = [];
private array $parsedResponseMap = [];
/**
* @var array<string|int, string>
*/
private array $tags = [];
private ?string $scope = null;
/**
* @param string[]|string|null $description
*/
public function __construct(
private string|bool $resource = false,
private array|string|null $description = null,
private string|array|null $input = null,
private ?array $inputs = null,
private string|array|null $output = null,
private ?string $section = null,
private bool $deprecated = false,
private ?string $resourceDescription = null,
?array $filters = null,
?array $requirements = null,
array|string|null $views = null,
?array $parameters = null,
?array $headers = null,
?array $statusCodes = null,
array|string|int|null $tags = null,
?array $responseMap = null,
) {
if (null !== $filters) {
foreach ($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 (null !== $requirements) {
foreach ($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 (null !== $views) {
if (!is_array($views)) {
$views = [$views];
}
foreach ($views as $view) {
$this->addView($view);
}
}
if (null !== $parameters) {
foreach ($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 (null !== $headers) {
foreach ($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 (null !== $statusCodes) {
foreach ($statusCodes as $statusCode => $statusDescription) {
$this->addStatusCode($statusCode, $statusDescription);
}
}
if (null !== $tags) {
if (is_array($tags)) {
foreach ($tags as $tag => $colorCode) {
if (is_numeric($tag)) {
$this->addTag($colorCode);
} else {
$this->addTag($tag, $colorCode);
}
}
} else {
$this->tags[] = $tags;
}
}
if (null !== $responseMap) {
$this->responseMap = $responseMap;
if (isset($this->responseMap[200])) {
$this->output = $this->responseMap[200];
}
}
}
public function addFilter(string $name, array $filter): void
{
$this->filters[$name] = $filter;
}
public function addStatusCode(int|string $statusCode, string|array $description): void
{
$this->statusCodes[$statusCode] = !is_array($description) ? [$description] : $description;
}
public function addTag(int|string $tag, string $colorCode = '#d9534f'): void
{
$this->tags[$tag] = $colorCode;
}
public function addRequirement(string $name, array $requirement): void
{
$this->requirements[$name] = $requirement;
}
public function setRequirements(array $requirements): void
{
$this->requirements = array_merge($this->requirements, $requirements);
}
public function getInput(): string|array|null
{
return $this->input;
}
public function getInputs(): ?array
{
return $this->inputs;
}
public function getOutput(): array|string|null
{
return $this->output;
}
/**
* @return string[]|string|null
*/
public function getDescription(): array|string|null
{
return $this->description;
}
/**
* @param string[]|string|null $description
*/
public function setDescription(array|string|null $description): void
{
$this->description = $description;
}
public function setLink(?string $link): void
{
$this->link = $link;
}
public function getSection(): ?string
{
return $this->section;
}
public function addView(string $view): void
{
$this->views[] = $view;
}
/**
* @return string[]
*/
public function getViews(): array
{
return $this->views;
}
public function setDocumentation(?string $documentation): void
{
$this->documentation = $documentation;
}
public function getDocumentation(): ?string
{
return $this->documentation;
}
public function isResource(): bool
{
return (bool) $this->resource;
}
public function getResource(): string|bool
{
return $this->resource && is_string($this->resource) ? $this->resource : false;
}
public function addParameter(string $name, array $parameter): void
{
$this->parameters[$name] = $parameter;
}
public function setParameters(array $parameters): void
{
$this->parameters = $parameters;
}
public function addHeader($name, array $header): void
{
$this->headers[$name] = $header;
}
/**
* Sets the response data as processed by the parsers - same format as parameters
*/
public function setResponse(array $response): void
{
$this->response = $response;
}
public function setRoute(Route $route): void
{
$this->route = $route;
if (method_exists($route, 'getHost')) {
$this->host = $route->getHost() ?: null;
// replace route placeholders
foreach ($route->getDefaults() as $key => $value) {
if (null !== $this->host && is_string($value)) {
$this->host = str_replace('{' . $key . '}', $value, $this->host);
}
}
} else {
$this->host = null;
}
$this->uri = $route->getPath();
$this->method = $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY';
}
public function getRoute(): Route
{
return $this->route;
}
public function getHost(): ?string
{
return $this->host;
}
public function getDeprecated(): bool
{
return $this->deprecated;
}
/**
* @return array<string, array<string, string>>
*/
public function getFilters(): array
{
return $this->filters;
}
public function getRequirements(): array
{
return $this->requirements;
}
public function getParameters(): array
{
return $this->parameters;
}
public function getHeaders(): array
{
return $this->headers;
}
public function setDeprecated(bool $deprecated): void
{
$this->deprecated = $deprecated;
}
public function getMethod(): string
{
return $this->method;
}
public function setScope(string $scope): void
{
$this->scope = $scope;
}
public function getScope(): ?string
{
return $this->scope;
}
/**
* @return array
*/
public function toArray()
{
$data = [
'method' => $this->method ?? null,
'uri' => $this->uri ?? null,
];
if ($host = $this->host) {
$data['host'] = $host;
}
if ($description = $this->description) {
$data['description'] = $description;
}
if ($link = $this->link) {
$data['link'] = $link;
}
if ($documentation = $this->documentation) {
$data['documentation'] = $documentation;
}
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 ($views = $this->views) {
$data['views'] = $views;
}
if ($response = $this->response) {
$data['response'] = $response;
}
if ($parsedResponseMap = $this->parsedResponseMap) {
$data['parsedResponseMap'] = $parsedResponseMap;
}
if ($statusCodes = $this->statusCodes) {
$data['statusCodes'] = $statusCodes;
}
if ($section = $this->section) {
$data['section'] = $section;
}
if ($tags = $this->tags) {
$data['tags'] = $tags;
}
if ($resourceDescription = $this->resourceDescription) {
$data['resourceDescription'] = $resourceDescription;
}
$data['deprecated'] = $this->deprecated;
$data['scope'] = $this->scope;
return $data;
}
public function getResourceDescription(): ?string
{
return $this->resourceDescription;
}
public function getResponseMap(): array
{
if (!isset($this->responseMap[200]) && null !== $this->output) {
$this->responseMap[200] = $this->output;
}
return $this->responseMap;
}
public function getParsedResponseMap(): array
{
return $this->parsedResponseMap;
}
public function setResponseForStatusCode(array $model, array $type, int $statusCode = 200): void
{
$this->parsedResponseMap[$statusCode] = ['type' => $type, 'model' => $model];
if (200 === $statusCode && $this->response !== $model) {
$this->response = $model;
}
}
}

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Command; namespace Nelmio\ApiDocBundle\Command;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor; use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor;
use Nelmio\ApiDocBundle\Formatter\HtmlFormatter; use Nelmio\ApiDocBundle\Formatter\HtmlFormatter;
use Nelmio\ApiDocBundle\Formatter\MarkdownFormatter; use Nelmio\ApiDocBundle\Formatter\MarkdownFormatter;

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Controller; namespace Nelmio\ApiDocBundle\Controller;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor; use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor;
use Nelmio\ApiDocBundle\Formatter\HtmlFormatter; use Nelmio\ApiDocBundle\Formatter\HtmlFormatter;
use Nelmio\ApiDocBundle\Formatter\RequestAwareSwaggerFormatter; use Nelmio\ApiDocBundle\Formatter\RequestAwareSwaggerFormatter;

View file

@ -1,37 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* AnnotationsProvider compiler pass.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class AnnotationsProviderCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$annotationsProviders = [];
foreach ($container->findTaggedServiceIds('nelmio_api_doc.extractor.annotations_provider') as $id => $attributes) {
$annotationsProviders[] = new Reference($id);
}
$container
->getDefinition('nelmio_api_doc.extractor.api_doc_extractor')
->replaceArgument(4, $annotationsProviders)
;
}
}

View file

@ -26,7 +26,7 @@ class ExtractorHandlerCompilerPass implements CompilerPassInterface
$container $container
->getDefinition('nelmio_api_doc.extractor.api_doc_extractor') ->getDefinition('nelmio_api_doc.extractor.api_doc_extractor')
->replaceArgument(3, $handlers) ->replaceArgument(2, $handlers)
; ;
} }
} }

View file

@ -32,10 +32,5 @@ class LoadExtractorParsersPass implements CompilerPassInterface
if ($container->hasDefinition('jms_serializer.serializer')) { if ($container->hasDefinition('jms_serializer.serializer')) {
$loader->load('services.jms.xml'); $loader->load('services.jms.xml');
} }
// DunglasJsonLdApiBundle may or may not be installed, if it is, load that config as well
if ($container->hasDefinition('api.resource_collection')) {
$loader->load('services.dunglas_api.xml');
}
} }
} }

View file

@ -1,189 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Extractor\AnnotationsProvider;
use Dunglas\ApiBundle\Api\Operation\OperationInterface;
use Dunglas\ApiBundle\Api\ResourceCollectionInterface;
use Dunglas\ApiBundle\Api\ResourceInterface;
use Dunglas\ApiBundle\Hydra\ApiDocumentationBuilderInterface;
use Dunglas\ApiBundle\Mapping\ClassMetadataFactoryInterface;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\AnnotationsProviderInterface;
use Nelmio\ApiDocBundle\Parser\DunglasApiParser;
use Symfony\Component\HttpFoundation\Request;
/**
* Creates ApiDoc annotations for DunglasApiBundle.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DunglasApiProvider implements AnnotationsProviderInterface
{
/**
* @var ResourceCollectionInterface
*/
private $resourceCollection;
/**
* @var ApiDocumentationBuilderInterface
*/
private $apiDocumentationBuilder;
/**
* @var ClassMetadataFactoryInterface
*/
private $classMetadataFactory;
public function __construct(
ResourceCollectionInterface $resourceCollection,
ApiDocumentationBuilderInterface $apiDocumentationBuilder,
ClassMetadataFactoryInterface $classMetadataFactory,
) {
$this->resourceCollection = $resourceCollection;
$this->apiDocumentationBuilder = $apiDocumentationBuilder;
$this->classMetadataFactory = $classMetadataFactory;
}
public function getAnnotations()
{
$annotations = [];
$hydraDoc = $this->apiDocumentationBuilder->getApiDocumentation();
$entrypointHydraDoc = $this->getResourceHydraDoc($hydraDoc, '#Entrypoint');
/*
* @var ResourceInterface
*/
foreach ($this->resourceCollection as $resource) {
$classMetadata = $this->classMetadataFactory->getMetadataFor($resource->getEntityClass());
$prefixedShortName = ($iri = $classMetadata->getIri()) ? $iri : '#' . $resource->getShortName();
$resourceHydraDoc = $this->getResourceHydraDoc($hydraDoc, $prefixedShortName);
if ($hydraDoc) {
foreach ($resource->getCollectionOperations() as $operation) {
$annotations[] = $this->getApiDoc(true, $resource, $operation, $resourceHydraDoc, $entrypointHydraDoc);
}
foreach ($resource->getItemOperations() as $operation) {
$annotations[] = $this->getApiDoc(false, $resource, $operation, $resourceHydraDoc);
}
}
}
return $annotations;
}
/**
* Builds ApiDoc annotation from DunglasApiBundle data.
*
* @param bool $collection
*
* @return ApiDoc
*/
private function getApiDoc(
$collection,
ResourceInterface $resource,
OperationInterface $operation,
array $resourceHydraDoc,
array $entrypointHydraDoc = [],
) {
$method = $operation->getRoute()->getMethods()[0];
if ($collection) {
$operationHydraDoc = $this->getCollectionOperationHydraDoc($resource->getShortName(), $method, $entrypointHydraDoc);
} else {
$operationHydraDoc = $this->getOperationHydraDoc($operation->getRoute()->getMethods()[0], $resourceHydraDoc);
}
$route = $operation->getRoute();
$data = [
'resource' => $route->getPath(),
'description' => $operationHydraDoc['hydra:title'],
'resourceDescription' => $resourceHydraDoc['hydra:title'],
'section' => $resourceHydraDoc['hydra:title'],
];
$entityClass = $resource->getEntityClass();
if (isset($operationHydraDoc['expects']) && 'owl:Nothing' !== $operationHydraDoc['expects']) {
$data['input'] = sprintf('%s:%s', DunglasApiParser::IN_PREFIX, $entityClass);
}
if (isset($operationHydraDoc['returns']) && 'owl:Nothing' !== $operationHydraDoc['returns']) {
$data['output'] = sprintf('%s:%s', DunglasApiParser::OUT_PREFIX, $entityClass);
}
if (Request::METHOD_GET === $method && $collection) {
$data['filters'] = [];
foreach ($resource->getFilters() as $filter) {
foreach ($filter->getDescription($resource) as $name => $definition) {
$data['filters'][] = ['name' => $name] + $definition;
}
}
}
$apiDoc = new ApiDoc($data);
$apiDoc->setRoute($route);
return $apiDoc;
}
/**
* Gets Hydra documentation for the given resource.
*
* @param string $prefixedShortName
*
* @return array|null
*/
private function getResourceHydraDoc(array $hydraApiDoc, $prefixedShortName)
{
foreach ($hydraApiDoc['hydra:supportedClass'] as $supportedClass) {
if ($supportedClass['@id'] === $prefixedShortName) {
return $supportedClass;
}
}
}
/**
* Gets the Hydra documentation of a given operation.
*
* @param string $method
*
* @return array|null
*/
private function getOperationHydraDoc($method, array $hydraDoc)
{
foreach ($hydraDoc['hydra:supportedOperation'] as $supportedOperation) {
if ($supportedOperation['hydra:method'] === $method) {
return $supportedOperation;
}
}
}
/**
* Gets the Hydra documentation for the collection operation.
*
* @param string $shortName
* @param string $method
*
* @return array|null
*/
private function getCollectionOperationHydraDoc($shortName, $method, array $hydraEntrypointDoc)
{
$propertyName = '#Entrypoint/' . lcfirst($shortName);
foreach ($hydraEntrypointDoc['hydra:supportedProperty'] as $supportedProperty) {
$hydraProperty = $supportedProperty['hydra:property'];
if ($hydraProperty['@id'] === $propertyName) {
return $this->getOperationHydraDoc($method, $hydraProperty);
}
}
}
}

View file

@ -1,27 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Extractor;
/**
* Interface for annotations providers.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
interface AnnotationsProviderInterface
{
/**
* Returns an array ApiDoc annotations.
*
* @return \Nelmio\ApiDocBundle\Annotation\ApiDoc[]
*/
public function getAnnotations();
}

View file

@ -11,8 +11,7 @@
namespace Nelmio\ApiDocBundle\Extractor; namespace Nelmio\ApiDocBundle\Extractor;
use Doctrine\Common\Annotations\Reader; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\DataTypes; use Nelmio\ApiDocBundle\DataTypes;
use Nelmio\ApiDocBundle\Parser\ParserInterface; use Nelmio\ApiDocBundle\Parser\ParserInterface;
use Nelmio\ApiDocBundle\Parser\PostParserInterface; use Nelmio\ApiDocBundle\Parser\PostParserInterface;
@ -22,24 +21,19 @@ use Symfony\Component\Routing\RouterInterface;
class ApiDocExtractor class ApiDocExtractor
{ {
public const ANNOTATION_CLASS = ApiDoc::class;
/** /**
* @var ParserInterface[] * @var ParserInterface[]
*/ */
protected array $parsers = []; protected array $parsers = [];
/** /**
* @param HandlerInterface[] $handlers * @param HandlerInterface[] $handlers
* @param AnnotationsProviderInterface[] $annotationsProviders * @param string[] $excludeSections
* @param string[] $excludeSections
*/ */
public function __construct( public function __construct(
protected RouterInterface $router, protected RouterInterface $router,
protected Reader $reader,
protected DocCommentExtractor $commentExtractor, protected DocCommentExtractor $commentExtractor,
protected array $handlers, protected array $handlers,
protected array $annotationsProviders,
protected array $excludeSections, protected array $excludeSections,
) { ) {
} }
@ -51,17 +45,15 @@ class ApiDocExtractor
* *
* @return Route[] An array of routes * @return Route[] An array of routes
*/ */
public function getRoutes() public function getRoutes(): array
{ {
return $this->router->getRouteCollection()->all(); return $this->router->getRouteCollection()->all();
} }
/** /*
* Extracts annotations from all known routes * Extracts annotations from all known routes
*
* @return array
*/ */
public function all($view = ApiDoc::DEFAULT_VIEW) public function all($view = ApiDoc::DEFAULT_VIEW): array
{ {
return $this->extractAnnotations($this->getRoutes(), $view); return $this->extractAnnotations($this->getRoutes(), $view);
} }
@ -71,10 +63,8 @@ class ApiDocExtractor
* *
* @param string $apiVersion API version * @param string $apiVersion API version
* @param string $view * @param string $view
*
* @return array
*/ */
public function allForVersion($apiVersion, $view = ApiDoc::DEFAULT_VIEW) public function allForVersion($apiVersion, $view = ApiDoc::DEFAULT_VIEW): array
{ {
$data = $this->all($view); $data = $this->all($view);
foreach ($data as $k => $a) { foreach ($data as $k => $a) {
@ -96,10 +86,8 @@ class ApiDocExtractor
* - resource * - resource
* *
* @param array $routes array of Route-objects for which the annotations should be extracted * @param array $routes array of Route-objects for which the annotations should be extracted
*
* @return array
*/ */
public function extractAnnotations(array $routes, $view = ApiDoc::DEFAULT_VIEW) public function extractAnnotations(array $routes, $view = ApiDoc::DEFAULT_VIEW): array
{ {
$array = []; $array = [];
$resources = []; $resources = [];
@ -110,7 +98,7 @@ class ApiDocExtractor
} }
if ($method = $this->getReflectionMethod($route->getDefault('_controller'))) { if ($method = $this->getReflectionMethod($route->getDefault('_controller'))) {
$annotation = $this->reader->getMethodAnnotation($method, static::ANNOTATION_CLASS); $annotation = $this->getMethodApiDoc($method);
if ( if (
$annotation && !in_array($annotation->getSection(), $this->excludeSections) $annotation && !in_array($annotation->getSection(), $this->excludeSections)
&& (in_array($view, $annotation->getViews()) || (0 === count($annotation->getViews()) && ApiDoc::DEFAULT_VIEW === $view)) && (in_array($view, $annotation->getViews()) || (0 === count($annotation->getViews()) && ApiDoc::DEFAULT_VIEW === $view))
@ -129,13 +117,6 @@ class ApiDocExtractor
} }
} }
foreach ($this->annotationsProviders as $annotationProvider) {
foreach ($annotationProvider->getAnnotations() as $annotation) {
$route = $annotation->getRoute();
$array[] = ['annotation' => $this->extractData($annotation, $route, $this->getReflectionMethod($route->getDefault('_controller')))];
}
}
rsort($resources); rsort($resources);
foreach ($array as $index => $element) { foreach ($array as $index => $element) {
$hasResource = false; $hasResource = false;
@ -223,7 +204,7 @@ class ApiDocExtractor
public function get($controller, $route) public function get($controller, $route)
{ {
if ($method = $this->getReflectionMethod($controller)) { if ($method = $this->getReflectionMethod($controller)) {
if ($annotation = $this->reader->getMethodAnnotation($method, static::ANNOTATION_CLASS)) { if ($annotation = $this->getMethodApiDoc($method)) {
if ($route = $this->router->getRouteCollection()->get($route)) { if ($route = $this->router->getRouteCollection()->get($route)) {
return $this->extractData($annotation, $route, $method); return $this->extractData($annotation, $route, $method);
} }
@ -233,6 +214,16 @@ class ApiDocExtractor
return null; return null;
} }
protected function getMethodApiDoc(\ReflectionMethod $method): ?ApiDoc
{
$attributes = $method->getAttributes(ApiDoc::class, \ReflectionAttribute::IS_INSTANCEOF);
if (!$attributes) {
return null;
}
return $attributes[0]->newInstance();
}
/** /**
* Registers a class parser to use for parsing input class metadata * Registers a class parser to use for parsing input class metadata
*/ */
@ -453,13 +444,13 @@ class ApiDocExtractor
} elseif (null !== $value) { } elseif (null !== $value) {
if (in_array($name, ['required', 'readonly'])) { if (in_array($name, ['required', 'readonly'])) {
$v1[$name] = $v1[$name] || $value; $v1[$name] = $v1[$name] || $value;
} elseif (in_array($name, ['requirement'])) { } elseif ('requirement' === $name) {
if (isset($v1[$name])) { if (isset($v1[$name])) {
$v1[$name] .= ', ' . $value; $v1[$name] .= ', ' . $value;
} else { } else {
$v1[$name] = $value; $v1[$name] = $value;
} }
} elseif ('default' == $name) { } elseif ('default' === $name) {
if (isset($v1[$name])) { if (isset($v1[$name])) {
$v1[$name] = $value ?? $v1[$name]; $v1[$name] = $value ?? $v1[$name];
} else { } else {
@ -481,14 +472,11 @@ class ApiDocExtractor
/** /**
* Parses annotations for a given method, and adds new information to the given ApiDoc * Parses annotations for a given method, and adds new information to the given ApiDoc
* annotation. Useful to extract information from the FOSRestBundle annotations. * annotation. Useful to extract information from the FOSRestBundle annotations.
*
* @param ReflectionMethod $method
*/ */
protected function parseAnnotations(ApiDoc $annotation, Route $route, \ReflectionMethod $method): void protected function parseAnnotations(ApiDoc $annotation, Route $route, \ReflectionMethod $method): void
{ {
$annots = $this->reader->getMethodAnnotations($method);
foreach ($this->handlers as $handler) { foreach ($this->handlers as $handler) {
$handler->handle($annotation, $annots, $route, $method); $handler->handle($annotation, $route, $method);
} }
} }

View file

@ -11,8 +11,7 @@
namespace Nelmio\ApiDocBundle\Extractor; namespace Nelmio\ApiDocBundle\Extractor;
use Doctrine\Common\Annotations\Reader; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Util\DocCommentExtractor; use Nelmio\ApiDocBundle\Util\DocCommentExtractor;
use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Resource\FileResource;
@ -26,22 +25,19 @@ use Symfony\Component\Routing\RouterInterface;
class CachingApiDocExtractor extends ApiDocExtractor class CachingApiDocExtractor extends ApiDocExtractor
{ {
/** /**
* @param HandlerInterface[] $handlers * @param HandlerInterface[] $handlers
* @param AnnotationsProviderInterface[] $annotationsProviders * @param string[] $excludeSections
* @param string[] $excludeSections * @param bool|false $debug
* @param bool|false $debug
*/ */
public function __construct( public function __construct(
RouterInterface $router, RouterInterface $router,
Reader $reader,
DocCommentExtractor $commentExtractor, DocCommentExtractor $commentExtractor,
array $handlers, array $handlers,
array $annotationsProviders,
array $excludeSections, array $excludeSections,
private string $cacheFile, private string $cacheFile,
private bool $debug = false, private bool $debug = false,
) { ) {
parent::__construct($router, $reader, $commentExtractor, $handlers, $annotationsProviders, $excludeSections); parent::__construct($router, $commentExtractor, $handlers, $excludeSections);
} }
/** /**
@ -49,15 +45,17 @@ class CachingApiDocExtractor extends ApiDocExtractor
* *
* @return array|mixed * @return array|mixed
*/ */
public function all($view = ApiDoc::DEFAULT_VIEW) public function all($view = ApiDoc::DEFAULT_VIEW): array
{ {
$cache = $this->getViewCache($view); $cache = $this->getViewCache($view);
if (!$cache->isFresh()) { if (!$cache->isFresh()) {
$resources = []; $resources = [];
foreach ($this->getRoutes() as $route) { foreach ($this->getRoutes() as $route) {
if (null !== ($method = $this->getReflectionMethod($route->getDefault('_controller'))) if (
&& null !== ($annotation = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS))) { null !== ($method = $this->getReflectionMethod($route->getDefault('_controller')))
&& null !== $this->getMethodApiDoc($method)
) {
$file = $method->getDeclaringClass()->getFileName(); $file = $method->getDeclaringClass()->getFileName();
$resources[] = new FileResource($file); $resources[] = new FileResource($file);
} }

View file

@ -1,125 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Extractor\Handler;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\RequestParam;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\DataTypes;
use Nelmio\ApiDocBundle\Extractor\HandlerInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Regex;
class FosRestHandler implements HandlerInterface
{
public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method): void
{
foreach ($annotations as $annot) {
if ($annot instanceof RequestParam) {
$requirements = $this->handleRequirements($annot->requirements);
$data = [
'required' => $annot->strict && false === $annot->nullable && null === $annot->default,
'dataType' => $requirements . ((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'actualType' => $this->inferType($requirements),
'subType' => null,
'description' => $annot->description,
'readonly' => false,
];
if (false === $annot->strict) {
$data['default'] = $annot->default;
}
$annotation->addParameter($annot->name, $data);
} elseif ($annot instanceof QueryParam) {
if ($annot->strict && false === $annot->nullable && null === $annot->default) {
$annotation->addRequirement($annot->name, [
'requirement' => $this->handleRequirements($annot->requirements) . ((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'dataType' => '',
'description' => $annot->description,
]);
} elseif (null !== $annot->default) {
$annotation->addFilter($annot->name, [
'requirement' => $this->handleRequirements($annot->requirements) . ((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'description' => $annot->description,
'default' => $annot->default,
]);
} elseif (null !== $annot->requirements) {
$annotation->addFilter($annot->name, [
'requirement' => $this->handleRequirements($annot->requirements) . ((property_exists($annot, 'map') ? $annot->map : $annot->array) ? '[]' : ''),
'description' => $annot->description,
]);
} else {
$annotation->addFilter($annot->name, [
'description' => $annot->description,
]);
}
}
}
}
/**
* Handle FOSRestBundle requirements in order to return a string.
*
* @return string
*/
private function handleRequirements($requirements)
{
if (is_object($requirements) && $requirements instanceof Constraint) {
if ($requirements instanceof Regex) {
return $requirements->getHtmlPattern();
}
$class = $requirements::class;
return substr($class, strrpos($class, '\\') + 1);
}
if (is_array($requirements) && isset($requirements['rule'])) {
return (string) $requirements['rule'];
}
if (is_array($requirements) && array_key_exists(0, $requirements)) {
$output = [];
foreach ($requirements as $req) {
if (is_object($req) && $req instanceof Constraint) {
if ($req instanceof Regex) {
$output[] = $req->getHtmlPattern();
} else {
$class = $req::class;
$output[] = substr($class, strrpos($class, '\\') + 1);
}
}
if (is_array($req)) {
if (array_key_exists('_format', $req)) {
$output[] = 'Format: ' . $req['_format'];
} elseif (isset($req['rule'])) {
$output[] = $req['rule'];
}
}
}
return implode(', ', $output);
}
return (string) $requirements;
}
public function inferType($requirement)
{
if (DataTypes::isPrimitive($requirement)) {
return $requirement;
}
return DataTypes::STRING;
}
}

View file

@ -1,33 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Extractor\Handler;
use JMS\SecurityExtraBundle\Annotation\PreAuthorize;
use JMS\SecurityExtraBundle\Annotation\Secure;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\HandlerInterface;
use Symfony\Component\Routing\Route;
class JmsSecurityExtraHandler implements HandlerInterface
{
public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method): void
{
foreach ($annotations as $annot) {
if ($annot instanceof PreAuthorize) {
$annotation->setAuthentication(true);
} elseif ($annot instanceof Secure) {
$annotation->setAuthentication(true);
$annotation->setAuthenticationRoles(is_array($annot->roles) ? $annot->roles : explode(',', $annot->roles));
}
}
}
}

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Extractor\Handler; namespace Nelmio\ApiDocBundle\Extractor\Handler;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\HandlerInterface; use Nelmio\ApiDocBundle\Extractor\HandlerInterface;
use Nelmio\ApiDocBundle\Util\DocCommentExtractor; use Nelmio\ApiDocBundle\Util\DocCommentExtractor;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
@ -28,7 +28,7 @@ class PhpDocHandler implements HandlerInterface
$this->commentExtractor = $commentExtractor; $this->commentExtractor = $commentExtractor;
} }
public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method): void public function handle(ApiDoc $annotation, Route $route, \ReflectionMethod $method): void
{ {
// description // description
if (null === $annotation->getDescription()) { if (null === $annotation->getDescription()) {
@ -54,15 +54,6 @@ class PhpDocHandler implements HandlerInterface
'description' => '', 'description' => '',
]; ];
} }
if ('_scheme' === $name) {
$https = ('https' == $value);
$annotation->setHttps($https);
}
}
if (method_exists($route, 'getSchemes')) {
$annotation->setHttps(in_array('https', $route->getSchemes()));
} }
$paramDocs = []; $paramDocs = [];
@ -83,7 +74,7 @@ class PhpDocHandler implements HandlerInterface
$found = false; $found = false;
foreach ($paramDocs as $paramDoc) { foreach ($paramDocs as $paramDoc) {
if (preg_match(sprintf($regexp, preg_quote($var)), $paramDoc, $matches)) { if (preg_match(sprintf($regexp, preg_quote($var)), $paramDoc, $matches)) {
$annotationRequirements = $annotation->getrequirements(); $annotationRequirements = $annotation->getRequirements();
if (!isset($annotationRequirements[$var]['dataType'])) { if (!isset($annotationRequirements[$var]['dataType'])) {
$requirements[$var]['dataType'] = $matches[1] ?? ''; $requirements[$var]['dataType'] = $matches[1] ?? '';

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Extractor; namespace Nelmio\ApiDocBundle\Extractor;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
interface HandlerInterface interface HandlerInterface
@ -19,5 +19,5 @@ interface HandlerInterface
/** /**
* Parse route parameters in order to populate ApiDoc. * Parse route parameters in order to populate ApiDoc.
*/ */
public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method); public function handle(ApiDoc $annotation, Route $route, \ReflectionMethod $method);
} }

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Formatter; namespace Nelmio\ApiDocBundle\Formatter;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\DataTypes; use Nelmio\ApiDocBundle\DataTypes;
abstract class AbstractFormatter implements FormatterInterface abstract class AbstractFormatter implements FormatterInterface

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Formatter; namespace Nelmio\ApiDocBundle\Formatter;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
interface FormatterInterface interface FormatterInterface
{ {

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Formatter; namespace Nelmio\ApiDocBundle\Formatter;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/** /**

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Formatter; namespace Nelmio\ApiDocBundle\Formatter;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
class SimpleFormatter extends AbstractFormatter class SimpleFormatter extends AbstractFormatter
{ {

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Formatter; namespace Nelmio\ApiDocBundle\Formatter;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\DataTypes; use Nelmio\ApiDocBundle\DataTypes;
use Nelmio\ApiDocBundle\Swagger\ModelRegistry; use Nelmio\ApiDocBundle\Swagger\ModelRegistry;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;

View file

@ -2,7 +2,6 @@
namespace Nelmio\ApiDocBundle; namespace Nelmio\ApiDocBundle;
use Nelmio\ApiDocBundle\DependencyInjection\AnnotationsProviderCompilerPass;
use Nelmio\ApiDocBundle\DependencyInjection\ExtractorHandlerCompilerPass; use Nelmio\ApiDocBundle\DependencyInjection\ExtractorHandlerCompilerPass;
use Nelmio\ApiDocBundle\DependencyInjection\FormInfoParserCompilerPass; use Nelmio\ApiDocBundle\DependencyInjection\FormInfoParserCompilerPass;
use Nelmio\ApiDocBundle\DependencyInjection\LoadExtractorParsersPass; use Nelmio\ApiDocBundle\DependencyInjection\LoadExtractorParsersPass;
@ -20,7 +19,6 @@ class NelmioApiDocBundle extends Bundle
$container->addCompilerPass(new LoadExtractorParsersPass()); $container->addCompilerPass(new LoadExtractorParsersPass());
$container->addCompilerPass(new RegisterExtractorParsersPass()); $container->addCompilerPass(new RegisterExtractorParsersPass());
$container->addCompilerPass(new ExtractorHandlerCompilerPass()); $container->addCompilerPass(new ExtractorHandlerCompilerPass());
$container->addCompilerPass(new AnnotationsProviderCompilerPass());
$container->addCompilerPass(new SwaggerConfigCompilerPass()); $container->addCompilerPass(new SwaggerConfigCompilerPass());
$container->addCompilerPass(new FormInfoParserCompilerPass()); $container->addCompilerPass(new FormInfoParserCompilerPass());
} }

View file

@ -1,187 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Parser;
use Dunglas\ApiBundle\Api\ResourceCollectionInterface;
use Dunglas\ApiBundle\Api\ResourceInterface;
use Dunglas\ApiBundle\Mapping\AttributeMetadataInterface;
use Dunglas\ApiBundle\Mapping\ClassMetadataFactoryInterface;
use Nelmio\ApiDocBundle\DataTypes;
use PropertyInfo\Type;
/**
* Use DunglasApiBundle to extract input and output information.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DunglasApiParser implements ParserInterface
{
public const IN_PREFIX = 'dunglas_api_in';
public const OUT_PREFIX = 'dunglas_api_out';
public const IRI = 'IRI';
private static $typeMap = [
'int' => DataTypes::INTEGER,
'bool' => DataTypes::BOOLEAN,
'string' => DataTypes::STRING,
'float' => DataTypes::FLOAT,
];
/**
* @var ResourceCollectionInterface
*/
private $resourceCollection;
/**
* @var ClassMetadataFactory
*/
private $classMetadataFactory;
public function __construct(
ResourceCollectionInterface $resourceCollection,
ClassMetadataFactoryInterface $classMetadataFactory,
) {
$this->resourceCollection = $resourceCollection;
$this->classMetadataFactory = $classMetadataFactory;
}
public function supports(array $item)
{
$data = explode(':', $item['class'], 2);
if (isset($data[1])) {
return null !== $this->resourceCollection->getResourceForEntity($data[1]);
}
return false;
}
public function parse(array $item)
{
[$io, $entityClass] = explode(':', $item['class'], 2);
$resource = $this->resourceCollection->getResourceForEntity($entityClass);
return $this->parseClass($resource, $entityClass, $io);
}
/**
* Parses a class.
*
* @param string $entityClass
* @param string $io
* @param string[] $visited
*
* @return array
*/
private function parseClass(ResourceInterface $resource, $entityClass, $io, array $visited = [])
{
$visited[] = $entityClass;
$classMetadata = $this->classMetadataFactory->getMetadataFor(
$entityClass,
$resource->getNormalizationGroups(),
$resource->getDenormalizationGroups(),
$resource->getValidationGroups()
);
$data = [];
foreach ($classMetadata->getAttributes() as $attributeMetadata) {
if (
(!$attributeMetadata->isIdentifier() && $attributeMetadata->isReadable() && self::OUT_PREFIX === $io)
|| ($attributeMetadata->isWritable() && self::IN_PREFIX === $io)
) {
$data[$attributeMetadata->getName()] = $this->parseAttribute($resource, $attributeMetadata, $io, null, $visited);
}
}
return $data;
}
/**
* Parses an attribute.
*
* @param string $io
* @param string[] $visited
*
* @return array
*/
private function parseAttribute(ResourceInterface $resource, AttributeMetadataInterface $attributeMetadata, $io, ?Type $type = null, array $visited = [])
{
$data = [
'dataType' => null,
'required' => $attributeMetadata->isRequired(),
'description' => $attributeMetadata->getDescription(),
'readonly' => !$attributeMetadata->isWritable(),
];
if (null == $type) {
if (!isset($attributeMetadata->getTypes()[0])) {
// Default to string
$data['dataType'] = DataTypes::STRING;
return $data;
}
// Use the first type found as primary
$type = $attributeMetadata->getTypes()[0];
}
if ($type->isCollection()) {
$data['actualType'] = DataTypes::COLLECTION;
if ($collectionType = $type->getCollectionType()) {
$subAttribute = $this->parseAttribute($resource, $attributeMetadata, $io, $collectionType, $visited);
if (self::IRI === $subAttribute['dataType']) {
$data['dataType'] = 'array of IRIs';
$data['subType'] = DataTypes::STRING;
return $data;
}
$data['subType'] = $subAttribute['subType'];
$data['children'] = $subAttribute['children'];
}
return $data;
}
$phpType = $type->getType();
if ('object' === $phpType) {
$class = $type->getClass();
if ('DateTime' === $class) {
$data['dataType'] = DataTypes::DATETIME;
$data['format'] = sprintf('{DateTime %s}', \DateTime::ATOM);
return $data;
}
if (
(self::OUT_PREFIX === $io && $attributeMetadata->isNormalizationLink())
|| (self::IN_PREFIX === $io && $attributeMetadata->isDenormalizationLink())
) {
$data['dataType'] = self::IRI;
$data['actualType'] = DataTypes::STRING;
return $data;
}
$data['actualType'] = DataTypes::MODEL;
$data['subType'] = $class;
$data['children'] = in_array($class, $visited) ? [] : $this->parseClass($resource, $class, $io, $visited);
return $data;
}
$data['dataType'] = isset(self::$typeMap[$type->getType()]) ? self::$typeMap[$type->getType()] : DataTypes::STRING;
return $data;
}
}

View file

@ -1,12 +1,6 @@
NelmioApiDocBundle NelmioApiDocBundle
================== ==================
[![Build
Status](https://secure.travis-ci.org/nelmio/NelmioApiDocBundle.png?branch=master)](http://travis-ci.org/nelmio/NelmioApiDocBundle)
[![Total Downloads](https://poser.pugx.org/nelmio/api-doc-bundle/downloads)](https://packagist.org/packages/nelmio/api-doc-bundle)
[![Latest Stable
Version](https://poser.pugx.org/nelmio/api-doc-bundle/v/stable)](https://packagist.org/packages/nelmio/api-doc-bundle)
The **NelmioApiDocBundle** bundle allows you to generate a decent documentation The **NelmioApiDocBundle** bundle allows you to generate a decent documentation
for your APIs. for your APIs.

View file

@ -1,23 +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.annotations_provider.dunglas_api_annotation_provider" class="Nelmio\ApiDocBundle\Extractor\AnnotationsProvider\DunglasApiProvider">
<argument type="service" id="api.resource_collection" />
<argument type="service" id="api.hydra.documentation_builder" />
<argument type="service" id="api.mapping.class_metadata_factory" />
<tag name="nelmio_api_doc.extractor.annotations_provider" />
</service>
<service id="nelmio_api_doc.parser.dunglas_api_parser" class="Nelmio\ApiDocBundle\Parser\DunglasApiParser">
<argument type="service" id="api.resource_collection" />
<argument type="service" id="api.mapping.class_metadata_factory" />
<tag name="nelmio_api_doc.extractor.parser" />
</service>
</services>
</container>

View file

@ -9,8 +9,6 @@
<parameter key="nelmio_api_doc.twig.extension.extra_markdown.class">Nelmio\ApiDocBundle\Twig\Extension\MarkdownExtension</parameter> <parameter key="nelmio_api_doc.twig.extension.extra_markdown.class">Nelmio\ApiDocBundle\Twig\Extension\MarkdownExtension</parameter>
<parameter key="nelmio_api_doc.doc_comment_extractor.class">Nelmio\ApiDocBundle\Util\DocCommentExtractor</parameter> <parameter key="nelmio_api_doc.doc_comment_extractor.class">Nelmio\ApiDocBundle\Util\DocCommentExtractor</parameter>
<parameter key="nelmio_api_doc.extractor.handler.fos_rest.class">Nelmio\ApiDocBundle\Extractor\Handler\FosRestHandler</parameter>
<parameter key="nelmio_api_doc.extractor.handler.jms_security.class">Nelmio\ApiDocBundle\Extractor\Handler\JmsSecurityExtraHandler</parameter>
<parameter key="nelmio_api_doc.extractor.handler.phpdoc.class">Nelmio\ApiDocBundle\Extractor\Handler\PhpDocHandler</parameter> <parameter key="nelmio_api_doc.extractor.handler.phpdoc.class">Nelmio\ApiDocBundle\Extractor\Handler\PhpDocHandler</parameter>
<parameter key="nelmio_api_doc.parser.collection_parser.class">Nelmio\ApiDocBundle\Parser\CollectionParser</parameter> <parameter key="nelmio_api_doc.parser.collection_parser.class">Nelmio\ApiDocBundle\Parser\CollectionParser</parameter>
@ -27,10 +25,8 @@
<service id="nelmio_api_doc.extractor.api_doc_extractor" class="%nelmio_api_doc.extractor.api_doc_extractor.class%" public="true"> <service id="nelmio_api_doc.extractor.api_doc_extractor" class="%nelmio_api_doc.extractor.api_doc_extractor.class%" public="true">
<argument type="service" id="router" /> <argument type="service" id="router" />
<argument type="service" id="annotation_reader" />
<argument type="service" id="nelmio_api_doc.doc_comment_extractor" /> <argument type="service" id="nelmio_api_doc.doc_comment_extractor" />
<argument type="collection" /> <argument type="collection" />
<argument type="collection" />
<argument>%nelmio_api_doc.exclude_sections%</argument> <argument>%nelmio_api_doc.exclude_sections%</argument>
</service> </service>
@ -44,14 +40,6 @@
<!-- Extractor Annotation Handlers --> <!-- Extractor Annotation Handlers -->
<service id="nelmio_api_doc.extractor.handler.fos_rest" class="%nelmio_api_doc.extractor.handler.fos_rest.class%" public="false">
<tag name="nelmio_api_doc.extractor.handler"/>
</service>
<service id="nelmio_api_doc.extractor.handler.jms_security" class="%nelmio_api_doc.extractor.handler.jms_security.class%" public="false">
<tag name="nelmio_api_doc.extractor.handler"/>
</service>
<service id="nelmio_api_doc.extractor.handler.phpdoc" class="%nelmio_api_doc.extractor.handler.phpdoc.class%" public="false"> <service id="nelmio_api_doc.extractor.handler.phpdoc" class="%nelmio_api_doc.extractor.handler.phpdoc.class%" public="false">
<argument type="service" id="nelmio_api_doc.doc_comment_extractor" /> <argument type="service" id="nelmio_api_doc.doc_comment_extractor" />
<tag name="nelmio_api_doc.extractor.handler"/> <tag name="nelmio_api_doc.extractor.handler"/>

View file

@ -1,23 +0,0 @@
DunglasApiBundle Support
========================
This bundle recognizes and documents resources exposed with
`DunglasApiBundle`_.
Install NelmioApiDocBundle and the documentation will be automatically
available. To enable the sandbox, use the following configuration:
.. code-block:: yaml
# app/config/config.yml
nelmio_api_doc:
sandbox:
accept_type: "application/json"
body_format:
formats: [ "json" ]
default_format: "json"
request_format:
formats:
json: "application/json"
.. _`DunglasApiBundle`: https://github.com/dunglas/DunglasApiBundle

View file

@ -94,7 +94,6 @@ setup your API documentation:
multiple-api-doc multiple-api-doc
other-bundle-annotations other-bundle-annotations
swagger-support swagger-support
dunglasapibundle
sandbox sandbox
commands commands
configuration-in-depth configuration-in-depth

View file

@ -1,14 +1,6 @@
Other Bundle Annotations Other Bundle Annotations
======================== ========================
This bundle will get information from the following other annotations:
* ``@FOS\RestBundle\Controller\Annotations\RequestParam`` - use as ``parameters``
* ``@FOS\RestBundle\Controller\Annotations\QueryParam`` - use as ``requirements``
(when strict parameter is true), ``filters`` (when strict is false)
* ``@JMS\SecurityExtraBundle\Annotation\Secure`` - set ``authentication`` to true,
``authenticationRoles`` to the given roles
PHPDoc PHPDoc
------ ------

View file

@ -5,7 +5,7 @@ The bundle provides an ``ApiDoc()`` annotation for your controllers::
namespace Your\Namespace; namespace Your\Namespace;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
class YourController extends Controller class YourController extends Controller
{ {
@ -65,8 +65,6 @@ The following properties are available:
* ``resource``: whether the method describes a main resource or not (default: * ``resource``: whether the method describes a main resource or not (default:
``false``); ``false``);
* ``description``: a description of the API method; * ``description``: a description of the API method;
* ``https``: whether the method described requires the https protocol (default:
``false``);
* ``deprecated``: allow to set method as deprecated (default: ``false``); * ``deprecated``: allow to set method as deprecated (default: ``false``);
* ``tags``: allow to tag a method (e.g. ``beta`` or ``in-development``). Either * ``tags``: allow to tag a method (e.g. ``beta`` or ``in-development``). Either
a single tag or an array of tags. Each tag can have an optional hex colorcode a single tag or an array of tags. Each tag can have an optional hex colorcode

View file

@ -11,13 +11,6 @@
</span> </span>
{% endif %} {% endif %}
{% if data.https %}
<span class="icon lock" title="HTTPS"></span>
{% endif %}
{% if data.authentication %}
<span class="icon keys" title="Needs {{ data.authenticationRoles|length > 0 ? data.authenticationRoles|join(', ') : 'authentication' }}"></span>
{% endif %}
<span class="path"> <span class="path">
{% if data.host is defined -%} {% if data.host is defined -%}
{{ data.https ? 'https://' : 'http://' -}} {{ data.https ? 'https://' : 'http://' -}}
@ -234,9 +227,9 @@
{% if enableSandbox %} {% if enableSandbox %}
<div class="pane sandbox"> <div class="pane sandbox">
{% if app.request is not null and data.https and app.request.secure != data.https %} {% if app.request is not null and data.https and app.request.secure != data.https %}
Please reload the documentation using the scheme {% if data.https %}HTTPS{% else %}HTTP{% endif %} if you want to use the sandbox. Please reload the documentation using the scheme HTTP if you want to use the sandbox.
{% else %} {% else %}
<form method="" action="{% if data.host is defined %}{{ data.https ? 'https://' : 'http://' }}{{ data.host }}{% endif %}{{ data.uri }}"> <form method="" action="{% if data.host is defined %}http://{{ data.host }}{% endif %}{{ data.uri }}">
<fieldset class="parameters"> <fieldset class="parameters">
<legend>Input</legend> <legend>Input</legend>
{% if data.requirements is defined %} {% if data.requirements is defined %}

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Annotation; namespace Nelmio\ApiDocBundle\Tests\Annotation;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Tests\TestCase; use Nelmio\ApiDocBundle\Tests\TestCase;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
@ -19,9 +19,7 @@ class ApiDocTest extends TestCase
{ {
public function testConstructWithoutData(): void public function testConstructWithoutData(): void
{ {
$data = []; $annot = new ApiDoc();
$annot = new ApiDoc($data);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -33,19 +31,12 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['requirements'])); $this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters'])); $this->assertFalse(isset($array['parameters']));
$this->assertNull($annot->getInput()); $this->assertNull($annot->getInput());
$this->assertFalse($array['authentication']);
$this->assertFalse(isset($array['headers'])); $this->assertFalse(isset($array['headers']));
$this->assertTrue(is_array($array['authenticationRoles']));
} }
public function testConstructWithInvalidData(): void public function testConstructWithInvalidData(): void
{ {
$data = [ $annot = new ApiDoc();
'unknown' => 'foo',
'array' => ['bar' => 'bar'],
];
$annot = new ApiDoc($data);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -64,7 +55,7 @@ class ApiDocTest extends TestCase
'description' => 'Heya', 'description' => 'Heya',
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(description: $data['description']);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -84,7 +75,10 @@ class ApiDocTest extends TestCase
'input' => 'My\Form\Type', 'input' => 'My\Form\Type',
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
description: $data['description'],
input: $data['input']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -106,7 +100,12 @@ class ApiDocTest extends TestCase
'input' => 'My\Form\Type', 'input' => 'My\Form\Type',
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
resource: $data['resource'],
description: $data['description'],
deprecated: $data['deprecated'],
input: $data['input']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -128,7 +127,12 @@ class ApiDocTest extends TestCase
'input' => 'My\Form\Type', 'input' => 'My\Form\Type',
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
resource: $data['resource'],
description: $data['description'],
deprecated: $data['deprecated'],
input: $data['input']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -152,7 +156,12 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
resource: $data['resource'],
description: $data['description'],
deprecated: $data['deprecated'],
filters: $data['filters']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -178,7 +187,10 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
description: $data['description'],
filters: $data['filters']
);
} }
public function testConstructWithStatusCodes(): void public function testConstructWithStatusCodes(): void
@ -195,7 +207,10 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
description: $data['description'],
statusCodes: $data['statusCodes']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -205,30 +220,6 @@ class ApiDocTest extends TestCase
} }
} }
public function testConstructWithAuthentication(): void
{
$data = [
'authentication' => true,
];
$annot = new ApiDoc($data);
$array = $annot->toArray();
$this->assertTrue($array['authentication']);
}
public function testConstructWithCache(): void
{
$data = [
'cache' => '60',
];
$annot = new ApiDoc($data);
$array = $annot->toArray();
$this->assertEquals($data['cache'], $array['cache']);
}
public function testConstructWithRequirements(): void public function testConstructWithRequirements(): void
{ {
$data = [ $data = [
@ -242,7 +233,9 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
requirements: $data['requirements']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -262,7 +255,9 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
parameters: $data['parameters']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -281,7 +276,9 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
headers: $data['headers']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertArrayHasKey('headerName', $array['headers']); $this->assertArrayHasKey('headerName', $array['headers']);
@ -298,7 +295,9 @@ class ApiDocTest extends TestCase
'tags' => 'beta', 'tags' => 'beta',
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
tags: $data['tags']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -314,7 +313,9 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
tags: $data['tags']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -331,7 +332,9 @@ class ApiDocTest extends TestCase
], ],
]; ];
$annot = new ApiDoc($data); $annot = new ApiDoc(
tags: $data['tags']
);
$array = $annot->toArray(); $array = $annot->toArray();
$this->assertTrue(is_array($array)); $this->assertTrue(is_array($array));
@ -348,7 +351,10 @@ class ApiDocTest extends TestCase
], ],
]; ];
$apiDoc = new ApiDoc($data); $apiDoc = new ApiDoc(
output: $data['output'],
responseMap: $data['responseMap']
);
$map = $apiDoc->getResponseMap(); $map = $apiDoc->getResponseMap();
@ -367,7 +373,9 @@ class ApiDocTest extends TestCase
], ],
]; ];
$apiDoc = new ApiDoc($data); $apiDoc = new ApiDoc(
responseMap: $data['responseMap']
);
$map = $apiDoc->getResponseMap(); $map = $apiDoc->getResponseMap();
$this->assertCount(2, $map); $this->assertCount(2, $map);
@ -392,7 +400,7 @@ class ApiDocTest extends TestCase
'{foo}.awesome_host.com' '{foo}.awesome_host.com'
); );
$apiDoc = new ApiDoc([]); $apiDoc = new ApiDoc();
$apiDoc->setRoute($route); $apiDoc->setRoute($route);
$this->assertSame($route, $apiDoc->getRoute()); $this->assertSame($route, $apiDoc->getRoute());

View file

@ -1,44 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Extractor\AnnotationsProvider;
use Nelmio\ApiDocBundle\Tests\WebTestCase;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DunglasApiProviderTest extends WebTestCase
{
protected function setUp(): void
{
if (!class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
$this->markTestSkipped(
'DunglasApiBundle is not available.'
);
}
}
public function testGetAnnotations(): void
{
$container = $this->getContainer();
$provider = $container->get('nelmio_api_doc.annotations_provider.dunglas_api_annotation_provider');
$annotations = $provider->getAnnotations();
$this->assertCount(5, $annotations);
foreach ($annotations as $annotation) {
$this->assertInstanceOf('Nelmio\ApiDocBundle\Annotation\ApiDoc', $annotation);
$this->assertInstanceOf('Symfony\Component\Routing\Route', $annotation->getRoute());
$this->assertTrue('' != $annotation->getDescription());
}
}
}

View file

@ -11,27 +11,16 @@
namespace Nelmio\ApiDocBundle\Tests\Extractor; namespace Nelmio\ApiDocBundle\Tests\Extractor;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor; use Nelmio\ApiDocBundle\Extractor\ApiDocExtractor;
use Nelmio\ApiDocBundle\Tests\WebTestCase; use Nelmio\ApiDocBundle\Tests\WebTestCase;
class ApiDocExtractorTest extends WebTestCase class ApiDocExtractorTest extends WebTestCase
{ {
public const NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE = 5; private static $ROUTES_QUANTITY_DEFAULT = 26; // Routes in the default view
private static $ROUTES_QUANTITY_DEFAULT = 36; // Routes in the default view
private static $ROUTES_QUANTITY_PREMIUM = 5; // Routes in the premium view private static $ROUTES_QUANTITY_PREMIUM = 5; // Routes in the premium view
private static $ROUTES_QUANTITY_TEST = 2; // Routes in the test view private static $ROUTES_QUANTITY_TEST = 2; // Routes in the test view
public static function setUpBeforeClass(): void
{
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
self::$ROUTES_QUANTITY_DEFAULT += self::NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE;
self::$ROUTES_QUANTITY_PREMIUM += self::NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE;
self::$ROUTES_QUANTITY_TEST += self::NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE;
}
}
public function testAll(): void public function testAll(): void
{ {
$container = $this->getContainer(); $container = $this->getContainer();
@ -40,11 +29,6 @@ class ApiDocExtractorTest extends WebTestCase
$data = $extractor->all(); $data = $extractor->all();
restore_error_handler(); restore_error_handler();
$httpsKey = 21;
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
$httpsKey += self::NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE;
}
$this->assertTrue(is_array($data)); $this->assertTrue(is_array($data));
$this->assertCount(self::$ROUTES_QUANTITY_DEFAULT, $data); $this->assertCount(self::$ROUTES_QUANTITY_DEFAULT, $data);
@ -57,43 +41,10 @@ class ApiDocExtractorTest extends WebTestCase
$this->assertArrayHasKey('annotation', $d); $this->assertArrayHasKey('annotation', $d);
$this->assertArrayHasKey('resource', $d); $this->assertArrayHasKey('resource', $d);
$this->assertInstanceOf('Nelmio\ApiDocBundle\Annotation\ApiDoc', $d['annotation']); $this->assertInstanceOf('Nelmio\ApiDocBundle\Attribute\ApiDoc', $d['annotation']);
$this->assertInstanceOf('Symfony\Component\Routing\Route', $d['annotation']->getRoute()); $this->assertInstanceOf('Symfony\Component\Routing\Route', $d['annotation']->getRoute());
$this->assertNotNull($d['resource']); $this->assertNotNull($d['resource']);
} }
// $a1 = $data[7]['annotation'];
// $array1 = $a1->toArray();
// $this->assertTrue($a1->isResource());
// $this->assertEquals('index action', $a1->getDescription());
// $this->assertTrue(is_array($array1['filters']));
// $this->assertNull($a1->getInput());
//
// $a2 = $data[8]['annotation'];
// $array2 = $a2->toArray();
// $this->assertFalse($a2->isResource());
// $this->assertEquals('create test', $a2->getDescription());
// $this->assertFalse(isset($array2['filters']));
// $this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getInput());
//
// $a2 = $data[9]['annotation'];
// $array2 = $a2->toArray();
// $this->assertFalse($a2->isResource());
// $this->assertEquals('create test', $a2->getDescription());
// $this->assertFalse(isset($array2['filters']));
// $this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getInput());
//
// $a3 = $data[$httpsKey]['annotation'];
// $this->assertTrue($a3->getHttps());
//
// $a4 = $data[11]['annotation'];
// $this->assertTrue($a4->isResource());
// $this->assertEquals('TestResource', $a4->getResource());
//
// $a5 = $data[$httpsKey - 1]['annotation'];
// $a5requirements = $a5->getRequirements();
// $this->assertEquals('api.test.dev', $a5->getHost());
// $this->assertEquals('test.dev|test.com', $a5requirements['domain']['requirement']);
} }
public function testRouteVersionChecking(): void public function testRouteVersionChecking(): void
@ -114,7 +65,7 @@ class ApiDocExtractorTest extends WebTestCase
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor'); $extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1'); $annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1');
$this->assertInstanceOf('Nelmio\ApiDocBundle\Annotation\ApiDoc', $annotation); $this->assertInstanceOf('Nelmio\ApiDocBundle\Attribute\ApiDoc', $annotation);
$this->assertTrue($annotation->isResource()); $this->assertTrue($annotation->isResource());
$this->assertEquals('index action', $annotation->getDescription()); $this->assertEquals('index action', $annotation->getDescription());
@ -210,21 +161,6 @@ class ApiDocExtractorTest extends WebTestCase
); );
} }
public function testGetWithAuthentication(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::AuthenticatedAction', 'test_route_13');
$this->assertNotNull($annotation);
$this->assertTrue(
$annotation->getAuthentication()
);
$this->assertContains('ROLE_USER', $annotation->getAuthenticationRoles());
$this->assertContains('ROLE_FOOBAR', $annotation->getAuthenticationRoles());
$this->assertCount(2, $annotation->getAuthenticationRoles());
}
public function testGetWithDeprecated(): void public function testGetWithDeprecated(): void
{ {
$container = $this->getContainer(); $container = $this->getContainer();
@ -298,12 +234,9 @@ class ApiDocExtractorTest extends WebTestCase
$this->assertFalse($parameters['required_field']['required']); $this->assertFalse($parameters['required_field']['required']);
} }
public static function dataProviderForViews() public static function dataProviderForViews(): array
{ {
$offset = 0; $offset = 0;
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
$offset = self::NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE;
}
return [ return [
['default', self::$ROUTES_QUANTITY_DEFAULT + $offset], ['default', self::$ROUTES_QUANTITY_DEFAULT + $offset],
@ -379,7 +312,7 @@ class ApiDocExtractorTest extends WebTestCase
'test_route_27' 'test_route_27'
); );
$this->assertInstanceOf('Nelmio\ApiDocBundle\Annotation\ApiDoc', $annotation); $this->assertInstanceOf('Nelmio\ApiDocBundle\Attribute\ApiDoc', $annotation);
$array = $annotation->toArray(); $array = $annotation->toArray();
$this->assertTrue(is_array($array['parameters'])); $this->assertTrue(is_array($array['parameters']));
@ -412,7 +345,7 @@ class ApiDocExtractorTest extends WebTestCase
'test_route_27' 'test_route_27'
); );
$this->assertInstanceOf('Nelmio\ApiDocBundle\Annotation\ApiDoc', $annotation); $this->assertInstanceOf('Nelmio\ApiDocBundle\Attribute\ApiDoc', $annotation);
$array = $annotation->toArray(); $array = $annotation->toArray();
$this->assertTrue(is_array($array['parameters'])); $this->assertTrue(is_array($array['parameters']));

View file

@ -11,7 +11,7 @@
namespace Nelmio\ApiDocBundle\Tests\Extractor; namespace Nelmio\ApiDocBundle\Tests\Extractor;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use Nelmio\ApiDocBundle\Extractor\CachingApiDocExtractor; use Nelmio\ApiDocBundle\Extractor\CachingApiDocExtractor;
use Nelmio\ApiDocBundle\Tests\WebTestCase; use Nelmio\ApiDocBundle\Tests\WebTestCase;

View file

@ -1,205 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Extractor;
use Nelmio\ApiDocBundle\Tests\WebTestCase;
class FosRestHandlerTest extends WebTestCase
{
public function testGetWithQueryParamStrict(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithQueryParamStrictAction', 'test_route_15');
$this->assertNotNull($annotation);
$requirements = $annotation->getRequirements();
$this->assertCount(1, $requirements);
$this->assertArrayHasKey('page', $requirements);
$requirement = $requirements['page'];
$this->assertArrayHasKey('requirement', $requirement);
$this->assertEquals($requirement['requirement'], '\d+');
$this->assertArrayHasKey('description', $requirement);
$this->assertEquals($requirement['description'], 'Page of the overview.');
$this->assertArrayHasKey('dataType', $requirement);
$this->assertArrayNotHasKey('default', $requirement);
}
public function testGetWithQueryParam(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithQueryParamAction', 'test_route_8');
$this->assertNotNull($annotation);
$filters = $annotation->getFilters();
$this->assertCount(1, $filters);
$this->assertArrayHasKey('page', $filters);
$filter = $filters['page'];
$this->assertArrayHasKey('requirement', $filter);
$this->assertEquals($filter['requirement'], '\d+');
$this->assertArrayHasKey('description', $filter);
$this->assertEquals($filter['description'], 'Page of the overview.');
$this->assertArrayHasKey('default', $filter);
$this->assertEquals($filter['default'], '1');
}
public function testGetWithQueryParamNoDefault(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithQueryParamNoDefaultAction', 'test_route_16');
$this->assertNotNull($annotation);
$filters = $annotation->getFilters();
$this->assertCount(1, $filters);
$this->assertArrayHasKey('page', $filters);
$filter = $filters['page'];
$this->assertArrayHasKey('requirement', $filter);
$this->assertEquals($filter['requirement'], '\d+');
$this->assertArrayHasKey('description', $filter);
$this->assertEquals($filter['description'], 'Page of the overview.');
$this->assertArrayNotHasKey('default', $filter);
}
public function testGetWithConstraintAsRequirements(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithConstraintAsRequirements', 'test_route_21');
$this->assertNotNull($annotation);
$filters = $annotation->getFilters();
$this->assertCount(1, $filters);
$this->assertArrayHasKey('mail', $filters);
$filter = $filters['mail'];
$this->assertArrayHasKey('requirement', $filter);
$this->assertEquals($filter['requirement'], 'Email');
}
public function testGetWithRequestParam(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithRequestParamAction', 'test_route_11');
$this->assertNotNull($annotation);
$parameters = $annotation->getParameters();
$this->assertCount(1, $parameters);
$this->assertArrayHasKey('param1', $parameters);
$parameter = $parameters['param1'];
$this->assertArrayHasKey('dataType', $parameter);
$this->assertEquals($parameter['dataType'], 'string');
$this->assertArrayHasKey('description', $parameter);
$this->assertEquals($parameter['description'], 'Param1 description.');
$this->assertArrayHasKey('required', $parameter);
$this->assertEquals($parameter['required'], true);
$this->assertArrayNotHasKey('default', $parameter);
}
public function testGetWithRequestParamNullable(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithNullableRequestParamAction', 'test_route_22');
$this->assertNotNull($annotation);
$parameters = $annotation->getParameters();
$this->assertCount(1, $parameters);
$this->assertArrayHasKey('param1', $parameters);
$parameter = $parameters['param1'];
$this->assertArrayHasKey('dataType', $parameter);
$this->assertEquals($parameter['dataType'], 'string');
$this->assertArrayHasKey('description', $parameter);
$this->assertEquals($parameter['description'], 'Param1 description.');
$this->assertArrayHasKey('required', $parameter);
$this->assertEquals($parameter['required'], false);
$this->assertArrayNotHasKey('default', $parameter);
}
public function testWithRequestParamArrayRequirements(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::routeWithQueryParamArrayRequirementsAction', 'test_route_29');
$this->assertNotNull($annotation);
$filters = $annotation->getFilters();
$this->assertArrayHasKey('param1', $filters);
$this->assertArrayHasKey('requirement', $filters['param1']);
$this->assertEquals('regexp', $filters['param1']['requirement']);
}
public function testWithRequestParamPlainArrayRequirements(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::routeWithQueryParamPlainArrayRequirementsAction', 'test_route_30');
$this->assertNotNull($annotation);
$filters = $annotation->getFilters();
$this->assertArrayHasKey('param1', $filters);
$this->assertArrayHasKey('requirement', $filters['param1']);
$this->assertEquals('NotNull, NotBlank', $filters['param1']['requirement']);
}
public function testWithRequirementParamNotSet(): void
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithRequirementParamNotSet', 'test_route_31');
$this->assertNotNull($annotation);
$filters = $annotation->getFilters();
$this->assertCount(1, $filters);
$this->assertArrayHasKey('param1', $filters);
$filter = $filters['param1'];
$this->assertArrayNotHasKey('requirement', $filter);
$this->assertArrayHasKey('description', $filter);
$this->assertEquals($filter['description'], 'Param1 description.');
}
}

View file

@ -11,76 +11,62 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Controller; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Controller;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
class ResourceController class ResourceController
{ {
/** #[ApiDoc(
* @ApiDoc( resource: true,
* resource=true, views: ['test', 'premium', 'default'],
* views={ "test", "premium", "default" }, resourceDescription: 'Operations on resource.',
* resourceDescription="Operations on resource.", description: 'List resources.',
* description="List resources.", output: "array<Nelmio\ApiDocBundle\Tests\Fixtures\Model\Test> as tests",
* output="array<Nelmio\ApiDocBundle\Tests\Fixtures\Model\Test> as tests", statusCodes: [200 => 'Returned on success.', 404 => 'Returned if resource cannot be found.']
* statusCodes={200 = "Returned on success.", 404 = "Returned if resource cannot be found."} )]
* )
*/
public function listResourcesAction(): void public function listResourcesAction(): void
{ {
} }
/** #[ApiDoc(description: 'Retrieve a resource by ID.')]
* @ApiDoc(description="Retrieve a resource by ID.")
*/
public function getResourceAction(): void public function getResourceAction(): void
{ {
} }
/** #[ApiDoc(description: 'Delete a resource by ID.')]
* @ApiDoc(description="Delete a resource by ID.")
*/
public function deleteResourceAction(): void public function deleteResourceAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( description: 'Create a new resource.',
* description="Create a new resource.", views: ['default', 'premium'],
* views={ "default", "premium" }, input: ['class' => "Nelmio\ApiDocBundle\Tests\Fixtures\Form\SimpleType", 'name' => ''],
* input={"class" = "Nelmio\ApiDocBundle\Tests\Fixtures\Form\SimpleType", "name" = ""}, output: "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested",
* output="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested", responseMap: [
* responseMap={ 400 => ['class' => "Nelmio\ApiDocBundle\Tests\Fixtures\Form\SimpleType", 'form_errors' => true],
* 400 = {"class" = "Nelmio\ApiDocBundle\Tests\Fixtures\Form\SimpleType", "form_errors" = true} ]
* } )]
* )
*/
public function createResourceAction(): void public function createResourceAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( resource: true,
* resource=true, views: ['default', 'premium'],
* views={ "default", "premium" }, description: 'List another resource.',
* description="List another resource.", resourceDescription: 'Operations on another resource.',
* resourceDescription="Operations on another resource.", output: "array<Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest>"
* output="array<Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest>" )]
* )
*/
public function listAnotherResourcesAction(): void public function listAnotherResourcesAction(): void
{ {
} }
/** #[ApiDoc(description: 'Retrieve another resource by ID.')]
* @ApiDoc(description="Retrieve another resource by ID.")
*/
public function getAnotherResourceAction(): void public function getAnotherResourceAction(): void
{ {
} }
/** #[ApiDoc(description: 'Update a resource bu ID.')]
* @ApiDoc(description="Update a resource bu ID.")
*/
public function updateAnotherResourceAction(): void public function updateAnotherResourceAction(): void
{ {
} }

View file

@ -11,68 +11,57 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Controller; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Controller;
use FOS\RestBundle\Controller\Annotations\QueryParam; use Nelmio\ApiDocBundle\Attribute\ApiDoc;
use FOS\RestBundle\Controller\Annotations\RequestParam;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Tests\Fixtures\DependencyTypePath; use Nelmio\ApiDocBundle\Tests\Fixtures\DependencyTypePath;
use Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints as Assert;
class TestController class TestController
{ {
/** #[ApiDoc(
* @ApiDoc( resource: 'TestResource',
* resource="TestResource", views: 'default'
* views="default" )]
* )
*/
public function namedResourceAction(): void public function namedResourceAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( resource: true,
* resource=true, description: 'index action',
* description="index action", filters: [
* filters={ ['name' => 'a', 'dataType' => 'integer'],
* {"name"="a", "dataType"="integer"}, ['name' => 'b', 'dataType' => 'string', 'arbitrary' => ['arg1', 'arg2']],
* {"name"="b", "dataType"="string", "arbitrary"={"arg1", "arg2"}} ],
* } )]
* )
*/
public function indexAction() public function indexAction()
{ {
return new Response('tests'); return new Response('tests');
} }
/** #[ApiDoc(
* @ApiDoc( resource: true,
* resource=true, description: 'create test',
* description="create test", views: ['default', 'premium'],
* views={ "default", "premium" }, input: TestType::class
* input="Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType" )]
* )
*/
public function postTestAction(): void public function postTestAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( description: 'post test 2',
* description="post test 2", views: ['default', 'premium'],
* views={ "default", "premium" }, resource: true
* resource=true )]
* )
*/
public function postTest2Action(): void public function postTest2Action(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( description: 'Action with required parameters',
* input="Nelmio\ApiDocBundle\Tests\Fixtures\Form\RequiredType" input: "Nelmio\ApiDocBundle\Tests\Fixtures\Form\RequiredType"
* ) )]
*/
public function requiredParametersAction(): void public function requiredParametersAction(): void
{ {
} }
@ -81,16 +70,12 @@ class TestController
{ {
} }
/** #[ApiDoc]
* @ApiDoc()
*/
public function routeVersionAction(): void public function routeVersionAction(): void
{ {
} }
/** #[ApiDoc(description: 'Action without HTTP verb')]
* @ApiDoc(description="Action without HTTP verb")
*/
public function anyAction(): void public function anyAction(): void
{ {
} }
@ -99,332 +84,193 @@ class TestController
* This method is useful to test if the getDocComment works. * This method is useful to test if the getDocComment works.
* And, it supports multilines until the first '@' char. * And, it supports multilines until the first '@' char.
* *
* @ApiDoc()
*
* @param int $id A nice comment * @param int $id A nice comment
* @param int $page * @param int $page
* @param int $paramType The param type * @param int $paramType The param type
* @param int $param The param id * @param int $param The param id
*/ */
#[ApiDoc]
public function myCommentedAction($id, $page, int $paramType, int $param): void public function myCommentedAction($id, $page, int $paramType, int $param): void
{ {
} }
/** #[ApiDoc]
* @ApiDoc()
*/
public function yetAnotherAction(): void public function yetAnotherAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( views: ['default', 'test'],
* views= { "default", "test" }, description: 'create another test',
* description="create another test", input: DependencyTypePath::TYPE
* input=DependencyTypePath::TYPE )]
* )
*/
public function anotherPostAction(): void public function anotherPostAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc() description: 'Testing JMS',
* input: "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest"
* @QueryParam(strict=true, name="page", requirements="\d+", description="Page of the overview.") )]
*/
public function zActionWithQueryParamStrictAction(): void
{
}
/**
* @ApiDoc()
*
* @QueryParam(name="page", requirements="\d+", default="1", description="Page of the overview.")
*/
public function zActionWithQueryParamAction(): void
{
}
/**
* @ApiDoc()
*
* @QueryParam(name="page", requirements="\d+", description="Page of the overview.")
*/
public function zActionWithQueryParamNoDefaultAction(): void
{
}
/**
* @ApiDoc()
*
* @QueryParam(name="mail", requirements=@Assert\Email, description="Email of someone.")
*/
public function zActionWithConstraintAsRequirements(): void
{
}
/**
* @ApiDoc(
* description="Testing JMS",
* input="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest"
* )
*/
public function jmsInputTestAction(): void public function jmsInputTestAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( description: 'Testing return',
* description="Testing return", output: DependencyTypePath::TYPE
* output=DependencyTypePath::TYPE )]
* )
*/
public function jmsReturnTestAction(): void public function jmsReturnTestAction(): void
{ {
} }
/** #[ApiDoc]
* @ApiDoc()
*
* @RequestParam(name="param1", requirements="string", description="Param1 description.")
*/
public function zActionWithRequestParamAction(): void
{
}
/**
* @ApiDoc()
*
* @RequestParam(name="param1", requirements="string", description="Param1 description.", nullable=true)
*/
public function zActionWithNullableRequestParamAction(): void
{
}
/**
* @ApiDoc()
*/
public function secureRouteAction(): void
{
}
/**
* @ApiDoc(
* authentication=true,
* authenticationRoles={"ROLE_USER","ROLE_FOOBAR"}
* )
*/
public function authenticatedAction(): void
{
}
/**
* @ApiDoc()
*/
public function zCachedAction(): void public function zCachedAction(): void
{ {
} }
/** #[ApiDoc]
* @ApiDoc()
*/
public function zSecuredAction(): void public function zSecuredAction(): void
{ {
} }
/** /**
* @ApiDoc()
*
* @deprecated * @deprecated
*/ */
#[ApiDoc]
public function deprecatedAction(): void public function deprecatedAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( output: "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest"
* output="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest" )]
* )
*/
public function jmsReturnNestedOutputAction(): void public function jmsReturnNestedOutputAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( output: "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsChild"
* output="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsChild" )]
* )
*/
public function jmsReturnNestedExtendedOutputAction(): void public function jmsReturnNestedExtendedOutputAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( output: "Nelmio\ApiDocBundle\Tests\Fixtures\Model\MultipleTest"
* output="Nelmio\ApiDocBundle\Tests\Fixtures\Model\MultipleTest" )]
* )
*/
public function zReturnJmsAndValidationOutputAction(): void public function zReturnJmsAndValidationOutputAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( description: 'Returns a collection of Object',
* description="Returns a collection of Object", requirements: [
* requirements={ ['name' => 'limit', 'dataType' => 'integer', 'requirement' => "\d+", 'description' => 'how many objects to return'],
* {"name"="limit", "dataType"="integer", "requirement"="\d+", "description"="how many objects to return"} ],
* }, parameters: [
* parameters={ ['name' => 'categoryId', 'dataType' => 'integer', 'required' => true, 'description' => 'category id'],
* {"name"="categoryId", "dataType"="integer", "required"=true, "description"="category id"} ]
* } )]
* )
*/
public function cgetAction($id): void public function cgetAction($id): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( input: [
* input={ 'class' => TestType::class,
* "class"="Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType", 'parsers' => ["Nelmio\ApiDocBundle\Parser\FormTypeParser"],
* "parsers"={ ]
* "Nelmio\ApiDocBundle\Parser\FormTypeParser", )]
* }
* }
* )
*/
public function zReturnSelectedParsersInputAction(): void public function zReturnSelectedParsersInputAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( output: [
* output={ 'class' => "Nelmio\ApiDocBundle\Tests\Fixtures\Model\MultipleTest",
* "class"="Nelmio\ApiDocBundle\Tests\Fixtures\Model\MultipleTest", 'parsers' => [
* "parsers"={ "Nelmio\ApiDocBundle\Parser\JmsMetadataParser",
* "Nelmio\ApiDocBundle\Parser\JmsMetadataParser", "Nelmio\ApiDocBundle\Parser\ValidationParser",
* "Nelmio\ApiDocBundle\Parser\ValidationParser" ],
* } ]
* } )]
* )
*/
public function zReturnSelectedParsersOutputAction(): void public function zReturnSelectedParsersOutputAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( section: 'private'
* section="private" )]
* )
*/
public function privateAction(): void public function privateAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( section: 'exclusive'
* section="exclusive" )]
* )
*/
public function exclusiveAction(): void public function exclusiveAction(): void
{ {
} }
/** /**
* @ApiDoc()
*
* @see http://symfony.com * @see http://symfony.com
*/ */
#[ApiDoc]
public function withLinkAction(): void public function withLinkAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( input: ['class' => "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest"],
* output="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest", output: "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest",
* input={ parameters: [
* "class" = "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest" [
* }, 'name' => 'number',
* parameters={ 'dataType' => 'integer',
* { 'actualType' => 'string',
* "name"="number", 'subType' => null,
* "dataType"="integer", 'required' => true,
* "actualType"="string", 'description' => 'This is the new description',
* "subType"=null, 'readonly' => false,
* "required"=true, 'sinceVersion' => 'v3.0',
* "description"="This is the new description", 'untilVersion' => 'v4.0',
* "readonly"=false, ],
* "sinceVersion"="v3.0", [
* "untilVersion"="v4.0" 'name' => 'arr',
* }, 'dataType' => 'object (ArrayCollection)',
* { ],
* "name"="arr", [
* "dataType"="object (ArrayCollection)" 'name' => 'nested',
* }, 'dataType' => 'object (JmsNested)',
* { 'children' => [
* "name"="nested", 'bar' => [
* "dataType"="object (JmsNested)", 'dataType' => 'integer',
* "children": { 'format' => 'd+',
* "bar": { ],
* "dataType"="integer", ],
* "format"="d+" ],
* } ]
* } )]
* }
* }
* )
*/
public function overrideJmsAnnotationWithApiDocParametersAction(): void public function overrideJmsAnnotationWithApiDocParametersAction(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( output: "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest",
* output="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest", input: [
* input={ 'class' => "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest",
* "class" = "Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest" ],
* } )]
* )
*/
public function defaultJmsAnnotations(): void public function defaultJmsAnnotations(): void
{ {
} }
/** #[ApiDoc(
* @ApiDoc( description: 'Route with host placeholder',
* description="Route with host placeholder", views: ['default']
* views={ "default" } )]
* )
*/
public function routeWithHostAction(): void public function routeWithHostAction(): void
{ {
} }
/**
* @ApiDoc()
*
* @QueryParam(name="param1", requirements={"rule": "regexp", "error_message": "warning"}, description="Param1 description.")
*/
public function routeWithQueryParamArrayRequirementsAction(): void
{
}
/**
* @ApiDoc()
*
* @QueryParam(name="param1", requirements={@Assert\NotNull(), @Assert\NotBlank()}, description="Param1 description.")
*/
public function routeWithQueryParamPlainArrayRequirementsAction(): void
{
}
/**
* @ApiDoc()
*
* @QueryParam(name="param1", description="Param1 description.")
*/
public function zActionWithRequirementParamNotSet(): void
{
}
} }

View file

@ -11,9 +11,6 @@
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model; namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class Popo class Popo
{ {
/** /**

View file

@ -29,11 +29,6 @@ class AppKernel extends Kernel
new \Nelmio\ApiDocBundle\Tests\Fixtures\NelmioApiDocTestBundle(), new \Nelmio\ApiDocBundle\Tests\Fixtures\NelmioApiDocTestBundle(),
]; ];
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
$bundles[] = new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle();
$bundles[] = new \Dunglas\ApiBundle\DunglasApiBundle();
}
return $bundles; return $bundles;
} }
@ -56,10 +51,6 @@ class AppKernel extends Kernel
{ {
$loader->load(__DIR__ . '/config/' . $this->environment . '.yml'); $loader->load(__DIR__ . '/config/' . $this->environment . '.yml');
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
$loader->load(__DIR__ . '/config/dunglas_api.yml');
}
// If symfony/framework-bundle > 3.0 // If symfony/framework-bundle > 3.0
if (!class_exists('Symfony\Bundle\FrameworkBundle\Command\RouterApacheDumperCommand')) { if (!class_exists('Symfony\Bundle\FrameworkBundle\Command\RouterApacheDumperCommand')) {
$loader->load(__DIR__ . '/config/twig_assets.yml'); $loader->load(__DIR__ . '/config/twig_assets.yml');

View file

@ -1,22 +0,0 @@
doctrine:
dbal:
driver: "pdo_sqlite"
path: "%kernel.cache_dir%/db.sqlite"
charset: "UTF8"
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
framework:
router: { resource: "%kernel.project_dir%/config/dunglas_api_routing.yml" }
dunglas_api:
title: API
description: Test API
services:
dunglas_api.popo:
parent: api.resource
arguments: [ Nelmio\ApiDocBundle\Tests\Fixtures\Model\Popo ]
tags: [ { name: api.resource } ]

View file

@ -1,6 +0,0 @@
main:
resource: "routing.yml"
dunglas_api:
resource: "."
type: "api"

View file

@ -32,11 +32,6 @@ test_route_7:
methods: [POST] methods: [POST]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::anotherPostAction, _format: json } defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::anotherPostAction, _format: json }
test_route_8:
path: /z-action-with-query-param
methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithQueryParamAction }
test_route_9: test_route_9:
path: /jms-input-test path: /jms-input-test
methods: [POST] methods: [POST]
@ -47,20 +42,6 @@ test_route_10:
methods: [GET] methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::jmsReturnTestAction } defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::jmsReturnTestAction }
test_route_11:
path: /z-action-with-request-param
methods: [POST]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithRequestParamAction }
test_route_12:
path: /secure-route
schemes: [https]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::secureRouteAction }
test_route_13:
path: /authenticated
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::authenticatedAction }
test_service_route_1: test_service_route_1:
path: /tests.{_format} path: /tests.{_format}
methods: [GET] methods: [GET]
@ -89,16 +70,6 @@ test_route_14:
methods: [POST] methods: [POST]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::postTest2Action, _format: json } defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::postTest2Action, _format: json }
test_route_15:
path: /z-action-with-query-param-strict
methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithQueryParamStrictAction }
test_route_16:
path: /z-action-with-query-param-no-default
methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithQueryParamNoDefaultAction }
test_route_17: test_route_17:
path: /z-action-with-deprecated-indicator path: /z-action-with-deprecated-indicator
methods: [GET] methods: [GET]
@ -136,16 +107,6 @@ test_route_exclusive:
path: /exclusive path: /exclusive
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::exclusiveAction } defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::exclusiveAction }
test_route_21:
path: /z-action-with-constraint-requirements
methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithConstraintAsRequirementsAction }
test_route_22:
path: /z-action-with-nullable-request-param
methods: [POST]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithNullableRequestParamAction }
test_route_list_resource: test_route_list_resource:
path: /api/resources.{_format} path: /api/resources.{_format}
methods: [GET] methods: [GET]
@ -239,21 +200,6 @@ test_route_28:
domain: "%domain_dev%|%domain_prod%" domain: "%domain_dev%|%domain_prod%"
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::routeWithHostAction, domain: "%domain_dev%", _format: json } defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::routeWithHostAction, domain: "%domain_dev%", _format: json }
test_route_29:
path: /z-query-param-array-requirements
methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::routeWithQueryParamArrayRequirementsAction }
test_route_30:
path: /z-query-param-plain-array-requirements
methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::routeWithQueryParamPlainArrayRequirementsAction }
test_route_31:
path: /z-query-requirement-param-not-set
methods: [GET]
defaults: { _controller: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::zActionWithRequirementParamNotSet }
test_route_version_checking: test_route_version_checking:
path: /zz-tests-route-version.{_format} path: /zz-tests-route-version.{_format}
methods: [GET] methods: [GET]

View file

@ -26,13 +26,13 @@ class MarkdownFormatterTest extends WebTestCase
restore_error_handler(); restore_error_handler();
$result = $container->get('nelmio_api_doc.formatter.markdown_formatter')->format($data); $result = $container->get('nelmio_api_doc.formatter.markdown_formatter')->format($data);
$suffix = class_exists('Dunglas\ApiBundle\DunglasApiBundle') ? '' : '_1'; $suffix = '_1';
$expected = file_get_contents(__DIR__ . '/testFormat-result' . $suffix . '.markdown'); $expected = file_get_contents(__DIR__ . '/testFormat-result' . $suffix . '.markdown');
if (LegacyFormHelper::isLegacy()) { if (LegacyFormHelper::isLegacy()) {
$expected = str_replace('DependencyType', 'dependency_type', $expected); $expected = str_replace('DependencyType', 'dependency_type', $expected);
} }
$this->assertEquals($expected, $result . "\n"); $this->assertEquals($expected, $result . "\n", 'file ' . __DIR__ . '/testFormat-result' . $suffix . '.markdown');
} }
public function testFormatOne(): void public function testFormatOne(): void

View file

@ -25,10 +25,10 @@ class SimpleFormatterTest extends WebTestCase
restore_error_handler(); restore_error_handler();
$result = $container->get('nelmio_api_doc.formatter.simple_formatter')->format($data); $result = $container->get('nelmio_api_doc.formatter.simple_formatter')->format($data);
$suffix = class_exists('Dunglas\ApiBundle\DunglasApiBundle') ? '' : '_1'; $suffix = '_1';
$expected = require __DIR__ . '/testFormat-result' . $suffix . '.php'; $expected = require __DIR__ . '/testFormat-result' . $suffix . '.php';
$this->assertEquals($expected, $result); $this->assertEquals($expected, $result, 'file ' . __DIR__ . '/testFormat-result' . $suffix . '.php');
} }
public function testFormatOne(): void public function testFormatOne(): void
@ -58,9 +58,6 @@ class SimpleFormatterTest extends WebTestCase
'requirements' => [ 'requirements' => [
'_format' => ['dataType' => '', 'description' => '', 'requirement' => ''], '_format' => ['dataType' => '', 'description' => '', 'requirement' => ''],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
]; ];

View file

@ -41,119 +41,51 @@ class SwaggerFormatterTest extends WebTestCase
/** @var $formatter SwaggerFormatter */ /** @var $formatter SwaggerFormatter */
$actual = $this->formatter->format($data, null); $actual = $this->formatter->format($data, null);
if (class_exists('Dunglas\ApiBundle\DunglasApiBundle')) { $expected = [
$expected = [ 'swaggerVersion' => '1.2',
'swaggerVersion' => '1.2', 'apiVersion' => '3.14',
'apis' => [ 'info' => [
0 => [ 'title' => 'Nelmio Swagger',
'path' => '/other-resources', 'description' => 'Testing Swagger integration.',
'description' => 'Operations on another resource.', 'TermsOfServiceUrl' => 'https://github.com',
], 'contact' => 'user@domain.tld',
1 => [ 'license' => 'MIT',
'path' => '/resources', 'licenseUrl' => 'http://opensource.org/licenses/MIT',
'description' => 'Operations on resource.', ],
], 'authorizations' => [
2 => [ 'apiKey' => [
'path' => '/tests', 'type' => 'apiKey',
'description' => null, 'passAs' => 'header',
], 'keyname' => 'access_token',
3 => [
'path' => '/tests',
'description' => null,
],
4 => [
'path' => '/tests2',
'description' => null,
],
5 => [
'path' => '/TestResource',
'description' => null,
],
6 => [
'path' => '/others',
'description' => 'Popo',
],
7 => [
'path' => '/others',
'description' => 'Popo',
],
8 => [
'path' => '/others',
'description' => 'Popo',
],
9 => [
'path' => '/others',
'description' => 'Popo',
],
10 => [
'path' => '/others',
'description' => 'Popo',
],
], ],
'apiVersion' => '3.14', ],
'info' => [ 'apis' => [
'title' => 'Nelmio Swagger', [
'description' => 'Testing Swagger integration.', 'path' => '/other-resources',
'TermsOfServiceUrl' => 'https://github.com', 'description' => 'Operations on another resource.',
'contact' => 'user@domain.tld',
'license' => 'MIT',
'licenseUrl' => 'http://opensource.org/licenses/MIT',
], ],
'authorizations' => [ [
'apiKey' => [ 'path' => '/resources',
'type' => 'apiKey', 'description' => 'Operations on resource.',
'passAs' => 'header',
'keyname' => 'access_token',
],
], ],
]; [
} else { 'path' => '/tests',
$expected = [ 'description' => null,
'swaggerVersion' => '1.2',
'apiVersion' => '3.14',
'info' => [
'title' => 'Nelmio Swagger',
'description' => 'Testing Swagger integration.',
'TermsOfServiceUrl' => 'https://github.com',
'contact' => 'user@domain.tld',
'license' => 'MIT',
'licenseUrl' => 'http://opensource.org/licenses/MIT',
], ],
'authorizations' => [ [
'apiKey' => [ 'path' => '/tests',
'type' => 'apiKey', 'description' => null,
'passAs' => 'header',
'keyname' => 'access_token',
],
], ],
'apis' => [ [
[ 'path' => '/tests2',
'path' => '/other-resources', 'description' => null,
'description' => 'Operations on another resource.',
],
[
'path' => '/resources',
'description' => 'Operations on resource.',
],
[
'path' => '/tests',
'description' => null,
],
[
'path' => '/tests',
'description' => null,
],
[
'path' => '/tests2',
'description' => null,
],
[
'path' => '/TestResource',
'description' => null,
],
], ],
]; [
} 'path' => '/TestResource',
'description' => null,
],
],
];
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
} }

View file

@ -1,947 +0,0 @@
## /api/other-resources ##
### `GET` /api/other-resources.{_format} ###
_List another resource._
#### Requirements ####
**_format**
- Requirement: json|xml|html
#### Response ####
[]:
* type: array of objects (JmsTest)
[][foo]:
* type: string
[][bar]:
* type: DateTime
[][number]:
* type: double
[][arr]:
* type: array
[][nested]:
* type: object (JmsNested)
[][nested][foo]:
* type: DateTime
[][nested][bar]:
* type: string
[][nested][baz][]:
* type: array of integers
* description: Epic description.
With multiple lines.
[][nested][circular]:
* type: object (JmsNested)
[][nested][parent]:
* type: object (JmsTest)
[][nested][parent][foo]:
* type: string
[][nested][parent][bar]:
* type: DateTime
[][nested][parent][number]:
* type: double
[][nested][parent][arr]:
* type: array
[][nested][parent][nested]:
* type: object (JmsNested)
[][nested][parent][nested_array][]:
* type: array of objects (JmsNested)
[][nested][since]:
* type: string
* versions: >=0.2
[][nested][until]:
* type: string
* versions: <=0.3
[][nested][since_and_until]:
* type: string
* versions: >=0.4,<=0.5
[][nested_array][]:
* type: array of objects (JmsNested)
### `PUT|PATCH` /api/other-resources/{id}.{_format} ###
_Update a resource bu ID._
#### Requirements ####
**_format**
- Requirement: json|xml|html
**id**
## /api/resources ##
### `GET` /api/resources.{_format} ###
_List resources._
#### Requirements ####
**_format**
- Requirement: json|xml|html
#### Response ####
tests[]:
* type: array of objects (Test)
tests[][a]:
* type: string
tests[][b]:
* type: DateTime
### `POST` /api/resources.{_format} ###
_Create a new resource._
#### Requirements ####
**_format**
- Requirement: json|xml|html
#### Parameters ####
a:
* type: string
* required: true
* description: Something that describes A.
b:
* type: float
* required: true
c:
* type: choice
* required: true
d:
* type: datetime
* required: true
e:
* type: date
* required: true
g:
* type: string
* required: true
#### Response ####
foo:
* type: DateTime
bar:
* type: string
baz[]:
* type: array of integers
* description: Epic description.
With multiple lines.
circular:
* type: object (JmsNested)
circular[foo]:
* type: DateTime
circular[bar]:
* type: string
circular[baz][]:
* type: array of integers
* description: Epic description.
With multiple lines.
circular[circular]:
* type: object (JmsNested)
circular[parent]:
* type: object (JmsTest)
circular[parent][foo]:
* type: string
circular[parent][bar]:
* type: DateTime
circular[parent][number]:
* type: double
circular[parent][arr]:
* type: array
circular[parent][nested]:
* type: object (JmsNested)
circular[parent][nested_array][]:
* type: array of objects (JmsNested)
circular[since]:
* type: string
* versions: >=0.2
circular[until]:
* type: string
* versions: <=0.3
circular[since_and_until]:
* type: string
* versions: >=0.4,<=0.5
parent:
* type: object (JmsTest)
parent[foo]:
* type: string
parent[bar]:
* type: DateTime
parent[number]:
* type: double
parent[arr]:
* type: array
parent[nested]:
* type: object (JmsNested)
parent[nested_array][]:
* type: array of objects (JmsNested)
since:
* type: string
* versions: >=0.2
until:
* type: string
* versions: <=0.3
since_and_until:
* type: string
* versions: >=0.4,<=0.5
### `DELETE` /api/resources/{id}.{_format} ###
_Delete a resource by ID._
#### Requirements ####
**_format**
- Requirement: json|xml|html
**id**
### `GET` /api/resources/{id}.{_format} ###
_Retrieve a resource by ID._
#### Requirements ####
**_format**
- Requirement: json|xml|html
**id**
## /tests ##
### `GET` /tests.{_format} ###
_index action_
#### Requirements ####
**_format**
#### Filters ####
a:
* DataType: integer
b:
* DataType: string
* Arbitrary: ["arg1","arg2"]
### `GET` /tests.{_format} ###
_index action_
#### Requirements ####
**_format**
#### Filters ####
a:
* DataType: integer
b:
* DataType: string
* Arbitrary: ["arg1","arg2"]
### `POST` /tests.{_format} ###
_create test_
#### Requirements ####
**_format**
#### Parameters ####
a:
* type: string
* required: true
* description: A nice description
b:
* type: string
* required: false
c:
* type: boolean
* required: true
d:
* type: string
* required: true
* default value: DefaultTest
### `POST` /tests.{_format} ###
_create test_
#### Requirements ####
**_format**
#### Parameters ####
a:
* type: string
* required: true
* description: A nice description
b:
* type: string
* required: false
c:
* type: boolean
* required: true
d:
* type: string
* required: true
* default value: DefaultTest
## /tests2 ##
### `POST` /tests2.{_format} ###
_post test 2_
#### Requirements ####
**_format**
## TestResource ##
### `ANY` /named-resource ###
### `POST` /another-post ###
_create another test_
#### Parameters ####
dependency_type:
* type: object (DependencyType)
* required: true
dependency_type[a]:
* type: string
* required: true
* description: A nice description
### `ANY` /any ###
_Action without HTTP verb_
### `ANY` /any/{foo} ###
_Action without HTTP verb_
#### Requirements ####
**foo**
### `ANY` /authenticated ###
### `POST` /jms-input-test ###
_Testing JMS_
#### Parameters ####
foo:
* type: string
* required: false
number:
* type: double
* required: false
arr:
* type: array
* required: false
nested:
* type: object (JmsNested)
* required: false
nested[bar]:
* type: string
* required: false
* default value: baz
nested[baz][]:
* type: array of integers
* required: false
* description: Epic description.
With multiple lines.
nested[circular]:
* type: object (JmsNested)
* required: false
nested[parent]:
* type: object (JmsTest)
* required: false
nested[parent][foo]:
* type: string
* required: false
nested[parent][number]:
* type: double
* required: false
nested[parent][arr]:
* type: array
* required: false
nested[parent][nested]:
* type: object (JmsNested)
* required: false
nested[parent][nested_array][]:
* type: array of objects (JmsNested)
* required: false
nested[since]:
* type: string
* required: false
nested[until]:
* type: string
* required: false
nested[since_and_until]:
* type: string
* required: false
nested_array[]:
* type: array of objects (JmsNested)
* required: false
### `GET` /jms-return-test ###
_Testing return_
#### Response ####
dependency_type:
* type: object (DependencyType)
dependency_type[a]:
* type: string
* description: A nice description
### `ANY` /my-commented/{id}/{page}/{paramType}/{param} ###
_This method is useful to test if the getDocComment works._
This method is useful to test if the getDocComment works.
And, it supports multilines until the first '@' char.
#### Requirements ####
**id**
- Type: int
- Description: A nice comment
**page**
- Type: int
**paramType**
- Type: int
- Description: The param type
**param**
- Type: int
- Description: The param id
### `ANY` /return-nested-output ###
#### Response ####
foo:
* type: string
bar:
* type: DateTime
number:
* type: double
arr:
* type: array
nested:
* type: object (JmsNested)
nested[foo]:
* type: DateTime
nested[bar]:
* type: string
nested[baz][]:
* type: array of integers
* description: Epic description.
With multiple lines.
nested[circular]:
* type: object (JmsNested)
nested[parent]:
* type: object (JmsTest)
nested[parent][foo]:
* type: string
nested[parent][bar]:
* type: DateTime
nested[parent][number]:
* type: double
nested[parent][arr]:
* type: array
nested[parent][nested]:
* type: object (JmsNested)
nested[parent][nested_array][]:
* type: array of objects (JmsNested)
nested[since]:
* type: string
* versions: >=0.2
nested[until]:
* type: string
* versions: <=0.3
nested[since_and_until]:
* type: string
* versions: >=0.4,<=0.5
nested_array[]:
* type: array of objects (JmsNested)
### `GET` /route_with_host.{_format} ###
_Route with host placeholder_
#### Requirements ####
**domain**
- Requirement: test.dev|test.com
**_format**
### `ANY` /secure-route ###
### `ANY` /yet-another/{id} ###
#### Requirements ####
**id**
- Requirement: \d+
### `GET` /z-action-with-deprecated-indicator ###
### This method is deprecated ###
### `POST` /z-action-with-nullable-request-param ###
#### Parameters ####
param1:
* type: string
* required: false
* description: Param1 description.
### `GET` /z-action-with-query-param ###
#### Filters ####
page:
* Requirement: \d+
* Description: Page of the overview.
* Default: 1
### `GET` /z-action-with-query-param-no-default ###
#### Filters ####
page:
* Requirement: \d+
* Description: Page of the overview.
### `GET` /z-action-with-query-param-strict ###
#### Requirements ####
**page**
- Requirement: \d+
- Description: Page of the overview.
### `POST` /z-action-with-request-param ###
#### Parameters ####
param1:
* type: string
* required: true
* description: Param1 description.
### `ANY` /z-return-jms-and-validator-output ###
#### Response ####
bar:
* type: DateTime
objects[]:
* type: array of objects (Test)
objects[][a]:
* type: string
objects[][b]:
* type: DateTime
number:
* type: DateTime
related:
* type: object (Test)
related[a]:
* type: string
related[b]:
* type: DateTime
### `ANY` /z-return-selected-parsers-input ###
#### Parameters ####
a:
* type: string
* required: true
* description: A nice description
b:
* type: string
* required: false
c:
* type: boolean
* required: true
d:
* type: string
* required: true
* default value: DefaultTest
### `ANY` /z-return-selected-parsers-output ###
#### Response ####
bar:
* type: DateTime
objects[]:
* type: array of objects (Test)
objects[][a]:
* type: string
objects[][b]:
* type: DateTime
number:
* type: DateTime
related:
* type: object (Test)
related[a]:
* type: string
related[b]:
* type: DateTime
### `POST` /zcached ###
### `POST` /zsecured ###
### `GET` /zz-tests-route-version.{_format} ###
#### Requirements ####
**_format**

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -442,10 +442,6 @@ _Action without HTTP verb_
### `ANY` /authenticated ###
### `POST` /jms-input-test ### ### `POST` /jms-input-test ###
_Testing JMS_ _Testing JMS_
@ -686,10 +682,6 @@ _Route with host placeholder_
### `ANY` /secure-route ###
### `GET` /with-link ### ### `GET` /with-link ###
@ -710,96 +702,6 @@ _Route with host placeholder_
### `POST` /z-action-with-nullable-request-param ###
#### Parameters ####
param1:
* type: string
* required: false
* description: Param1 description.
### `GET` /z-action-with-query-param ###
#### Filters ####
page:
* Requirement: \d+
* Description: Page of the overview.
* Default: 1
### `GET` /z-action-with-query-param-no-default ###
#### Filters ####
page:
* Requirement: \d+
* Description: Page of the overview.
### `GET` /z-action-with-query-param-strict ###
#### Requirements ####
**page**
- Requirement: \d+
- Description: Page of the overview.
### `POST` /z-action-with-request-param ###
#### Parameters ####
param1:
* type: string
* required: true
* description: Param1 description.
### `GET` /z-query-param-array-requirements ###
#### Filters ####
param1:
* Requirement: regexp
* Description: Param1 description.
### `GET` /z-query-param-plain-array-requirements ###
#### Filters ####
param1:
* Requirement: NotNull, NotBlank
* Description: Param1 description.
### `GET` /z-query-requirement-param-not-set ###
#### Filters ####
param1:
* Description: Param1 description.
### `ANY` /z-return-jms-and-validator-output ### ### `ANY` /z-return-jms-and-validator-output ###

View file

@ -285,10 +285,6 @@ With multiple lines.',
], ],
], ],
'resourceDescription' => 'Operations on another resource.', 'resourceDescription' => 'Operations on another resource.',
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -308,10 +304,6 @@ With multiple lines.',
'description' => '', 'description' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -380,10 +372,6 @@ With multiple lines.',
], ],
], ],
'resourceDescription' => 'Operations on resource.', 'resourceDescription' => 'Operations on resource.',
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -819,10 +807,6 @@ With multiple lines.',
'untilVersion' => '0.5', 'untilVersion' => '0.5',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -842,10 +826,6 @@ With multiple lines.',
'description' => '', 'description' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -865,10 +845,6 @@ With multiple lines.',
'description' => '', 'description' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -897,10 +873,6 @@ With multiple lines.',
'description' => '', 'description' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -958,10 +930,6 @@ With multiple lines.',
0 => 'default', 0 => 'default',
1 => 'premium', 1 => 'premium',
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -982,10 +950,6 @@ With multiple lines.',
0 => 'default', 0 => 'default',
1 => 'premium', 1 => 'premium',
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -997,10 +961,6 @@ With multiple lines.',
'views' => [ 'views' => [
0 => 'default', 0 => 'default',
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -1036,10 +996,6 @@ With multiple lines.',
0 => 'default', 0 => 'default',
1 => 'test', 1 => 'test',
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
@ -1054,26 +1010,10 @@ With multiple lines.',
'description' => '', 'description' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
2 => [ 2 => [
'method' => 'ANY',
'uri' => '/authenticated',
'https' => false,
'authentication' => true,
'authenticationRoles' => [
0 => 'ROLE_USER',
1 => 'ROLE_FOOBAR',
],
'deprecated' => false,
'scope' => null,
],
3 => [
'method' => 'POST', 'method' => 'POST',
'uri' => '/jms-input-test', 'uri' => '/jms-input-test',
'description' => 'Testing JMS', 'description' => 'Testing JMS',
@ -1333,14 +1273,10 @@ With multiple lines.',
'untilVersion' => null, 'untilVersion' => null,
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
4 => [ 3 => [
'method' => 'GET', 'method' => 'GET',
'uri' => '/jms-return-test', 'uri' => '/jms-return-test',
'description' => 'Testing return', 'description' => 'Testing return',
@ -1366,14 +1302,10 @@ With multiple lines.',
], ],
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
5 => [ 4 => [
'method' => 'ANY', 'method' => 'ANY',
'uri' => '/my-commented/{id}/{page}/{paramType}/{param}', 'uri' => '/my-commented/{id}/{page}/{paramType}/{param}',
'description' => 'This method is useful to test if the getDocComment works.', 'description' => 'This method is useful to test if the getDocComment works.',
@ -1401,14 +1333,10 @@ And, it supports multilines until the first \'@\' char.',
'requirement' => '', 'requirement' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
6 => [ 5 => [
'method' => 'ANY', 'method' => 'ANY',
'uri' => '/return-nested-output', 'uri' => '/return-nested-output',
'response' => [ 'response' => [
@ -1667,14 +1595,10 @@ With multiple lines.',
'untilVersion' => null, 'untilVersion' => null,
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
7 => [ 6 => [
'method' => 'GET', 'method' => 'GET',
'uri' => '/route_with_host.{_format}', 'uri' => '/route_with_host.{_format}',
'host' => 'api.test.dev', 'host' => 'api.test.dev',
@ -1694,35 +1618,17 @@ With multiple lines.',
'views' => [ 'views' => [
0 => 'default', 0 => 'default',
], ],
'https' => false, 'deprecated' => false,
'authentication' => false, 'scope' => null,
'authenticationRoles' => [ ],
], 7 => [
'method' => 'GET',
'uri' => '/with-link',
'link' => 'http://symfony.com',
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
8 => [ 8 => [
'method' => 'ANY',
'uri' => '/secure-route',
'https' => true,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
9 => [
'method' => 'GET',
'uri' => '/with-link',
'link' => 'http://symfony.com',
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
10 => [
'method' => 'ANY', 'method' => 'ANY',
'uri' => '/yet-another/{id}', 'uri' => '/yet-another/{id}',
'requirements' => [ 'requirements' => [
@ -1732,161 +1638,16 @@ With multiple lines.',
'description' => '', 'description' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
11 => [ 9 => [
'method' => 'GET', 'method' => 'GET',
'uri' => '/z-action-with-deprecated-indicator', 'uri' => '/z-action-with-deprecated-indicator',
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => true, 'deprecated' => true,
'scope' => null, 'scope' => null,
], ],
12 => [ 10 => [
'method' => 'POST',
'uri' => '/z-action-with-nullable-request-param',
'parameters' => [
'param1' => [
'required' => false,
'dataType' => 'string',
'actualType' => 'string',
'subType' => null,
'description' => 'Param1 description.',
'readonly' => false,
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
13 => [
'method' => 'GET',
'uri' => '/z-action-with-query-param',
'filters' => [
'page' => [
'requirement' => '\\d+',
'description' => 'Page of the overview.',
'default' => '1',
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
14 => [
'method' => 'GET',
'uri' => '/z-action-with-query-param-no-default',
'filters' => [
'page' => [
'requirement' => '\\d+',
'description' => 'Page of the overview.',
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
15 => [
'method' => 'GET',
'uri' => '/z-action-with-query-param-strict',
'requirements' => [
'page' => [
'requirement' => '\\d+',
'dataType' => '',
'description' => 'Page of the overview.',
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
16 => [
'method' => 'POST',
'uri' => '/z-action-with-request-param',
'parameters' => [
'param1' => [
'required' => true,
'dataType' => 'string',
'actualType' => 'string',
'subType' => null,
'description' => 'Param1 description.',
'readonly' => false,
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
17 => [
'method' => 'GET',
'uri' => '/z-query-param-array-requirements',
'filters' => [
'param1' => [
'requirement' => 'regexp',
'description' => 'Param1 description.',
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
18 => [
'method' => 'GET',
'uri' => '/z-query-param-plain-array-requirements',
'filters' => [
'param1' => [
'requirement' => 'NotNull, NotBlank',
'description' => 'Param1 description.',
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
19 => [
'method' => 'GET',
'uri' => '/z-query-requirement-param-not-set',
'filters' => [
'param1' => [
'description' => 'Param1 description.',
],
],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false,
'scope' => null,
],
20 => [
'method' => 'ANY', 'method' => 'ANY',
'uri' => '/z-return-jms-and-validator-output', 'uri' => '/z-return-jms-and-validator-output',
'response' => [ 'response' => [
@ -1999,14 +1760,10 @@ With multiple lines.',
], ],
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
21 => [ 11 => [
'method' => 'ANY', 'method' => 'ANY',
'uri' => '/z-return-selected-parsers-input', 'uri' => '/z-return-selected-parsers-input',
'parameters' => [ 'parameters' => [
@ -2047,14 +1804,10 @@ With multiple lines.',
'readonly' => false, 'readonly' => false,
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
22 => [ 12 => [
'method' => 'ANY', 'method' => 'ANY',
'uri' => '/z-return-selected-parsers-output', 'uri' => '/z-return-selected-parsers-output',
'response' => [ 'response' => [
@ -2167,34 +1920,22 @@ With multiple lines.',
], ],
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
23 => [ 13 => [
'method' => 'POST', 'method' => 'POST',
'uri' => '/zcached', 'uri' => '/zcached',
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
24 => [ 14 => [
'method' => 'POST', 'method' => 'POST',
'uri' => '/zsecured', 'uri' => '/zsecured',
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],
25 => [ 15 => [
'method' => 'GET', 'method' => 'GET',
'uri' => '/zz-tests-route-version.{_format}', 'uri' => '/zz-tests-route-version.{_format}',
'requirements' => [ 'requirements' => [
@ -2204,10 +1945,6 @@ With multiple lines.',
'description' => '', 'description' => '',
], ],
], ],
'https' => false,
'authentication' => false,
'authenticationRoles' => [
],
'deprecated' => false, 'deprecated' => false,
'scope' => null, 'scope' => null,
], ],

View file

@ -1,51 +0,0 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NelmioApiDocBundle\Tests\Parser;
use Nelmio\ApiDocBundle\DataTypes;
use Nelmio\ApiDocBundle\Parser\DunglasApiParser;
use Nelmio\ApiDocBundle\Tests\WebTestCase;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DunglasApiParserTest extends WebTestCase
{
protected function setUp(): void
{
if (!class_exists('Dunglas\ApiBundle\DunglasApiBundle')) {
$this->markTestSkipped(
'DunglasApiBundle is not available.'
);
}
}
public function testParser(): void
{
$container = $this->getContainer();
$parser = $container->get('nelmio_api_doc.parser.dunglas_api_parser');
$item = ['class' => DunglasApiParser::OUT_PREFIX . ':Nelmio\ApiDocBundle\Tests\Fixtures\Model\Popo'];
$expected = [
'foo' => [
'required' => false,
'description' => '',
'readonly' => false,
'dataType' => DataTypes::STRING,
],
];
$this->assertTrue($parser->supports($item));
$this->assertEquals($expected, $parser->parse($item));
}
}

View file

@ -13,9 +13,5 @@ if ((!$loader = includeIfExists(__DIR__ . '/../vendor/autoload.php')) && (!$load
'php composer.phar install' . PHP_EOL); 'php composer.phar install' . PHP_EOL);
} }
if (class_exists('Doctrine\Common\Annotations\AnnotationRegistry')) {
Doctrine\Common\Annotations\AnnotationRegistry::registerLoader([$loader, 'loadClass']);
}
// force loading the ApiDoc annotation since the composer target-dir autoloader does not run through $loader::loadClass // force loading the ApiDoc annotation since the composer target-dir autoloader does not run through $loader::loadClass
class_exists('Nelmio\ApiDocBundle\Annotation\ApiDoc'); class_exists('Nelmio\ApiDocBundle\Attribute\ApiDoc');

View file

@ -4,29 +4,30 @@ namespace Nelmio\ApiDocBundle\Twig\Extension;
use Michelf\MarkdownExtra; use Michelf\MarkdownExtra;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class MarkdownExtension extends AbstractExtension class MarkdownExtension extends AbstractExtension
{ {
protected $markdownParser; private MarkdownExtra $markdownParser;
public function __construct() public function __construct()
{ {
$this->markdownParser = new MarkdownExtra(); $this->markdownParser = new MarkdownExtra();
} }
public function getFilters() public function getFilters(): array
{ {
return [ return [
new \Twig\TwigFilter('extra_markdown', [$this, 'markdown'], ['is_safe' => ['html']]), new TwigFilter('extra_markdown', [$this, 'markdown'], ['is_safe' => ['html']]),
]; ];
} }
public function getName() public function getName(): string
{ {
return 'nelmio_api_doc'; return 'nelmio_api_doc';
} }
public function markdown($text) public function markdown($text): string
{ {
return $this->markdownParser->transform($text); return $this->markdownParser->transform($text);
} }

View file

@ -25,7 +25,6 @@
"require-dev": { "require-dev": {
"doctrine/annotations": "^1.0", "doctrine/annotations": "^1.0",
"friendsofphp/php-cs-fixer": "^3", "friendsofphp/php-cs-fixer": "^3",
"friendsofsymfony/rest-bundle": "^3.7",
"jms/serializer": "^3.15", "jms/serializer": "^3.15",
"jms/serializer-bundle": "^4.1|^5.4", "jms/serializer-bundle": "^4.1|^5.4",
"phpunit/phpunit": "~9.5", "phpunit/phpunit": "~9.5",
@ -45,8 +44,6 @@
"suggest": { "suggest": {
"symfony/form": "For using form definitions as input.", "symfony/form": "For using form definitions as input.",
"symfony/validator": "For making use of validator information in the doc.", "symfony/validator": "For making use of validator information in the doc.",
"friendsofsymfony/rest-bundle": "For making use of REST information in the doc.",
"dunglas/api-bundle": "For making use of resources definitions of DunglasApiBundle.",
"jms/serializer": "For making use of serializer information in the doc." "jms/serializer": "For making use of serializer information in the doc."
}, },
"autoload": { "autoload": {