[3.x]: Hide the default section per area with new config parameter (#1868)

* Add new config node disable_default_routes to prevent registering RouteDescriber to specific areas which allowes disabling rendering of default routes, Adjust tests accordingly

* Add documentation for new config variable

* Change disable_default_routes to filter route collection instead of disabling route describer, Add test for new handling in FilteredRouteCollectionBuilder

* Change naming of matching method for disabling default routes

* Fix codestyle issue

* Fix codestyle issue

* Change naming of dataProvider to match testing name

Co-authored-by: Frederik Holz <team-orange@auxmoney.com>
This commit is contained in:
Frederik Holz 2021-10-06 19:28:59 +02:00 committed by GitHub
parent 1306106931
commit aa18c6c83b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 125 additions and 0 deletions

View File

@ -63,6 +63,7 @@ final class Configuration implements ConfigurationInterface
'with_annotation' => false, 'with_annotation' => false,
'documentation' => [], 'documentation' => [],
'name_patterns' => [], 'name_patterns' => [],
'disable_default_routes' => false,
], ],
] ]
) )
@ -103,6 +104,10 @@ final class Configuration implements ConfigurationInterface
->defaultFalse() ->defaultFalse()
->info('whether to filter by annotation') ->info('whether to filter by annotation')
->end() ->end()
->booleanNode('disable_default_routes')
->defaultFalse()
->info('if set disables default routes without annotations')
->end()
->arrayNode('documentation') ->arrayNode('documentation')
->useAttributeAsKey('key') ->useAttributeAsKey('key')
->defaultValue([]) ->defaultValue([])

View File

@ -106,6 +106,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
&& 0 === count($areaConfig['host_patterns']) && 0 === count($areaConfig['host_patterns'])
&& 0 === count($areaConfig['name_patterns']) && 0 === count($areaConfig['name_patterns'])
&& false === $areaConfig['with_annotation'] && false === $areaConfig['with_annotation']
&& false === $areaConfig['disable_default_routes']
) { ) {
$container->setDefinition(sprintf('nelmio_api_doc.routes.%s', $area), $routesDefinition) $container->setDefinition(sprintf('nelmio_api_doc.routes.%s', $area), $routesDefinition)
->setPublic(false); ->setPublic(false);

View File

@ -197,3 +197,17 @@ A: Use ``@SWG\Tag`` annotation.
{ {
//... //...
} }
Disable Default Section
-----------------------
Q: I don't want to render the "default" section, how do I do that?
A: Use ``disable_default_routes`` config in your area.
.. code-block:: yaml
nelmio_api_doc:
areas:
default:
disable_default_routes: true

View File

@ -45,11 +45,13 @@ final class FilteredRouteCollectionBuilder
'host_patterns' => [], 'host_patterns' => [],
'name_patterns' => [], 'name_patterns' => [],
'with_annotation' => false, 'with_annotation' => false,
'disable_default_routes' => false,
]) ])
->setAllowedTypes('path_patterns', 'string[]') ->setAllowedTypes('path_patterns', 'string[]')
->setAllowedTypes('host_patterns', 'string[]') ->setAllowedTypes('host_patterns', 'string[]')
->setAllowedTypes('name_patterns', 'string[]') ->setAllowedTypes('name_patterns', 'string[]')
->setAllowedTypes('with_annotation', 'boolean') ->setAllowedTypes('with_annotation', 'boolean')
->setAllowedTypes('disable_default_routes', 'boolean')
; ;
if (array_key_exists(0, $options)) { if (array_key_exists(0, $options)) {
@ -73,6 +75,7 @@ final class FilteredRouteCollectionBuilder
&& $this->matchHost($route) && $this->matchHost($route)
&& $this->matchAnnotation($route) && $this->matchAnnotation($route)
&& $this->matchName($name) && $this->matchName($name)
&& $this->defaultRouteDisabled($route)
) { ) {
$filteredRoutes->add($name, $route); $filteredRoutes->add($name, $route);
} }
@ -135,4 +138,31 @@ final class FilteredRouteCollectionBuilder
return (null !== $areas) ? $areas->has($this->area) : false; return (null !== $areas) ? $areas->has($this->area) : false;
} }
private function defaultRouteDisabled(Route $route): bool
{
if (false === $this->options['disable_default_routes']) {
return true;
}
$method = $this->controllerReflector->getReflectionMethod(
$route->getDefault('_controller') ?? ''
);
if (null === $method) {
return false;
}
$annotations = $this->annotationReader->getMethodAnnotations($method);
foreach ($annotations as $annotation) {
if (false !== strpos(get_class($annotation), 'Nelmio\\ApiDocBundle\\Annotation')
|| false !== strpos(get_class($annotation), 'Swagger\\Annotations')
) {
return true;
}
}
return false;
}
} }

