mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 23:59:26 +03:00
Merge pull request #973 from nelmio/FILTERED_COLLECTION
[3.0] Get ride of Swagger-Php parser
This commit is contained in:
commit
1b7eb1c69c
21
Annotation/Operation.php
Normal file
21
Annotation/Operation.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Annotation;
|
||||
|
||||
use Swagger\Annotations\Operation as BaseOperation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Operation extends BaseOperation
|
||||
{
|
||||
}
|
@ -13,11 +13,10 @@ namespace Nelmio\ApiDocBundle\DependencyInjection;
|
||||
|
||||
use FOS\RestBundle\Controller\Annotations\ParamInterface;
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use Swagger\Annotations\Swagger;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
|
||||
final class NelmioApiDocExtension extends Extension implements PrependExtensionInterface
|
||||
@ -41,7 +40,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
||||
$loader->load('services.xml');
|
||||
|
||||
// Filter routes
|
||||
$routeCollectionBuilder = $container->getDefinition('nelmio_api_doc.describers.route.filtered_route_collection_builder');
|
||||
$routeCollectionBuilder = $container->getDefinition('nelmio_api_doc.filtered_route_collection_builder');
|
||||
$routeCollectionBuilder->replaceArgument(0, $config['routes']['path_patterns']);
|
||||
|
||||
// Import services needed for each library
|
||||
|
@ -11,13 +11,15 @@
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Describer;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use Nelmio\ApiDocBundle\SwaggerPhp\AddDefaults;
|
||||
use Nelmio\ApiDocBundle\SwaggerPhp\ModelRegister;
|
||||
use Nelmio\ApiDocBundle\SwaggerPhp\OperationResolver;
|
||||
use Nelmio\ApiDocBundle\Util\ControllerReflector;
|
||||
use Swagger\Analyser;
|
||||
use Swagger\Analysis;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Swagger\Context;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelRegistryAwareInterface
|
||||
@ -26,57 +28,138 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg
|
||||
|
||||
private $routeCollection;
|
||||
private $controllerReflector;
|
||||
private $annotationReader;
|
||||
|
||||
public function __construct(RouteCollection $routeCollection, ControllerReflector $controllerReflector, bool $overwrite = false)
|
||||
public function __construct(RouteCollection $routeCollection, ControllerReflector $controllerReflector, Reader $annotationReader, bool $overwrite = false)
|
||||
{
|
||||
$this->routeCollection = $routeCollection;
|
||||
$this->controllerReflector = $controllerReflector;
|
||||
$this->annotationReader = $annotationReader;
|
||||
|
||||
parent::__construct(function () {
|
||||
$whitelist = Analyser::$whitelist;
|
||||
Analyser::$whitelist = false;
|
||||
try {
|
||||
$options = ['processors' => $this->getProcessors()];
|
||||
$annotation = \Swagger\scan($this->getFinder(), $options);
|
||||
$analysis = $this->getAnnotations();
|
||||
|
||||
return json_decode(json_encode($annotation));
|
||||
} finally {
|
||||
Analyser::$whitelist = $whitelist;
|
||||
}
|
||||
$analysis->process($this->getProcessors());
|
||||
$analysis->validate();
|
||||
|
||||
return json_decode(json_encode($analysis->swagger));
|
||||
}, $overwrite);
|
||||
}
|
||||
|
||||
private function getFinder()
|
||||
{
|
||||
$files = [];
|
||||
foreach ($this->routeCollection->all() as $route) {
|
||||
if (!$route->hasDefault('_controller')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if able to resolve the controller
|
||||
$controller = $route->getDefault('_controller');
|
||||
if ($callable = $this->controllerReflector->getReflectionClassAndMethod($controller)) {
|
||||
list($class, $method) = $callable;
|
||||
|
||||
$files[$class->getFileName()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->append(array_keys($files));
|
||||
|
||||
return $finder;
|
||||
}
|
||||
|
||||
private function getProcessors(): array
|
||||
{
|
||||
$processors = [
|
||||
new AddDefaults(),
|
||||
new ModelRegister($this->modelRegistry),
|
||||
new OperationResolver($this->routeCollection, $this->controllerReflector),
|
||||
];
|
||||
|
||||
return array_merge($processors, Analysis::processors());
|
||||
}
|
||||
|
||||
private function getAnnotations(): Analysis
|
||||
{
|
||||
$analysis = new Analysis();
|
||||
|
||||
$operationAnnotations = [
|
||||
'get' => SWG\Get::class,
|
||||
'post' => SWG\Post::class,
|
||||
'put' => SWG\Put::class,
|
||||
'patch' => SWG\Patch::class,
|
||||
'delete' => SWG\Delete::class,
|
||||
'options' => SWG\Options::class,
|
||||
'head' => SWG\Head::class,
|
||||
];
|
||||
|
||||
foreach ($this->getMethodsToParse() as $method => list($path, $httpMethods)) {
|
||||
$annotations = array_filter($this->annotationReader->getMethodAnnotations($method), function ($v) {
|
||||
return $v instanceof SWG\AbstractAnnotation;
|
||||
});
|
||||
|
||||
if (0 === count($annotations)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$declaringClass = $method->getDeclaringClass();
|
||||
$context = new Context([
|
||||
'namespace' => $method->getNamespaceName(),
|
||||
'class' => $declaringClass->getShortName(),
|
||||
'method' => $method->name,
|
||||
'filename' => $method->getFileName(),
|
||||
]);
|
||||
$implicitAnnotations = [];
|
||||
foreach ($annotations as $annotation) {
|
||||
$annotation->_context = $context;
|
||||
|
||||
if ($annotation instanceof Operation) {
|
||||
foreach ($httpMethods as $httpMethod) {
|
||||
$annotationClass = $operationAnnotations[$httpMethod];
|
||||
$operation = new $annotationClass(['_context' => $context]);
|
||||
$operation->path = $path;
|
||||
$operation->mergeProperties($annotation);
|
||||
|
||||
$analysis->addAnnotation($operation, null);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($annotation instanceof SWG\Operation) {
|
||||
if (null === $annotation->path) {
|
||||
$annotation = clone $annotation;
|
||||
$annotation->path = $path;
|
||||
}
|
||||
|
||||
$analysis->addAnnotation($annotation, null);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$annotation instanceof SWG\Response && !$annotation instanceof SWG\Parameter && !$annotation instanceof SWG\ExternalDocumentation) {
|
||||
throw new \LogicException(sprintf('Using the annotation "%s" as a root annotation in "%s::%s()" is not allowed.', get_class($annotation), $method->getDeclaringClass()->name, $method->name));
|
||||
}
|
||||
|
||||
$implicitAnnotations[] = $annotation;
|
||||
}
|
||||
|
||||
if (0 === count($implicitAnnotations)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($httpMethods as $httpMethod) {
|
||||
$annotationClass = $operationAnnotations[$httpMethod];
|
||||
$operation = new $annotationClass(['_context' => $context, 'path' => $path, 'value' => $implicitAnnotations]);
|
||||
$analysis->addAnnotation($operation, null);
|
||||
}
|
||||
}
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
private function getMethodsToParse()
|
||||
{
|
||||
foreach ($this->routeCollection->all() as $route) {
|
||||
if (!$route->hasDefault('_controller')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$controller = $route->getDefault('_controller');
|
||||
if ($callable = $this->controllerReflector->getReflectionClassAndMethod($controller)) {
|
||||
list($class, $method) = $callable;
|
||||
$path = $this->normalizePath($route->getPath());
|
||||
$httpMethods = $route->getMethods() ?: Swagger::$METHODS;
|
||||
$httpMethods = array_map('strtolower', $httpMethods);
|
||||
|
||||
yield $method => [$path, $httpMethods];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function normalizePath(string $path)
|
||||
{
|
||||
if (substr($path, -10) === '.{_format}') {
|
||||
$path = substr($path, 0, -10);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,19 @@
|
||||
<argument type="service" id="controller_name_converter" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.filtered_route_collection" class="Symfony\Component\Routing\RouteCollection" public="false">
|
||||
<factory service="nelmio_api_doc.filtered_route_collection_builder" method="filter" />
|
||||
<argument type="service">
|
||||
<service class="Symfony\Component\Routing\RouteCollection">
|
||||
<factory service="router" method="getRouteCollection" />
|
||||
</service>
|
||||
</argument>
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.filtered_route_collection_builder" class="Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder" public="false">
|
||||
<argument type="collection" /> <!-- Path patterns -->
|
||||
</service>
|
||||
|
||||
<!-- Describers -->
|
||||
<service id="nelmio_api_doc.describers.config" class="Nelmio\ApiDocBundle\Describer\ExternalDocDescriber" public="false">
|
||||
<argument type="collection" />
|
||||
@ -21,21 +34,8 @@
|
||||
<tag name="nelmio_api_doc.describer" priority="1000" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.describers.route.filtered_route_collection_builder" class="Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder" public="false">
|
||||
<argument type="collection" /> <!-- Path patterns -->
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.describers.route" class="Nelmio\ApiDocBundle\Describer\RouteDescriber" public="false">
|
||||
<argument type="service">
|
||||
<service class="Symfony\Component\Routing\RouteCollection">
|
||||
<factory service="nelmio_api_doc.describers.route.filtered_route_collection_builder" method="filter" />
|
||||
<argument type="service">
|
||||
<service class="Symfony\Component\Routing\RouteCollection">
|
||||
<factory service="router" method="getRouteCollection" />
|
||||
</service>
|
||||
</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="nelmio_api_doc.filtered_route_collection" />
|
||||
<argument type="service" id="nelmio_api_doc.controller_reflector" />
|
||||
<argument type="collection" />
|
||||
|
||||
|
@ -5,12 +5,9 @@
|
||||
|
||||
<services>
|
||||
<service id="nelmio_api_doc.describers.swagger_php" class="Nelmio\ApiDocBundle\Describer\SwaggerPhpDescriber" public="false">
|
||||
<argument type="service">
|
||||
<service class="Symfony\Component\Routing\RouteCollection">
|
||||
<factory service="router" method="getRouteCollection" />
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="nelmio_api_doc.filtered_route_collection" />
|
||||
<argument type="service" id="nelmio_api_doc.controller_reflector" />
|
||||
<argument type="service" id="annotation_reader" />
|
||||
|
||||
<tag name="nelmio_api_doc.describer" priority="-200" />
|
||||
</service>
|
||||
|
@ -38,38 +38,51 @@ final class ModelRegister
|
||||
public function __invoke(Analysis $analysis)
|
||||
{
|
||||
foreach ($analysis->annotations as $annotation) {
|
||||
if (!$annotation instanceof ModelAnnotation || $annotation->_context->not('nested')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_string($annotation->type)) {
|
||||
// Ignore invalid annotations, they are validated later
|
||||
continue;
|
||||
}
|
||||
|
||||
$parent = $annotation->_context->nested;
|
||||
if (!$parent instanceof Response && !$parent instanceof Parameter && !$parent instanceof Schema) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$annotationClass = Schema::class;
|
||||
if ($parent instanceof Schema) {
|
||||
if ($annotation instanceof Response) {
|
||||
$annotationClass = Schema::class;
|
||||
} elseif ($annotation instanceof Parameter) {
|
||||
if ('array' === $annotation->type) {
|
||||
$annotationClass = Items::class;
|
||||
} else {
|
||||
$annotationClass = Schema::class;
|
||||
}
|
||||
} elseif ($annotation instanceof Schema) {
|
||||
$annotationClass = Items::class;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parent->merge([new $annotationClass([
|
||||
'ref' => $this->modelRegistry->register(new Model($this->createType($annotation->type))),
|
||||
])]);
|
||||
|
||||
// It is no longer an unmerged annotation
|
||||
foreach ($parent->_unmerged as $key => $unmerged) {
|
||||
if ($unmerged === $annotation) {
|
||||
unset($parent->_unmerged[$key]);
|
||||
$model = null;
|
||||
foreach ($annotation->_unmerged as $unmerged) {
|
||||
if ($unmerged instanceof ModelAnnotation) {
|
||||
$model = $unmerged;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
$analysis->annotations->detach($annotation);
|
||||
|
||||
if (null === $model || !$model instanceof ModelAnnotation) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_string($model->type)) {
|
||||
// Ignore invalid annotations, they are validated later
|
||||
continue;
|
||||
}
|
||||
|
||||
$annotation->merge([new $annotationClass([
|
||||
'ref' => $this->modelRegistry->register(new Model($this->createType($model->type))),
|
||||
])]);
|
||||
|
||||
// It is no longer an unmerged annotation
|
||||
foreach ($annotation->_unmerged as $key => $unmerged) {
|
||||
if ($unmerged === $model) {
|
||||
unset($annotation->_unmerged[$key]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
$analysis->annotations->detach($model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,195 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\SwaggerPhp;
|
||||
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Nelmio\ApiDocBundle\Util\ControllerReflector;
|
||||
use Swagger\Analysis;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Swagger\Context;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* Automatically resolves the {@link SWG\Operation} linked to
|
||||
* {@link SWG\Response}, {@link SWG\Parameter} and
|
||||
* {@link SWG\ExternalDocumentation} annotations.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class OperationResolver
|
||||
{
|
||||
private $routeCollection;
|
||||
private $controllerReflector;
|
||||
|
||||
private $controllerMap;
|
||||
|
||||
public function __construct(RouteCollection $routeCollection, ControllerReflector $controllerReflector)
|
||||
{
|
||||
$this->routeCollection = $routeCollection;
|
||||
$this->controllerReflector = $controllerReflector;
|
||||
}
|
||||
|
||||
public function __invoke(Analysis $analysis)
|
||||
{
|
||||
$this->resolveOperationsPath($analysis);
|
||||
$this->createImplicitOperations($analysis);
|
||||
}
|
||||
|
||||
private function resolveOperationsPath(Analysis $analysis)
|
||||
{
|
||||
$operations = $analysis->getAnnotationsOfType(SWG\Operation::class);
|
||||
foreach ($operations as $operation) {
|
||||
if (null !== $operation->path || $operation->_context->not('method')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paths = $this->getPaths($operation->_context, $operation->method);
|
||||
if (0 === count($paths)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Define the path of the first annotation
|
||||
$operation->path = array_pop($paths);
|
||||
|
||||
// If there are other paths, clone the annotation
|
||||
foreach ($paths as $path) {
|
||||
$alias = clone $operation;
|
||||
$alias->path = $path;
|
||||
|
||||
$analysis->addAnnotation($alias, $alias->_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function createImplicitOperations(Analysis $analysis)
|
||||
{
|
||||
$annotations = array_merge($analysis->getAnnotationsOfType(SWG\Response::class), $analysis->getAnnotationsOfType(SWG\Parameter::class), $analysis->getAnnotationsOfType(SWG\ExternalDocumentation::class));
|
||||
$map = [];
|
||||
foreach ($annotations as $annotation) {
|
||||
$context = $annotation->_context;
|
||||
if ($context->not('method')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $this->getClass($context);
|
||||
$method = $context->method;
|
||||
|
||||
$id = $class.'|'.$method;
|
||||
if (!isset($map[$id])) {
|
||||
$map[$id] = [];
|
||||
}
|
||||
|
||||
$map[$id][] = $annotation;
|
||||
}
|
||||
|
||||
$operationAnnotations = [
|
||||
'get' => SWG\Get::class,
|
||||
'post' => SWG\Post::class,
|
||||
'put' => SWG\Put::class,
|
||||
'patch' => SWG\Patch::class,
|
||||
'delete' => SWG\Delete::class,
|
||||
'options' => SWG\Options::class,
|
||||
'head' => SWG\Head::class,
|
||||
];
|
||||
foreach ($map as $id => $annotations) {
|
||||
$context = $annotations[0]->_context;
|
||||
$httpMethods = $this->getHttpMethods($context);
|
||||
foreach ($httpMethods as $httpMethod => $paths) {
|
||||
$annotationClass = $operationAnnotations[$httpMethod];
|
||||
foreach ($paths as $path => $v) {
|
||||
$operation = new $annotationClass(['path' => $path, 'value' => $annotations], $context);
|
||||
$analysis->addAnnotation($operation, $context);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($annotations as $annotation) {
|
||||
$analysis->annotations->detach($annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getPaths(Context $context, string $httpMethod): array
|
||||
{
|
||||
$httpMethods = $this->getHttpMethods($context);
|
||||
if (!isset($httpMethods[$httpMethod])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_keys($httpMethods[$httpMethod]);
|
||||
}
|
||||
|
||||
private function getHttpMethods(Context $context)
|
||||
{
|
||||
if (null === $this->controllerMap) {
|
||||
$this->buildMap();
|
||||
}
|
||||
|
||||
$class = $this->getClass($context);
|
||||
$method = $context->method;
|
||||
|
||||
// Checks if a route corresponds to this method
|
||||
if (!isset($this->controllerMap[$class][$method])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->controllerMap[$class][$method];
|
||||
}
|
||||
|
||||
private function getClass(Context $context)
|
||||
{
|
||||
return ltrim($context->namespace.'\\'.$context->class, '\\');
|
||||
}
|
||||
|
||||
private function buildMap()
|
||||
{
|
||||
$this->controllerMap = [];
|
||||
foreach ($this->routeCollection->all() as $route) {
|
||||
if (!$route->hasDefault('_controller')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$controller = $route->getDefault('_controller');
|
||||
if ($callable = $this->controllerReflector->getReflectionClassAndMethod($controller)) {
|
||||
list($class, $method) = $callable;
|
||||
$class = $class->name;
|
||||
$method = $method->name;
|
||||
|
||||
if (!isset($this->controllerMap[$class])) {
|
||||
$this->controllerMap[$class] = [];
|
||||
}
|
||||
if (!isset($this->controllerMap[$class][$method])) {
|
||||
$this->controllerMap[$class][$method] = [];
|
||||
}
|
||||
|
||||
$httpMethods = $route->getMethods() ?: Swagger::$METHODS;
|
||||
foreach ($httpMethods as $httpMethod) {
|
||||
$httpMethod = strtolower($httpMethod);
|
||||
if (!isset($this->controllerMap[$class][$method][$httpMethod])) {
|
||||
$this->controllerMap[$class][$method][$httpMethod] = [];
|
||||
}
|
||||
|
||||
$path = $this->normalizePath($route->getPath());
|
||||
$this->controllerMap[$class][$method][$httpMethod][$path] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function normalizePath(string $path)
|
||||
{
|
||||
if (substr($path, -10) === '.{_format}') {
|
||||
$path = substr($path, 0, -10);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Controller;
|
||||
use FOS\RestBundle\Controller\Annotations\QueryParam;
|
||||
use FOS\RestBundle\Controller\Annotations\RequestParam;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\User;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Swagger\Annotations as SWG;
|
||||
@ -26,7 +27,7 @@ class ApiController
|
||||
/**
|
||||
* @Route("/swagger", methods={"GET"})
|
||||
* @Route("/swagger2", methods={"GET"})
|
||||
* @SWG\Get(
|
||||
* @Operation(
|
||||
* @SWG\Response(response="201", description="An example resource")
|
||||
* )
|
||||
*/
|
||||
@ -92,4 +93,14 @@ class ApiController
|
||||
public function adminAction()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @SWG\Get(
|
||||
* path="/filtered",
|
||||
* @SWG\Response(response="201", description="")
|
||||
* )
|
||||
*/
|
||||
public function filteredAction()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,13 @@ class FunctionalTest extends WebTestCase
|
||||
$this->assertFalse($paths->has('/api/admin'));
|
||||
}
|
||||
|
||||
public function testFilteredAction()
|
||||
{
|
||||
$paths = $this->getSwaggerDefinition()->getPaths();
|
||||
|
||||
$this->assertFalse($paths->has('/filtered'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the paths are automatically resolved in Swagger annotations.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user