mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-10 11:39:25 +03:00
Merge pull request #2 from EXSyst/FILTER_ROUTES
Allow to filter routes based on their path
This commit is contained in:
commit
9b82da1d85
@ -19,7 +19,21 @@ class Configuration implements ConfigurationInterface
|
|||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder();
|
$treeBuilder = new TreeBuilder();
|
||||||
$rootNode = $treeBuilder->root('exsyst_api_doc');
|
$treeBuilder
|
||||||
|
->root('exsyst_api_doc')
|
||||||
|
->children()
|
||||||
|
->arrayNode('routes')
|
||||||
|
->info('Filter the routes that are documented')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->arrayNode('path_patterns')
|
||||||
|
->example(array('^/api', '^/api(?!/admin)'))
|
||||||
|
->prototype('scalar')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
|
||||||
return $treeBuilder;
|
return $treeBuilder;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,10 @@ class EXSystApiDocExtension extends Extension
|
|||||||
|
|
||||||
$loader->load('services.xml');
|
$loader->load('services.xml');
|
||||||
|
|
||||||
|
// Filter routes
|
||||||
|
$routeCollectionBuilder = $container->getDefinition('exsyst_api_doc.describers.route.filtered_route_collection_builder');
|
||||||
|
$routeCollectionBuilder->replaceArgument(0, $config['routes']['path_patterns']);
|
||||||
|
|
||||||
// Import services needed for each library
|
// Import services needed for each library
|
||||||
if (class_exists(ApiDoc::class)) {
|
if (class_exists(ApiDoc::class)) {
|
||||||
$loader->load('nelmio_apidoc.xml');
|
$loader->load('nelmio_apidoc.xml');
|
||||||
|
@ -17,25 +17,25 @@ use EXSyst\Component\Swagger\Swagger;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\Routing\Route;
|
use Symfony\Component\Routing\Route;
|
||||||
use Symfony\Component\Routing\RouterInterface;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
class RouteDescriber implements DescriberInterface
|
class RouteDescriber implements DescriberInterface
|
||||||
{
|
{
|
||||||
private $container;
|
private $container;
|
||||||
private $router;
|
private $routeCollection;
|
||||||
private $controllerNameParser;
|
private $controllerNameParser;
|
||||||
private $routeDescribers;
|
private $routeDescribers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ContainerInterface $container
|
* @param ContainerInterface $container
|
||||||
* @param RouterInterface $router
|
* @param RouteCollection $routeCollection
|
||||||
* @param ControllerNameParser $controllerNameParser
|
* @param ControllerNameParser $controllerNameParser
|
||||||
* @param RouteDescriberInterface[] $routeDescribers
|
* @param RouteDescriberInterface[] $routeDescribers
|
||||||
*/
|
*/
|
||||||
public function __construct(ContainerInterface $container, RouterInterface $router, ControllerNameParser $controllerNameParser, array $routeDescribers)
|
public function __construct(ContainerInterface $container, RouteCollection $routeCollection, ControllerNameParser $controllerNameParser, array $routeDescribers)
|
||||||
{
|
{
|
||||||
$this->container = $container;
|
$this->container = $container;
|
||||||
$this->router = $router;
|
$this->routeCollection = $routeCollection;
|
||||||
$this->controllerNameParser = $controllerNameParser;
|
$this->controllerNameParser = $controllerNameParser;
|
||||||
$this->routeDescribers = $routeDescribers;
|
$this->routeDescribers = $routeDescribers;
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ class RouteDescriber implements DescriberInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->getRoutes() as $route) {
|
foreach ($this->routeCollection->all() as $route) {
|
||||||
// if able to resolve the controller
|
// if able to resolve the controller
|
||||||
if ($method = $this->getReflectionMethod($route->getDefault('_controller'))) {
|
if ($method = $this->getReflectionMethod($route->getDefault('_controller'))) {
|
||||||
// Extract as many informations as possible about this route
|
// Extract as many informations as possible about this route
|
||||||
@ -57,16 +57,6 @@ class RouteDescriber implements DescriberInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of route to inspect.
|
|
||||||
*
|
|
||||||
* @return Route[] An array of routes
|
|
||||||
*/
|
|
||||||
private function getRoutes()
|
|
||||||
{
|
|
||||||
return $this->router->getRouteCollection()->all();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ReflectionMethod for the given controller string.
|
* Returns the ReflectionMethod for the given controller string.
|
||||||
*
|
*
|
||||||
|
@ -9,9 +9,23 @@
|
|||||||
</service>
|
</service>
|
||||||
|
|
||||||
<!-- Extractors -->
|
<!-- Extractors -->
|
||||||
|
<service id="exsyst_api_doc.describers.route.filtered_route_collection_builder" class="EXSyst\Bundle\ApiDocBundle\Routing\FilteredRouteCollectionBuilder" public="false">
|
||||||
|
<argument type="collection" /> <!-- Path patterns -->
|
||||||
|
</service>
|
||||||
|
|
||||||
|
|
||||||
<service id="exsyst_api_doc.describers.route" class="EXSyst\Bundle\ApiDocBundle\Describer\RouteDescriber" public="false">
|
<service id="exsyst_api_doc.describers.route" class="EXSyst\Bundle\ApiDocBundle\Describer\RouteDescriber" public="false">
|
||||||
<argument type="service" id="service_container" />
|
<argument type="service" id="service_container" />
|
||||||
<argument type="service" id="router" />
|
<argument type="service">
|
||||||
|
<service class="Symfony\Component\Routing\RouteCollection">
|
||||||
|
<factory service="exsyst_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="controller_name_converter" />
|
<argument type="service" id="controller_name_converter" />
|
||||||
<argument type="collection" />
|
<argument type="collection" />
|
||||||
|
|
||||||
|
48
Routing/FilteredRouteCollectionBuilder.php
Normal file
48
Routing/FilteredRouteCollectionBuilder.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the ApiDocBundle package.
|
||||||
|
*
|
||||||
|
* (c) EXSyst
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EXSyst\Bundle\ApiDocBundle\Routing;
|
||||||
|
|
||||||
|
use Symfony\Component\Routing\Route;
|
||||||
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
|
final class FilteredRouteCollectionBuilder
|
||||||
|
{
|
||||||
|
private $pathPatterns;
|
||||||
|
|
||||||
|
public function __construct(array $pathPatterns = [])
|
||||||
|
{
|
||||||
|
$this->pathPatterns = $pathPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filter(RouteCollection $routes): RouteCollection
|
||||||
|
{
|
||||||
|
$filteredRoutes = new RouteCollection();
|
||||||
|
foreach ($routes->all() as $name => $route) {
|
||||||
|
if ($this->match($route)) {
|
||||||
|
$filteredRoutes->add($name, $route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $filteredRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function match(Route $route): bool
|
||||||
|
{
|
||||||
|
foreach ($this->pathPatterns as $pathPattern) {
|
||||||
|
if (!preg_match('{'.$pathPattern.'}', $route->getPath())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,9 @@ namespace EXSyst\Bundle\ApiDocBundle\Tests\Functional\Controller;
|
|||||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api")
|
||||||
|
*/
|
||||||
class ApiController
|
class ApiController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -45,4 +48,13 @@ class ApiController
|
|||||||
public function deprecatedAction()
|
public function deprecatedAction()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This action is not documented. It is excluded by the config.
|
||||||
|
*
|
||||||
|
* @Route("/admin", methods={"GET"})
|
||||||
|
*/
|
||||||
|
public function adminAction()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
27
Tests/Functional/Controller/UndocumentedController.php
Normal file
27
Tests/Functional/Controller/UndocumentedController.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the ApiDocBundle package.
|
||||||
|
*
|
||||||
|
* (c) EXSyst
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EXSyst\Bundle\ApiDocBundle\Tests\Functional\Controller;
|
||||||
|
|
||||||
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||||
|
|
||||||
|
class UndocumentedController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This path is excluded by the config (only /api allowed).
|
||||||
|
*
|
||||||
|
* @Route("/undocumented", methods={"GET"})
|
||||||
|
*/
|
||||||
|
public function undocumentedAction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -15,9 +15,16 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|||||||
|
|
||||||
class FunctionalTest extends WebTestCase
|
class FunctionalTest extends WebTestCase
|
||||||
{
|
{
|
||||||
|
public function testUndocumentedAction()
|
||||||
|
{
|
||||||
|
$paths = $this->getSwaggerDefinition()->getPaths();
|
||||||
|
$this->assertFalse($paths->has('/undocumented'));
|
||||||
|
$this->assertFalse($paths->has('/api/admin'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testUserAction()
|
public function testUserAction()
|
||||||
{
|
{
|
||||||
$operation = $this->getOperation('/test/{user}', 'get');
|
$operation = $this->getOperation('/api/test/{user}', 'get');
|
||||||
|
|
||||||
$this->assertEquals(['https'], $operation->getSchemes());
|
$this->assertEquals(['https'], $operation->getSchemes());
|
||||||
$this->assertEmpty($operation->getSummary());
|
$this->assertEmpty($operation->getSummary());
|
||||||
@ -35,7 +42,7 @@ class FunctionalTest extends WebTestCase
|
|||||||
|
|
||||||
public function testNelmioAction()
|
public function testNelmioAction()
|
||||||
{
|
{
|
||||||
$operation = $this->getOperation('/nelmio/{foo}', 'post');
|
$operation = $this->getOperation('/api/nelmio/{foo}', 'post');
|
||||||
|
|
||||||
$this->assertEquals('This action is described.', $operation->getDescription());
|
$this->assertEquals('This action is described.', $operation->getDescription());
|
||||||
$this->assertNull($operation->getDeprecated());
|
$this->assertNull($operation->getDeprecated());
|
||||||
@ -47,7 +54,7 @@ class FunctionalTest extends WebTestCase
|
|||||||
|
|
||||||
public function testDeprecatedAction()
|
public function testDeprecatedAction()
|
||||||
{
|
{
|
||||||
$operation = $this->getOperation('/deprecated', 'get');
|
$operation = $this->getOperation('/api/deprecated', 'get');
|
||||||
|
|
||||||
$this->assertEquals('This action is deprecated.', $operation->getSummary());
|
$this->assertEquals('This action is deprecated.', $operation->getSummary());
|
||||||
$this->assertEquals('Please do not use this action.', $operation->getDescription());
|
$this->assertEquals('Please do not use this action.', $operation->getDescription());
|
||||||
|
@ -59,5 +59,12 @@ class TestKernel extends Kernel
|
|||||||
'test' => null,
|
'test' => null,
|
||||||
'validation' => null,
|
'validation' => null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Filter routes
|
||||||
|
$c->loadFromExtension('exsyst_api_doc', [
|
||||||
|
'routes' => [
|
||||||
|
'path_patterns' => ['^/api(?!/admin)'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user