View File

@ -29,6 +29,7 @@ class ConfigurationTest extends TestCase
'host_patterns' => [], 'host_patterns' => [],
'name_patterns' => [], 'name_patterns' => [],
'with_annotation' => false, 'with_annotation' => false,
'disable_default_routes' => false,
'documentation' => [], 'documentation' => [],
], ],
], ],
@ -46,6 +47,7 @@ class ConfigurationTest extends TestCase
'with_annotation' => false, 'with_annotation' => false,
'documentation' => [], 'documentation' => [],
'name_patterns' => [], 'name_patterns' => [],
'disable_default_routes' => false,
], ],
'internal' => [ 'internal' => [
'path_patterns' => ['/internal'], 'path_patterns' => ['/internal'],
@ -53,6 +55,7 @@ class ConfigurationTest extends TestCase
'with_annotation' => false, 'with_annotation' => false,
'documentation' => [], 'documentation' => [],
'name_patterns' => [], 'name_patterns' => [],
'disable_default_routes' => false,
], ],
'commercial' => [ 'commercial' => [
'path_patterns' => ['/internal'], 'path_patterns' => ['/internal'],
@ -60,6 +63,7 @@ class ConfigurationTest extends TestCase
'with_annotation' => false, 'with_annotation' => false,
'documentation' => [], 'documentation' => [],
'name_patterns' => [], 'name_patterns' => [],
'disable_default_routes' => false,
], ],
]]]); ]]]);
@ -173,6 +177,7 @@ class ConfigurationTest extends TestCase
'host_patterns' => [], 'host_patterns' => [],
'name_patterns' => [], 'name_patterns' => [],
'with_annotation' => false, 'with_annotation' => false,
'disable_default_routes' => false,
'documentation' => [], 'documentation' => [],
], ],
], ],

View File

@ -14,9 +14,11 @@ namespace Nelmio\ApiDocBundle\Tests\Routing;
use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Annotations\Reader;
use Nelmio\ApiDocBundle\Annotation\Areas; use Nelmio\ApiDocBundle\Annotation\Areas;
use Nelmio\ApiDocBundle\Annotation\Operation;
use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder; use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder;
use Nelmio\ApiDocBundle\Util\ControllerReflector; use Nelmio\ApiDocBundle\Util\ControllerReflector;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Swagger\Annotations\Parameter;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
@ -245,6 +247,74 @@ class FilteredRouteCollectionBuilderTest extends TestCase
]; ];
} }
/**
* @dataProvider getRoutesWithDisabledDefaultRoutes
*
* @param array<Operation|Parameter> $annotations
* @param array<string|boolean> $options
*/
public function testRoutesWithDisabledDefaultRoutes(
string $name,
Route $route,
array $annotations,
array $options,
int $expectedRoutesCount
): void {
$routes = new RouteCollection();
$routes->add($name, $route);
$area = 'area';
$reflectionMethodStub = $this->createMock(\ReflectionMethod::class);
$controllerReflectorStub = $this->createMock(ControllerReflector::class);
$controllerReflectorStub->method('getReflectionMethod')->willReturn($reflectionMethodStub);
$annotationReader = $this->createMock(Reader::class);
$annotationReader
->method('getMethodAnnotations')
->willReturn($annotations)
;
$routeBuilder = new FilteredRouteCollectionBuilder(
$annotationReader,
$controllerReflectorStub,
$area,
$options
);
$filteredRoutes = $routeBuilder->filter($routes);
$this->assertCount($expectedRoutesCount, $filteredRoutes);
}
/**
* @return array<string,array>
*/
public function getRoutesWithDisabledDefaultRoutes(): array
{
return [
'non matching route without Annotation' => [
'r10',
new Route('/api/foo', ['_controller' => 'ApiController::fooAction']),
[],
['disable_default_routes' => true],
0,
],
'matching route with Nelmio Annotation' => [
'r10',
new Route('/api/foo', ['_controller' => 'ApiController::fooAction']),
[new Operation([])],
['disable_default_routes' => true],
1,
],
'matching route with Swagger Annotation' => [
'r10',
new Route('/api/foo', ['_controller' => 'ApiController::fooAction']),
[new Parameter([])],
['disable_default_routes' => true],
1,
],
];
}
private function createControllerReflector(): ControllerReflector private function createControllerReflector(): ControllerReflector
{ {
if (class_exists(ControllerNameParser::class)) { if (class_exists(ControllerNameParser::class)) {