From b1d95d966d3cdf327fc7cd371ff7a2470d2a183e Mon Sep 17 00:00:00 2001 From: Guilhem N Date: Mon, 23 Jan 2017 19:46:38 +0100 Subject: [PATCH 1/5] [SwaggerPhp] Only parse controllers --- DependencyInjection/Configuration.php | 1 - DependencyInjection/NelmioApiDocExtension.php | 7 +-- Describer/SwaggerPhpDescriber.php | 58 +++++++++++++------ ModelDescriber/ScalarModelDescriber.php | 2 +- Resources/config/swagger_php.xml | 28 ++------- Tests/Describer/SwaggerPhpDescriberTest.php | 34 ----------- Tests/Fixtures/SwaggerPhp/Api.php | 24 -------- Tests/Functional/Controller/ApiController.php | 6 +- Tests/Functional/TestKernel.php | 1 - Util/ControllerReflector.php | 10 +++- composer.json | 5 +- 11 files changed, 60 insertions(+), 116 deletions(-) delete mode 100644 Tests/Describer/SwaggerPhpDescriberTest.php delete mode 100644 Tests/Fixtures/SwaggerPhp/Api.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 2eb1441..5356c53 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -22,7 +22,6 @@ final class Configuration implements ConfigurationInterface $treeBuilder ->root('nelmio_api_doc') ->children() - ->scalarNode('source_folder')->defaultValue('%kernel.root_dir%/../src')->end() ->arrayNode('routes') ->info('Filter the routes that are documented') ->addDefaultsIfNotSet() diff --git a/DependencyInjection/NelmioApiDocExtension.php b/DependencyInjection/NelmioApiDocExtension.php index d3059bb..6d1e413 100644 --- a/DependencyInjection/NelmioApiDocExtension.php +++ b/DependencyInjection/NelmioApiDocExtension.php @@ -36,15 +36,10 @@ final class NelmioApiDocExtension extends Extension $routeCollectionBuilder->replaceArgument(0, $config['routes']['path_patterns']); // Import services needed for each library + $loader->load('swagger_php.xml'); if (class_exists(DocBlockFactory::class)) { $loader->load('php_doc.xml'); } - if (class_exists(Swagger::class)) { - $loader->load('swagger_php.xml'); - - $swaggerPHPDescriber = $container->getDefinition('nelmio_api_doc.describers.swagger_php'); - $swaggerPHPDescriber->replaceArgument(0, $config['source_folder']); - } if (interface_exists(ParamInterface::class)) { $loader->load('fos_rest.xml'); } diff --git a/Describer/SwaggerPhpDescriber.php b/Describer/SwaggerPhpDescriber.php index 5f26d1c..d016b94 100644 --- a/Describer/SwaggerPhpDescriber.php +++ b/Describer/SwaggerPhpDescriber.php @@ -14,37 +14,59 @@ namespace Nelmio\ApiDocBundle\Describer; 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 Symfony\Component\Routing\RouteCollection; final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelRegistryAwareInterface { use ModelRegistryAwareTrait; - private $operationResolver; + private $routeCollection; + private $controllerReflector; - public function __construct(string $projectPath, bool $overwrite = false) + public function __construct(RouteCollection $routeCollection, ControllerReflector $controllerReflector, bool $overwrite = false) { - $nelmioNamespace = 'Nelmio\\ApiDocBundle\\'; - if (!in_array($nelmioNamespace, Analyser::$whitelist)) { - Analyser::$whitelist[] = $nelmioNamespace; - } + $this->routeCollection = $routeCollection; + $this->controllerReflector = $controllerReflector; - parent::__construct(function () use ($projectPath) { - $options = ['processors' => $this->getProcessors()]; - $annotation = \Swagger\scan($projectPath, $options); + parent::__construct(function () { + $whitelist = Analyser::$whitelist; + Analyser::$whitelist = false; + try { + $options = ['processors' => $this->getProcessors()]; + $annotation = \Swagger\scan($this->getFinder(), $options); - return json_decode(json_encode($annotation)); + return json_decode(json_encode($annotation)); + } finally { + Analyser::$whitelist = $whitelist; + } }, $overwrite); } - /** - * If set, the describer will try to complete paths and create - * implicit operations. - */ - public function setOperationResolver(OperationResolver $operationResolver) + private function getFinder() { - $this->operationResolver = $operationResolver; + $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 @@ -52,10 +74,8 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg $processors = [ new AddDefaults(), new ModelRegister($this->modelRegistry), + new OperationResolver($this->routeCollection, $this->controllerReflector), ]; - if (null !== $this->operationResolver) { - $processors[] = $this->operationResolver; - } return array_merge($processors, Analysis::processors()); } diff --git a/ModelDescriber/ScalarModelDescriber.php b/ModelDescriber/ScalarModelDescriber.php index 4581dcf..48a502f 100644 --- a/ModelDescriber/ScalarModelDescriber.php +++ b/ModelDescriber/ScalarModelDescriber.php @@ -21,7 +21,7 @@ class ScalarModelDescriber implements ModelDescriberInterface Type::BUILTIN_TYPE_INT => 'integer', Type::BUILTIN_TYPE_FLOAT => 'float', Type::BUILTIN_TYPE_STRING => 'string', - Type::BUILTIN_TYPE_BOOL => 'boolean' + Type::BUILTIN_TYPE_BOOL => 'boolean', ]; public function describe(Model $model, Schema $schema) diff --git a/Resources/config/swagger_php.xml b/Resources/config/swagger_php.xml index e582117..70bf245 100644 --- a/Resources/config/swagger_php.xml +++ b/Resources/config/swagger_php.xml @@ -5,31 +5,15 @@ - %kernel.root_dir% - - - + + + + + + - - - - - - - - - - - - - - - - - - diff --git a/Tests/Describer/SwaggerPhpDescriberTest.php b/Tests/Describer/SwaggerPhpDescriberTest.php deleted file mode 100644 index 0102f2e..0000000 --- a/Tests/Describer/SwaggerPhpDescriberTest.php +++ /dev/null @@ -1,34 +0,0 @@ -getSwaggerDoc(); - $info = $api->getInfo(); - - $this->assertEquals('My Awesome App', $info->getTitle()); - $this->assertEquals('1.3', $info->getVersion()); - } - - protected function setUp() - { - $this->describer = new SwaggerPhpDescriber(__DIR__.'/../Fixtures'); - $this->describer->setModelRegistry(new ModelRegistry([], new Swagger())); - } -} diff --git a/Tests/Fixtures/SwaggerPhp/Api.php b/Tests/Fixtures/SwaggerPhp/Api.php deleted file mode 100644 index b1b8efb..0000000 --- a/Tests/Fixtures/SwaggerPhp/Api.php +++ /dev/null @@ -1,24 +0,0 @@ -loadFromExtension('nelmio_api_doc', [ - 'source_folder' => '%kernel.root_dir%', 'routes' => [ 'path_patterns' => ['^/api(?!/admin)'], ], diff --git a/Util/ControllerReflector.php b/Util/ControllerReflector.php index a4b7d0f..6a6f9ff 100644 --- a/Util/ControllerReflector.php +++ b/Util/ControllerReflector.php @@ -22,6 +22,8 @@ final class ControllerReflector private $container; private $controllerNameParser; + private $controllers = []; + public function __construct(ContainerInterface $container, ControllerNameParser $controllerNameParser) { $this->container = $container; @@ -69,6 +71,10 @@ final class ControllerReflector private function getClassAndMethod(string $controller) { + if (isset($this->controllers[$controller])) { + return $this->controllers[$controller]; + } + if (false === strpos($controller, '::') && 2 === substr_count($controller, ':')) { $controller = $this->controllerNameParser->parse($controller); } @@ -98,9 +104,11 @@ final class ControllerReflector } if (!isset($class) || !isset($method)) { + $this->controllers[$controller] = null; + return; } - return [$class, $method]; + return $this->controllers[$controller] = [$class, $method]; } } diff --git a/composer.json b/composer.json index 431a599..7fc9452 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "php": "~7.0|~7.1", "symfony/framework-bundle": "^2.8|^3.0", "symfony/property-info": "^2.8|^3.0", - "exsyst/swagger": "~0.2.3" + "exsyst/swagger": "~0.2.3", + "zircote/swagger-php": "dev-master" }, "require-dev": { "symfony/twig-bundle": "^2.8|^3.0", @@ -34,13 +35,11 @@ "doctrine/annotations": "^1.2", "phpdocumentor/reflection-docblock": "^3.1", - "zircote/swagger-php": "^2.0", "api-platform/core": "^2.0", "friendsofsymfony/rest-bundle": "^2.0" }, "suggest": { "phpdocumentor/reflection-docblock": "For parsing php docs.", - "zircote/swagger-php": "For using swagger annotations.", "api-platform/core": "For using an API oriented framework.", "friendsofsymfony/rest-bundle": "For using the parameters annotations." }, From 33274ca4a89730fb324f407b76ad732db8d7ce4e Mon Sep 17 00:00:00 2001 From: Guilhem N Date: Wed, 25 Jan 2017 19:38:56 +0100 Subject: [PATCH 2/5] Fix an error when installing NelmioApiDocBundle --- DependencyInjection/NelmioApiDocExtension.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/NelmioApiDocExtension.php b/DependencyInjection/NelmioApiDocExtension.php index d3059bb..458d8bd 100644 --- a/DependencyInjection/NelmioApiDocExtension.php +++ b/DependencyInjection/NelmioApiDocExtension.php @@ -17,10 +17,19 @@ 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\HttpKernel\DependencyInjection\Extension; -final class NelmioApiDocExtension extends Extension +final class NelmioApiDocExtension extends Extension implements PrependExtensionInterface { + /** + * {@inheritdoc} + */ + public function prepend(ContainerBuilder $container) + { + $container->prependExtensionConfig('framework', ['property_info' => ['enabled' => true]]); + } + /** * {@inheritdoc} */ From 645f4f2c1b97c9e9661dc891cfb9667ff4bfddc6 Mon Sep 17 00:00:00 2001 From: Guilhem N Date: Wed, 1 Feb 2017 16:13:49 +0100 Subject: [PATCH 3/5] Make compiler passes internal --- DependencyInjection/Compiler/AddDescribersPass.php | 5 ++++- DependencyInjection/Compiler/AddRouteDescribersPass.php | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Compiler/AddDescribersPass.php b/DependencyInjection/Compiler/AddDescribersPass.php index ff7173d..0849b1c 100644 --- a/DependencyInjection/Compiler/AddDescribersPass.php +++ b/DependencyInjection/Compiler/AddDescribersPass.php @@ -14,7 +14,10 @@ namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -class AddDescribersPass implements CompilerPassInterface +/** + * @internal + */ +final class AddDescribersPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; diff --git a/DependencyInjection/Compiler/AddRouteDescribersPass.php b/DependencyInjection/Compiler/AddRouteDescribersPass.php index 64ddde3..35e0867 100644 --- a/DependencyInjection/Compiler/AddRouteDescribersPass.php +++ b/DependencyInjection/Compiler/AddRouteDescribersPass.php @@ -14,7 +14,10 @@ namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -class AddRouteDescribersPass implements CompilerPassInterface +/** + * @internal + */ +final class AddRouteDescribersPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; From 2e034dc3a8d0e795208546f3215dfd621f625d59 Mon Sep 17 00:00:00 2001 From: Guilhem N Date: Wed, 1 Feb 2017 16:14:58 +0100 Subject: [PATCH 4/5] Remove EXSystApiDocBundle --- EXSystApiDocBundle.php | 45 ------------------------------------------ 1 file changed, 45 deletions(-) delete mode 100644 EXSystApiDocBundle.php diff --git a/EXSystApiDocBundle.php b/EXSystApiDocBundle.php deleted file mode 100644 index 13ee40a..0000000 --- a/EXSystApiDocBundle.php +++ /dev/null @@ -1,45 +0,0 @@ -addCompilerPass(new AddDescribersPass()); - $container->addCompilerPass(new AddRouteDescribersPass()); - $container->addCompilerPass(new AddModelDescribersPass()); - } - - /** - * {@inheritdoc} - */ - public function getContainerExtension() - { - if (null === $this->extension) { - $this->extension = new EXSystApiDocExtension(); - } - if ($this->extension) { - return $this->extension; - } - } -} From fa0d937160f959bc474c343ed14c8ab647ff560f Mon Sep 17 00:00:00 2001 From: Guilhem N Date: Thu, 2 Feb 2017 17:17:42 +0100 Subject: [PATCH 5/5] Do not allow using @Model in @Swagger annotation --- Annotation/Model.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Annotation/Model.php b/Annotation/Model.php index 799914a..06d3b63 100644 --- a/Annotation/Model.php +++ b/Annotation/Model.php @@ -22,7 +22,6 @@ final class Model extends AbstractAnnotation public static $_parents = [ 'Swagger\Annotations\Parameter', 'Swagger\Annotations\Response', - 'Swagger\Annotations\Swagger', ]; public $type;