mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 15:51:48 +03:00
Refactoring
Move logic to extract data in the Extractor Remove logic in the AbstractFormatter Use ApiDoc class as data container Update tests Add test to prove the bug with FOSRestBundle annotations (\\d+ instead of \d+)
This commit is contained in:
parent
8f3327b376
commit
cca97cf6af
@ -11,6 +11,8 @@
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Annotation;
|
||||
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
@ -41,6 +43,31 @@ class ApiDoc
|
||||
*/
|
||||
private $isResource = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $requirements = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $method;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $uri;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $parameters = array();
|
||||
|
||||
/**
|
||||
* @var Route
|
||||
*/
|
||||
private $route;
|
||||
|
||||
public function __construct(array $data)
|
||||
{
|
||||
if (isset($data['formType'])) {
|
||||
@ -65,14 +92,6 @@ class ApiDoc
|
||||
$this->isResource = isset($data['resource']) && $data['resource'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $filter
|
||||
@ -82,6 +101,23 @@ class ApiDoc
|
||||
$this->filters[$name] = $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $requirement
|
||||
*/
|
||||
public function addRequirement($name, array $requirement)
|
||||
{
|
||||
$this->requirements[$name] = $requirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $requirements
|
||||
*/
|
||||
public function setRequirements(array $requirements)
|
||||
{
|
||||
$this->requirements = array_merge($this->requirements, $requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
@ -91,7 +127,7 @@ class ApiDoc
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
@ -106,14 +142,6 @@ class ApiDoc
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDocumentation()
|
||||
{
|
||||
return $this->documentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $documentation
|
||||
*/
|
||||
@ -129,4 +157,77 @@ class ApiDoc
|
||||
{
|
||||
return $this->isResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string $method
|
||||
*/
|
||||
public function setMethod($method)
|
||||
{
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string $uri
|
||||
*/
|
||||
public function setUri($uri)
|
||||
{
|
||||
$this->uri = $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
*/
|
||||
public function setParameters(array $parameters)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Route $route
|
||||
*/
|
||||
public function setRoute(Route $route)
|
||||
{
|
||||
$this->route = $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Route
|
||||
*/
|
||||
public function getRoute()
|
||||
{
|
||||
return $this->route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$data = array(
|
||||
'method' => $this->method,
|
||||
'uri' => $this->uri,
|
||||
);
|
||||
|
||||
if ($description = $this->description) {
|
||||
$data['description'] = $description;
|
||||
}
|
||||
|
||||
if ($documentation = $this->documentation) {
|
||||
$data['documentation'] = $documentation;
|
||||
}
|
||||
|
||||
if ($filters = $this->filters) {
|
||||
$data['filters'] = $filters;
|
||||
}
|
||||
|
||||
if ($parameters = $this->parameters) {
|
||||
$data['parameters'] = $parameters;
|
||||
}
|
||||
|
||||
if ($requirements = $this->requirements) {
|
||||
$data['requirements'] = $requirements;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ class RequestListener
|
||||
$controller = $request->attributes->get('_controller');
|
||||
$route = $request->attributes->get('_route');
|
||||
|
||||
if (null !== $array = $this->extractor->get($controller, $route)) {
|
||||
$result = $this->formatter->formatOne($array['annotation'], $array['route']);
|
||||
if (null !== $annotation = $this->extractor->get($controller, $route)) {
|
||||
$result = $this->formatter->formatOne($annotation);
|
||||
|
||||
$event->setResponse(new Response($result, 200, array(
|
||||
'Content-Type' => 'text/html'
|
||||
|
@ -13,6 +13,7 @@ namespace Nelmio\ApiDocBundle\Extractor;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Nelmio\ApiDocBundle\Parser\FormTypeParser;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
@ -39,17 +40,22 @@ class ApiDocExtractor
|
||||
*/
|
||||
private $reader;
|
||||
|
||||
public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader)
|
||||
/**
|
||||
* @var \Nelmio\ApiDocBundle\Parser\FormTypeParser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, FormTypeParser $parser)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->router = $router;
|
||||
$this->reader = $reader;
|
||||
$this->router = $router;
|
||||
$this->reader = $reader;
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of data where each data is an array with the following keys:
|
||||
* - annotation
|
||||
* - route
|
||||
* - resource
|
||||
*
|
||||
* @return array
|
||||
@ -61,12 +67,12 @@ class ApiDocExtractor
|
||||
|
||||
foreach ($this->router->getRouteCollection()->all() as $route) {
|
||||
if ($method = $this->getReflectionMethod($route->getDefault('_controller'))) {
|
||||
if ($annot = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS)) {
|
||||
if ($annot->isResource()) {
|
||||
if ($annotation = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS)) {
|
||||
if ($annotation->isResource()) {
|
||||
$resources[] = $route->getPattern();
|
||||
}
|
||||
|
||||
$array[] = $this->parseAnnotations($annot, $method, $route);
|
||||
$array[] = array('annotation' => $this->extractData($annotation, $route, $method));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,7 +80,7 @@ class ApiDocExtractor
|
||||
rsort($resources);
|
||||
foreach ($array as $index => $element) {
|
||||
$hasResource = false;
|
||||
$pattern = $element['route']->getPattern();
|
||||
$pattern = $element['annotation']->getRoute()->getPattern();
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
if (0 === strpos($pattern, $resource)) {
|
||||
@ -91,31 +97,38 @@ class ApiDocExtractor
|
||||
}
|
||||
|
||||
$methodOrder = array('GET', 'POST', 'PUT', 'DELETE');
|
||||
|
||||
usort($array, function($a, $b) use ($methodOrder) {
|
||||
if ($a['resource'] === $b['resource']) {
|
||||
if ($a['route']->getPattern() === $b['route']->getPattern()) {
|
||||
$methodA = array_search($a['route']->getRequirement('_method'), $methodOrder);
|
||||
$methodB = array_search($b['route']->getRequirement('_method'), $methodOrder);
|
||||
if ($a['annotation']->getRoute()->getPattern() === $b['annotation']->getRoute()->getPattern()) {
|
||||
$methodA = array_search($a['annotation']->getRoute()->getRequirement('_method'), $methodOrder);
|
||||
$methodB = array_search($b['annotation']->getRoute()->getRequirement('_method'), $methodOrder);
|
||||
|
||||
if ($methodA === $methodB) {
|
||||
return strcmp($a['route']->getRequirement('_method'), $b['route']->getRequirement('_method'));
|
||||
return strcmp(
|
||||
$a['annotation']->getRoute()->getRequirement('_method'),
|
||||
$b['annotation']->getRoute()->getRequirement('_method')
|
||||
);
|
||||
}
|
||||
|
||||
return $methodA > $methodB ? 1 : -1;
|
||||
}
|
||||
|
||||
return strcmp($a['route']->getPattern(), $b['route']->getPattern());
|
||||
return strcmp(
|
||||
$a['annotation']->getRoute()->getPattern(),
|
||||
$b['annotation']->getRoute()->getPattern()
|
||||
);
|
||||
}
|
||||
|
||||
return strcmp($a['resource'], $b['resource']);
|
||||
});
|
||||
|
||||
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ReflectionMethod for the given controller string
|
||||
* Returns the ReflectionMethod for the given controller string.
|
||||
*
|
||||
* @param string $controller
|
||||
* @return \ReflectionMethod|null
|
||||
@ -130,7 +143,7 @@ class ApiDocExtractor
|
||||
$method = $matches[2];
|
||||
if ($this->container->has($controller)) {
|
||||
$this->container->enterScope('request');
|
||||
$this->container->set('request', new Request);
|
||||
$this->container->set('request', new Request());
|
||||
$class = get_class($this->container->get($controller));
|
||||
$this->container->leaveScope('request');
|
||||
}
|
||||
@ -147,20 +160,18 @@ class ApiDocExtractor
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing two values with the following keys:
|
||||
* - annotation
|
||||
* - route
|
||||
* Returns an ApiDoc annotation.
|
||||
*
|
||||
* @param string $controller
|
||||
* @param Route $route
|
||||
* @return array|null
|
||||
* @return ApiDoc|null
|
||||
*/
|
||||
public function get($controller, $route)
|
||||
{
|
||||
if ($method = $this->getReflectionMethod($controller)) {
|
||||
if ($annot = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS)) {
|
||||
if ($annotation = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS)) {
|
||||
if ($route = $this->router->getRouteCollection()->get($route)) {
|
||||
return $this->parseAnnotations($annot, $method, $route);
|
||||
return $this->extractData($annotation, $route, $method);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,45 +179,26 @@ class ApiDocExtractor
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function parseAnnotations($annotation, $method, $route)
|
||||
{
|
||||
$data = $this->getData($annotation, $route, $method);
|
||||
|
||||
foreach ($this->reader->getMethodAnnotations($method) as $annot) {
|
||||
if (is_subclass_of($annot, self::FOS_REST_PARAM_CLASS)) {
|
||||
if ($annot->strict) {
|
||||
$data['requirements'][$annot->name] = array(
|
||||
'requirement' => $annot->requirements,
|
||||
'type' => '',
|
||||
'description' => $annot->description,
|
||||
);
|
||||
} else {
|
||||
$data['annotation']->addFilter($annot->name, array(
|
||||
'requirement' => $annot->requirements,
|
||||
'description' => $annot->description,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to add more data to the ApiDoc object, and
|
||||
* returns an array containing the following keys:
|
||||
* - annotation
|
||||
* - route
|
||||
* Returns a new ApiDoc instance with more data.
|
||||
*
|
||||
* @param ApiDoc $annotation
|
||||
* @param Route $route
|
||||
* @param \ReflectionMethod $method
|
||||
* @return array
|
||||
* @return ApiDoc
|
||||
*/
|
||||
protected function getData(ApiDoc $annotation, Route $route, \ReflectionMethod $method)
|
||||
protected function extractData(ApiDoc $annotation, Route $route, \ReflectionMethod $method)
|
||||
{
|
||||
$docblock = $this->getDocComment($method);
|
||||
// create a new annotation
|
||||
$annotation = clone $annotation;
|
||||
|
||||
// parse annotations
|
||||
$this->parseAnnotations($annotation, $route, $method);
|
||||
|
||||
// route
|
||||
$annotation->setRoute($route);
|
||||
|
||||
// description
|
||||
if (null === $annotation->getDescription()) {
|
||||
$comments = explode("\n", $this->getDocCommentText($method));
|
||||
// just set the first line
|
||||
@ -220,20 +212,77 @@ class ApiDocExtractor
|
||||
}
|
||||
}
|
||||
|
||||
// doc
|
||||
$annotation->setDocumentation($this->getDocCommentText($method));
|
||||
|
||||
// formType
|
||||
if (null !== $formType = $annotation->getFormType()) {
|
||||
$parameters = $this->parser->parse($formType);
|
||||
|
||||
if ('PUT' === $method) {
|
||||
// All parameters are optional with PUT (update)
|
||||
array_walk($parameters, function($val, $key) use (&$data) {
|
||||
$parameters[$key]['required'] = false;
|
||||
});
|
||||
}
|
||||
|
||||
$annotation->setParameters($parameters);
|
||||
}
|
||||
|
||||
// requirements
|
||||
$requirements = array();
|
||||
foreach ($route->compile()->getRequirements() as $name => $value) {
|
||||
if ('_method' !== $name) {
|
||||
$requirements[$name] = array(
|
||||
'requirement' => $value,
|
||||
'type' => '',
|
||||
'description' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$paramDocs = array();
|
||||
foreach (explode("\n", $docblock) as $line) {
|
||||
foreach (explode("\n", $this->getDocComment($method)) as $line) {
|
||||
if (preg_match('{^@param (.+)}', trim($line), $matches)) {
|
||||
$paramDocs[] = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
$route->setOptions(array_merge($route->getOptions(), array('_paramDocs' => $paramDocs)));
|
||||
$regexp = '{(\w*) *\$%s *(.*)}i';
|
||||
foreach ($route->compile()->getVariables() as $var) {
|
||||
$found = false;
|
||||
foreach ($paramDocs as $paramDoc) {
|
||||
if (preg_match(sprintf($regexp, preg_quote($var)), $paramDoc, $matches)) {
|
||||
$requirements[$var]['type'] = isset($matches[1]) ? $matches[1] : '';
|
||||
$requirements[$var]['description'] = $matches[2];
|
||||
|
||||
return array('annotation' => $annotation, 'route' => $route, 'requirements' => array());
|
||||
if (!isset($requirements[$var]['requirement'])) {
|
||||
$requirements[$var]['requirement'] = '';
|
||||
}
|
||||
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($requirements[$var]) && false === $found) {
|
||||
$requirements[$var] = array('requirement' => '', 'type' => '', 'description' => '');
|
||||
}
|
||||
}
|
||||
|
||||
$annotation->setRequirements($requirements);
|
||||
|
||||
// method/uri
|
||||
$annotation->setMethod($route->getRequirement('_method') ?: 'ANY');
|
||||
$annotation->setUri($route->compile()->getPattern());
|
||||
|
||||
return $annotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Reflector $reflected
|
||||
* @return string
|
||||
*/
|
||||
protected function getDocComment(\Reflector $reflected)
|
||||
{
|
||||
$comment = $reflected->getDocComment();
|
||||
@ -250,6 +299,10 @@ class ApiDocExtractor
|
||||
return $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Reflector $reflected
|
||||
* @return string
|
||||
*/
|
||||
protected function getDocCommentText(\Reflector $reflected)
|
||||
{
|
||||
$comment = $reflected->getDocComment();
|
||||
@ -264,4 +317,32 @@ class ApiDocExtractor
|
||||
|
||||
return trim($comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses annotations for a given method, and adds new information to the given ApiDoc
|
||||
* annotation. Useful to extract information from the FOSRestBundle annotations.
|
||||
*
|
||||
* @param ApiDoc $annotation
|
||||
* @param Route $route
|
||||
* @param ReflectionMethod $method
|
||||
*/
|
||||
protected function parseAnnotations(ApiDoc $annotation, Route $route, \ReflectionMethod $method)
|
||||
{
|
||||
foreach ($this->reader->getMethodAnnotations($method) as $annot) {
|
||||
if (is_subclass_of($annot, self::FOS_REST_PARAM_CLASS)) {
|
||||
if ($annot->strict) {
|
||||
$annotation->addRequirement($annot->name, array(
|
||||
'requirement' => $annot->requirements,
|
||||
'type' => '',
|
||||
'description' => $annot->description,
|
||||
));
|
||||
} else {
|
||||
$annotation->addFilter($annot->name, array(
|
||||
'requirement' => $annot->requirements,
|
||||
'description' => $annot->description,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,27 +12,15 @@
|
||||
namespace Nelmio\ApiDocBundle\Formatter;
|
||||
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Nelmio\ApiDocBundle\Parser\FormTypeParser;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
abstract class AbstractFormatter implements FormatterInterface
|
||||
{
|
||||
/**
|
||||
* @var \Nelmio\ApiDocBundle\Parser\FormTypeParser
|
||||
*/
|
||||
protected $parser;
|
||||
|
||||
public function __construct(FormTypeParser $parser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatOne(ApiDoc $apiDoc, Route $route)
|
||||
public function formatOne(ApiDoc $annotation)
|
||||
{
|
||||
return $this->renderOne($this->getData($apiDoc, $route));
|
||||
return $this->renderOne($annotation->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,12 +30,7 @@ abstract class AbstractFormatter implements FormatterInterface
|
||||
{
|
||||
$array = array();
|
||||
foreach ($collection as $coll) {
|
||||
$resource = $coll['resource'];
|
||||
if (!isset($array[$resource])) {
|
||||
$array[$resource] = array();
|
||||
}
|
||||
|
||||
$array[$resource][] = $this->getData($coll['annotation'], $coll['route'], $coll['requirements']);
|
||||
$array[$coll['resource']][] = $coll['annotation']->toArray();
|
||||
}
|
||||
|
||||
return $this->render($array);
|
||||
@ -68,80 +51,4 @@ abstract class AbstractFormatter implements FormatterInterface
|
||||
* @return string|array
|
||||
*/
|
||||
abstract protected function render(array $collection);
|
||||
|
||||
/**
|
||||
* @param ApiDoc $apiDoc
|
||||
* @param Route $route
|
||||
* @param array $requirements
|
||||
* @return array
|
||||
*/
|
||||
protected function getData(ApiDoc $apiDoc, Route $route, array $requirements = array())
|
||||
{
|
||||
$method = $route->getRequirement('_method');
|
||||
$data = array(
|
||||
'method' => $method ?: 'ANY',
|
||||
'uri' => $route->compile()->getPattern(),
|
||||
);
|
||||
|
||||
foreach ($route->compile()->getRequirements() as $name => $value) {
|
||||
if ('_method' !== $name) {
|
||||
$requirements[$name] = array(
|
||||
'requirement' => $value,
|
||||
'type' => '',
|
||||
'description' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $paramDocs = $route->getOption('_paramDocs')) {
|
||||
$regexp = '{(\w*) *\$%s *(.*)}i';
|
||||
foreach ($route->compile()->getVariables() as $var) {
|
||||
$found = false;
|
||||
foreach ($paramDocs as $paramDoc) {
|
||||
if (preg_match(sprintf($regexp, preg_quote($var)), $paramDoc, $matches)) {
|
||||
$requirements[$var]['type'] = isset($matches[1]) ? $matches[1] : '';
|
||||
$requirements[$var]['description'] = $matches[2];
|
||||
|
||||
if (!isset($requirements[$var]['requirement'])) {
|
||||
$requirements[$var]['requirement'] = '';
|
||||
}
|
||||
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($requirements[$var]) && false === $found) {
|
||||
$requirements[$var] = array('requirement' => '', 'type' => '', 'description' => '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data['requirements'] = $requirements;
|
||||
|
||||
if (null !== $formType = $apiDoc->getFormType()) {
|
||||
$data['parameters'] = $this->parser->parse($formType);
|
||||
|
||||
if ('PUT' === $method) {
|
||||
// All parameters are optional with PUT (update)
|
||||
array_walk($data['parameters'], function($val, $key) use (&$data) {
|
||||
$data['parameters'][$key]['required'] = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ($filters = $apiDoc->getFilters()) {
|
||||
$data['filters'] = $filters;
|
||||
}
|
||||
|
||||
if ($description = $apiDoc->getDescription()) {
|
||||
$data['description'] = $description;
|
||||
}
|
||||
|
||||
if ($documentation = $apiDoc->getDocumentation()) {
|
||||
$data['documentation'] = $documentation;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace Nelmio\ApiDocBundle\Formatter;
|
||||
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
interface FormatterInterface
|
||||
{
|
||||
@ -27,9 +26,8 @@ interface FormatterInterface
|
||||
/**
|
||||
* Format documentation data for one route.
|
||||
*
|
||||
* @param ApiDoc $apiDoc
|
||||
* @param Route $route
|
||||
* @param ApiDoc $annotation
|
||||
* return string|array
|
||||
*/
|
||||
public function formatOne(ApiDoc $apiDoc, Route $route);
|
||||
public function formatOne(ApiDoc $annotation);
|
||||
}
|
||||
|
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2011 Nelmio
|
||||
Copyright (c) 2012 Nelmio
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -15,9 +15,7 @@
|
||||
<service id="nelmio_api_doc.parser.form_type_parser" class="%nelmio_api_doc.parser.form_type_parser.class%">
|
||||
<argument type="service" id="form.factory" />
|
||||
</service>
|
||||
<service id="nelmio_api_doc.formatter.abstract_formatter" class="%nelmio_api_doc.formatter.abstract_formatter.class%">
|
||||
<argument type="service" id="nelmio_api_doc.parser.form_type_parser" />
|
||||
</service>
|
||||
<service id="nelmio_api_doc.formatter.abstract_formatter" class="%nelmio_api_doc.formatter.abstract_formatter.class%" />
|
||||
<service id="nelmio_api_doc.formatter.markdown_formatter" class="%nelmio_api_doc.formatter.markdown_formatter.class%"
|
||||
parent="nelmio_api_doc.formatter.abstract_formatter" />
|
||||
<service id="nelmio_api_doc.formatter.simple_formatter" class="%nelmio_api_doc.formatter.simple_formatter.class%"
|
||||
|
@ -13,6 +13,7 @@
|
||||
<argument type="service" id="service_container"/>
|
||||
<argument type="service" id="router" />
|
||||
<argument type="service" id="annotation_reader" />
|
||||
<argument type="service" id="nelmio_api_doc.parser.form_type_parser" />
|
||||
</service>
|
||||
<service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%">
|
||||
<tag name="form.type_extension" alias="form" />
|
||||
|
@ -21,11 +21,12 @@ class ApiDocTest extends TestCase
|
||||
$data = array();
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(0, $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertFalse(isset($array['filters']));
|
||||
$this->assertFalse($annot->isResource());
|
||||
$this->assertNull($annot->getDescription());
|
||||
$this->assertFalse(isset($array['description']));
|
||||
$this->assertNull($annot->getFormType());
|
||||
}
|
||||
|
||||
@ -37,11 +38,12 @@ class ApiDocTest extends TestCase
|
||||
);
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(0, $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertFalse(isset($array['filters']));
|
||||
$this->assertFalse($annot->isResource());
|
||||
$this->assertNull($annot->getDescription());
|
||||
$this->assertFalse(isset($array['description']));
|
||||
$this->assertNull($annot->getFormType());
|
||||
}
|
||||
|
||||
@ -52,11 +54,12 @@ class ApiDocTest extends TestCase
|
||||
);
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(0, $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertFalse(isset($array['filters']));
|
||||
$this->assertFalse($annot->isResource());
|
||||
$this->assertEquals($data['description'], $annot->getDescription());
|
||||
$this->assertEquals($data['description'], $array['description']);
|
||||
$this->assertNull($annot->getFormType());
|
||||
}
|
||||
|
||||
@ -68,11 +71,12 @@ class ApiDocTest extends TestCase
|
||||
);
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(0, $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertFalse(isset($array['filters']));
|
||||
$this->assertFalse($annot->isResource());
|
||||
$this->assertEquals($data['description'], $annot->getDescription());
|
||||
$this->assertEquals($data['description'], $array['description']);
|
||||
$this->assertEquals($data['formType'], $annot->getFormType());
|
||||
}
|
||||
|
||||
@ -85,11 +89,12 @@ class ApiDocTest extends TestCase
|
||||
);
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(0, $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertFalse(isset($array['filters']));
|
||||
$this->assertTrue($annot->isResource());
|
||||
$this->assertEquals($data['description'], $annot->getDescription());
|
||||
$this->assertEquals($data['description'], $array['description']);
|
||||
$this->assertEquals($data['formType'], $annot->getFormType());
|
||||
}
|
||||
|
||||
@ -102,11 +107,12 @@ class ApiDocTest extends TestCase
|
||||
);
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(0, $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertFalse(isset($array['filters']));
|
||||
$this->assertFalse($annot->isResource());
|
||||
$this->assertEquals($data['description'], $annot->getDescription());
|
||||
$this->assertEquals($data['description'], $array['description']);
|
||||
$this->assertEquals($data['formType'], $annot->getFormType());
|
||||
}
|
||||
|
||||
@ -121,12 +127,14 @@ class ApiDocTest extends TestCase
|
||||
);
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(1, $annot->getFilters());
|
||||
$this->assertEquals(array('a-filter' => array()), $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertTrue(is_array($array['filters']));
|
||||
$this->assertCount(1, $array['filters']);
|
||||
$this->assertEquals(array('a-filter' => array()), $array['filters']);
|
||||
$this->assertTrue($annot->isResource());
|
||||
$this->assertEquals($data['description'], $annot->getDescription());
|
||||
$this->assertEquals($data['description'], $array['description']);
|
||||
$this->assertNull($annot->getFormType());
|
||||
}
|
||||
|
||||
@ -157,12 +165,12 @@ class ApiDocTest extends TestCase
|
||||
);
|
||||
|
||||
$annot = new ApiDoc($data);
|
||||
$array = $annot->toArray();
|
||||
|
||||
$this->assertTrue(is_array($annot->getFilters()));
|
||||
$this->assertCount(0, $annot->getFilters());
|
||||
$this->assertEquals(array(), $annot->getFilters());
|
||||
$this->assertTrue(is_array($array));
|
||||
$this->assertFalse(isset($array['filters']));
|
||||
$this->assertTrue($annot->isResource());
|
||||
$this->assertEquals($data['description'], $annot->getDescription());
|
||||
$this->assertEquals($data['description'], $array['description']);
|
||||
$this->assertEquals($data['formType'], $annot->getFormType());
|
||||
}
|
||||
}
|
||||
|
@ -22,62 +22,67 @@ class ApiDocExtractorTest extends WebTestCase
|
||||
$data = $extractor->all();
|
||||
|
||||
$this->assertTrue(is_array($data));
|
||||
$this->assertCount(9, $data);
|
||||
$this->assertCount(10, $data);
|
||||
|
||||
foreach ($data as $d) {
|
||||
$this->assertTrue(is_array($d));
|
||||
$this->assertArrayHasKey('annotation', $d);
|
||||
$this->assertArrayHasKey('route', $d);
|
||||
$this->assertArrayHasKey('resource', $d);
|
||||
|
||||
$this->assertInstanceOf('Nelmio\ApiDocBundle\Annotation\ApiDoc', $d['annotation']);
|
||||
$this->assertInstanceOf('Symfony\Component\Routing\Route', $d['route']);
|
||||
$this->assertInstanceOf('Symfony\Component\Routing\Route', $d['annotation']->getRoute());
|
||||
$this->assertNotNull($d['resource']);
|
||||
}
|
||||
|
||||
$a1 = $data[0]['annotation'];
|
||||
$array1 = $a1->toArray();
|
||||
$this->assertTrue($a1->isResource());
|
||||
$this->assertEquals('index action', $a1->getDescription());
|
||||
$this->assertTrue(is_array($a1->getFilters()));
|
||||
$this->assertTrue(is_array($array1['filters']));
|
||||
$this->assertNull($a1->getFormType());
|
||||
|
||||
$a1 = $data[1]['annotation'];
|
||||
$array1 = $a1->toArray();
|
||||
$this->assertTrue($a1->isResource());
|
||||
$this->assertEquals('index action', $a1->getDescription());
|
||||
$this->assertTrue(is_array($a1->getFilters()));
|
||||
$this->assertTrue(is_array($array1['filters']));
|
||||
$this->assertNull($a1->getFormType());
|
||||
|
||||
$a2 = $data[2]['annotation'];
|
||||
$array2 = $a2->toArray();
|
||||
$this->assertFalse($a2->isResource());
|
||||
$this->assertEquals('create test', $a2->getDescription());
|
||||
$this->assertTrue(is_array($a2->getFilters()));
|
||||
$this->assertFalse(isset($array2['filters']));
|
||||
$this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getFormType());
|
||||
|
||||
$a2 = $data[3]['annotation'];
|
||||
$array2 = $a2->toArray();
|
||||
$this->assertFalse($a2->isResource());
|
||||
$this->assertEquals('create test', $a2->getDescription());
|
||||
$this->assertTrue(is_array($a2->getFilters()));
|
||||
$this->assertFalse(isset($array2['filters']));
|
||||
$this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getFormType());
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$data = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1');
|
||||
$container = $this->getContainer();
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1');
|
||||
|
||||
$this->assertTrue(isset($data['route']));
|
||||
$this->assertTrue(isset($data['annotation']));
|
||||
$this->assertInstanceOf('Nelmio\ApiDocBundle\Annotation\ApiDoc', $annotation);
|
||||
|
||||
$a = $data['annotation'];
|
||||
$this->assertTrue($a->isResource());
|
||||
$this->assertEquals('index action', $a->getDescription());
|
||||
$this->assertTrue(is_array($a->getFilters()));
|
||||
$this->assertNull($a->getFormType());
|
||||
$this->assertTrue($annotation->isResource());
|
||||
$this->assertEquals('index action', $annotation->getDescription());
|
||||
|
||||
$data2 = $extractor->get('nemlio.test.controller:indexAction', 'test_service_route_1');
|
||||
$data2['route']->setDefault('_controller', $data['route']->getDefault('_controller'));
|
||||
$this->assertEquals($data, $data2);
|
||||
$array = $annotation->toArray();
|
||||
$this->assertTrue(is_array($array['filters']));
|
||||
$this->assertNull($annotation->getFormType());
|
||||
|
||||
$annotation2 = $extractor->get('nemlio.test.controller:indexAction', 'test_service_route_1');
|
||||
$annotation2->getRoute()
|
||||
->setDefault('_controller', $annotation->getRoute()->getDefault('_controller'))
|
||||
->compile(); // compile as we changed a default value
|
||||
$this->assertEquals($annotation, $annotation2);
|
||||
}
|
||||
|
||||
public function testGetWithBadController()
|
||||
@ -134,14 +139,14 @@ class ApiDocExtractorTest extends WebTestCase
|
||||
|
||||
public function testGetWithDocComment()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$data = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::myCommentedAction', 'test_route_5');
|
||||
$container = $this->getContainer();
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::myCommentedAction', 'test_route_5');
|
||||
|
||||
$this->assertNotNull($data);
|
||||
$this->assertNotNull($annotation);
|
||||
$this->assertEquals(
|
||||
"This method is useful to test if the getDocComment works.",
|
||||
$data['annotation']->getDescription()
|
||||
$annotation->getDescription()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Controller;
|
||||
|
||||
use FOS\RestBundle\Controller\Annotations\QueryParam;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
@ -81,4 +82,12 @@ class TestController
|
||||
public function anotherPostAction()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @ApiDoc()
|
||||
* @QueryParam(name="page", requirements="\d+", default="1", description="Page of the overview.")
|
||||
*/
|
||||
public function zActionWithQueryParamAction()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,12 @@ test_route_7:
|
||||
requirements:
|
||||
_method: POST
|
||||
|
||||
test_route_8:
|
||||
pattern: /z-action-with-query-param
|
||||
defaults: { _controller: NelmioApiDocTestBundle:Test:zActionWithQueryParam }
|
||||
requirements:
|
||||
_method: GET
|
||||
|
||||
test_service_route_1:
|
||||
pattern: /tests
|
||||
defaults: { _controller: nemlio.test.controller:indexAction, _format: json }
|
||||
|
@ -158,6 +158,17 @@ _This method is useful to test if the getDocComment works._
|
||||
**id**
|
||||
|
||||
- Requirement: \d+
|
||||
|
||||
|
||||
### `GET` /z-action-with-query-param ###
|
||||
|
||||
|
||||
#### Filters ####
|
||||
|
||||
page:
|
||||
|
||||
* requirement: \d+
|
||||
* description: Page of the overview.
|
||||
MARKDOWN;
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
@ -167,9 +178,9 @@ MARKDOWN;
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$data = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1');
|
||||
$result = $container->get('nelmio_api_doc.formatter.markdown_formatter')->formatOne($data['annotation'], $data['route']);
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1');
|
||||
$result = $container->get('nelmio_api_doc.formatter.markdown_formatter')->formatOne($annotation);
|
||||
|
||||
$expected = <<<MARKDOWN
|
||||
### `GET` /tests ###
|
||||
|
@ -30,9 +30,6 @@ class SimpleFormatterTest extends WebTestCase
|
||||
array(
|
||||
'method' => 'GET',
|
||||
'uri' => '/tests',
|
||||
'requirements' =>
|
||||
array(
|
||||
),
|
||||
'filters' =>
|
||||
array(
|
||||
'a' =>
|
||||
@ -55,9 +52,6 @@ class SimpleFormatterTest extends WebTestCase
|
||||
array(
|
||||
'method' => 'GET',
|
||||
'uri' => '/tests',
|
||||
'requirements' =>
|
||||
array(
|
||||
),
|
||||
'filters' =>
|
||||
array(
|
||||
'a' =>
|
||||
@ -80,9 +74,6 @@ class SimpleFormatterTest extends WebTestCase
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'uri' => '/tests',
|
||||
'requirements' =>
|
||||
array(
|
||||
),
|
||||
'parameters' =>
|
||||
array(
|
||||
'a' =>
|
||||
@ -110,9 +101,6 @@ class SimpleFormatterTest extends WebTestCase
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'uri' => '/tests',
|
||||
'requirements' =>
|
||||
array(
|
||||
),
|
||||
'parameters' =>
|
||||
array(
|
||||
'a' =>
|
||||
@ -143,9 +131,6 @@ class SimpleFormatterTest extends WebTestCase
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'uri' => '/another-post',
|
||||
'requirements' =>
|
||||
array(
|
||||
),
|
||||
'parameters' =>
|
||||
array(
|
||||
'a' =>
|
||||
@ -161,9 +146,6 @@ class SimpleFormatterTest extends WebTestCase
|
||||
array(
|
||||
'method' => 'ANY',
|
||||
'uri' => '/any',
|
||||
'requirements' =>
|
||||
array(
|
||||
),
|
||||
'description' => 'Action without HTTP verb',
|
||||
),
|
||||
2 =>
|
||||
@ -197,6 +179,15 @@ class SimpleFormatterTest extends WebTestCase
|
||||
'id' => array('type' => '', 'description' => '', 'requirement' => '\d+')
|
||||
),
|
||||
),
|
||||
5 =>
|
||||
array(
|
||||
'method' => 'GET',
|
||||
'uri' => '/z-action-with-query-param',
|
||||
'filters' =>
|
||||
array(
|
||||
'page' => array('description' => 'Page of the overview.', 'requirement' => '\d+')
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -207,14 +198,13 @@ class SimpleFormatterTest extends WebTestCase
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$data = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1');
|
||||
$result = $container->get('nelmio_api_doc.formatter.simple_formatter')->formatOne($data['annotation'], $data['route']);
|
||||
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$annotation = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'test_route_1');
|
||||
$result = $container->get('nelmio_api_doc.formatter.simple_formatter')->formatOne($annotation);
|
||||
|
||||
$expected = array(
|
||||
'method' => 'GET',
|
||||
'uri' => '/tests',
|
||||
'requirements' => array(),
|
||||
'filters' => array(
|
||||
'a' => array(
|
||||
'dataType' => 'integer',
|
||||
|
Loading…
x
Reference in New Issue
Block a user