diff --git a/DependencyInjection/EXSystApiDocExtension.php b/DependencyInjection/EXSystApiDocExtension.php
index f243ab1..3e0e4f4 100644
--- a/DependencyInjection/EXSystApiDocExtension.php
+++ b/DependencyInjection/EXSystApiDocExtension.php
@@ -39,15 +39,15 @@ class EXSystApiDocExtension extends Extension
$loader->load('services.xml');
- // Removes useless services
- if (!class_exists(ApiDoc::class)) {
- $container->removeDefinition('exsyst_api_doc.route_describers.nelmio_annotation');
+ // Import services needed for each library
+ if (class_exists(ApiDoc::class)) {
+ $loader->load('nelmio_apidoc.xml');
}
- if (!class_exists(DocBlockFactory::class)) {
- $container->removeDefinition('exsyst_api_doc.route_describers.php_doc');
+ if (class_exists(DocBlockFactory::class)) {
+ $loader->load('php_doc.xml');
}
- if (!class_exists(Swagger::class)) {
- $container->removeDefinition('exsyst_api_doc.describers.swagger_php');
+ if (class_exists(Swagger::class)) {
+ $loader->load('swagger_php.xml');
}
$bundles = $container->getParameter('kernel.bundles');
diff --git a/Describer/DefaultDescriber.php b/Describer/DefaultDescriber.php
index 88a864e..3afcd0b 100644
--- a/Describer/DefaultDescriber.php
+++ b/Describer/DefaultDescriber.php
@@ -34,24 +34,8 @@ class DefaultDescriber implements DescriberInterface
// Paths
$paths = $api->getPaths();
foreach ($paths as $uri => $path) {
- // Path Parameters
- preg_match_all('/\{(.+)\}/SU', $uri, $matches);
- $pathParameters = $matches[1];
-
foreach ($path->getMethods() as $method) {
$operation = $path->getOperation($method);
- $parameters = $operation->getParameters();
-
- // Default Path Parameters
- foreach ($pathParameters as $pathParameter) {
- if ($parameters->has($pathParameter, 'path')) {
- continue;
- }
-
- $parameters->get($pathParameter, 'path')
- ->setRequired(true)
- ->setType('string');
- }
// Default Response
if (0 === iterator_count($operation->getResponses())) {
diff --git a/Resources/config/api_platform.xml b/Resources/config/api_platform.xml
index 5d6a474..1d94baa 100644
--- a/Resources/config/api_platform.xml
+++ b/Resources/config/api_platform.xml
@@ -8,7 +8,7 @@
-
+
diff --git a/Resources/config/nelmio_apidoc.xml b/Resources/config/nelmio_apidoc.xml
new file mode 100644
index 0000000..b750164
--- /dev/null
+++ b/Resources/config/nelmio_apidoc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Resources/config/php_doc.xml b/Resources/config/php_doc.xml
new file mode 100644
index 0000000..d203ce5
--- /dev/null
+++ b/Resources/config/php_doc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
index 26f39f9..c352ee3 100644
--- a/Resources/config/services.xml
+++ b/Resources/config/services.xml
@@ -9,12 +9,6 @@
-
- %kernel.root_dir%
-
-
-
-
@@ -30,16 +24,6 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/Resources/config/swagger_php.xml b/Resources/config/swagger_php.xml
new file mode 100644
index 0000000..86859d2
--- /dev/null
+++ b/Resources/config/swagger_php.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ %kernel.root_dir%
+
+
+
+
+
+
diff --git a/RouteDescriber/FosRestDescriber.php b/RouteDescriber/FosRestDescriber.php
new file mode 100644
index 0000000..d1e19f9
--- /dev/null
+++ b/RouteDescriber/FosRestDescriber.php
@@ -0,0 +1,82 @@
+annotationReader = $annotationReader;
+ }
+
+ public function describe(Swagger $api, Route $route, \ReflectionMethod $reflectionMethod)
+ {
+ $annotations = $this->annotationReader->getMethodAnnotations();
+ $annotations = array_filter($annotations, function ($value) {
+ return $value instanceof RequestParam || $value instanceof QueryParam;
+ });
+
+ foreach ($this->getOperations($api, $route) as $operation) {
+ foreach ($annotations as $annotation) {
+ $in = $annotation instanceof QueryParam ? 'query' : 'formData';
+ $parameter = $operation->getParameters()->get($annotation->getKey(), $in);
+
+ $parameter->setAllowEmptyValue($annotation->nullable && $annotation->allowBlank);
+ $parameter->setType($annotation->map ? 'array' : 'string');
+ $parameter->setDefault($annotation->getDefault());
+ if (null === $parameter->getDescription()) {
+ $parameter->setDescription($annotation->description);
+ }
+
+ $normalizedRequirements = $this->normalizeRequirements($annotation->requirements);
+ if (null !== $normalizedRequirements) {
+ $parameter->setFormat($normalizedRequirements);
+ }
+ }
+ }
+ }
+
+ private function normalizeRequirements($requirements)
+ {
+ // if pattern
+ if (isset($requirements['rule'])) {
+ return (string) $requirements['rule'];
+ }
+ if (is_string($requirements)) {
+ return $requirements;
+ }
+ // if custom constraint
+ if ($requirements instanceof Constraint) {
+ if ($requirements instanceof Regex) {
+ return $requirements->getHtmlPattern();
+ }
+
+ $reflectionClass = new \ReflectionClass($requirements);
+
+ return $reflectionClass->getShortName();
+ }
+ }
+}
diff --git a/RouteDescriber/NelmioAnnotationDescriber.php b/RouteDescriber/NelmioAnnotationDescriber.php
index 2bc577c..c2237bf 100644
--- a/RouteDescriber/NelmioAnnotationDescriber.php
+++ b/RouteDescriber/NelmioAnnotationDescriber.php
@@ -39,28 +39,41 @@ class NelmioAnnotationDescriber implements RouteDescriberInterface
$annotationArray = $annotation->toArray();
foreach ($this->getOperations($api, $route) as $operation) {
- if ($annotation->getDescription()) {
+ if (null === $operation->getDescription()) {
$operation->setDescription($annotation->getDescription());
}
- $operation->setDeprecated($operation->getDeprecated() || $annotation->getDeprecated());
+ if (null === $operation->getDeprecated() && $annotation->getDeprecated()) {
+ $operation->setDeprecated(true);
+ }
// Request parameters
foreach ($annotation->getParameters() as $name => $configuration) {
$parameter = $operation->getParameters()->get($name, 'formData');
- if (isset($configuration['required'])) {
- $parameter->setRequired($parameter->getRequired() || $configuration['required']);
+ if (isset($configuration['required']) && $configuration['required']) {
+ $parameter->setRequired(true);
}
$this->configureParameter($parameter, $configuration);
}
- // Query parameters
+ // Query/Path required parameters
+ $compiledRoute = $route->compile();
+ $pathVariables = $compiledRoute->getVariables();
+ $hostVariables = $compiledRoute->getHostVariables();
foreach ($annotation->getRequirements() as $name => $configuration) {
- $parameter = $operation->getParameters()->get($name, 'query');
+ if (in_array($name, $pathVariables)) {
+ $in = 'path';
+ } elseif (!in_array($name, $hostVariables)) {
+ $in = 'query';
+ } else { // Host variables not supported
+ continue;
+ }
+ $parameter = $operation->getParameters()->get($name, $in);
$parameter->setRequired(true);
$this->configureParameter($parameter, $configuration);
}
+ // Optional Query parameters
foreach ($annotation->getFilters() as $name => $configuration) {
$parameter = $operation->getParameters()->get($name, 'query');
$this->configureParameter($parameter, $configuration);
diff --git a/RouteDescriber/PhpDocDescriber.php b/RouteDescriber/PhpDocDescriber.php
index 7c73b53..90570bd 100644
--- a/RouteDescriber/PhpDocDescriber.php
+++ b/RouteDescriber/PhpDocDescriber.php
@@ -46,8 +46,12 @@ class PhpDocDescriber implements RouteDescriberInterface
foreach ($this->getOperations($api, $route) as $operation) {
if (null !== $docBlock) {
- $operation->setSummary($docBlock->getSummary());
- $operation->setDescription((string) $docBlock->getDescription());
+ if (null === $operation->getSummary() && '' !== $docBlock->getSummary()) {
+ $operation->setSummary($docBlock->getSummary());
+ }
+ if (null === $operation->getDescription() && '' !== (string) $docBlock->getDescription()) {
+ $operation->setDescription((string) $docBlock->getDescription());
+ }
if ($docBlock->hasTag('deprecated')) {
$operation->setDeprecated(true);
}
diff --git a/RouteDescriber/RouteMetadataDescriber.php b/RouteDescriber/RouteMetadataDescriber.php
index a32685b..84a48f1 100644
--- a/RouteDescriber/RouteMetadataDescriber.php
+++ b/RouteDescriber/RouteMetadataDescriber.php
@@ -23,11 +23,18 @@ class RouteMetadataDescriber implements RouteDescriberInterface
foreach ($this->getOperations($api, $route) as $operation) {
$operation->merge(['schemes' => $route->getSchemes()]);
- foreach ($route->getRequirements() as $parameterName => $requirement) {
- $parameter = $operation->getParameters()->get($parameterName, 'path');
+ $requirements = $route->getRequirements();
+ $compiledRoute = $route->compile();
+
+ // Don't include path variables
+ foreach ($compiledRoute->getPathVariables() as $pathVariable) {
+ $parameter = $operation->getParameters()->get($pathVariable, 'path');
$parameter->setRequired(true);
$parameter->setType('string');
- $parameter->setFormat($requirement);
+
+ if (isset($requirements[$pathVariable])) {
+ $parameter->setFormat($requirements[$pathVariable]);
+ }
}
}
}
diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php
index 203707f..b69c747 100644
--- a/Tests/Functional/FunctionalTest.php
+++ b/Tests/Functional/FunctionalTest.php
@@ -38,7 +38,7 @@ class FunctionalTest extends WebTestCase
$operation = $this->getOperation('/nelmio/{foo}', 'post');
$this->assertEquals('This action is described.', $operation->getDescription());
- $this->assertFalse($operation->getDeprecated());
+ $this->assertNull($operation->getDeprecated());
$foo = $operation->getParameters()->get('foo', 'path');
$this->assertTrue($foo->getRequired());
diff --git a/composer.json b/composer.json
index d4a997d..c1ad59e 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,7 @@
"require": {
"php": "^7.0",
"symfony/framework-bundle": "^3.2",
- "exsyst/swagger": "dev-master"
+ "exsyst/swagger": "~0.2.1"
},
"require-dev": {
"symfony/validator": "^3.2",
@@ -20,17 +20,20 @@
"symfony/cache": "^3.2",
"symfony/phpunit-bridge": "^3.2",
"sensio/framework-extra-bundle": "^3.0",
+ "phpunit/phpunit": "^5.4",
+
"nelmio/api-doc-bundle": "^2.0",
"phpdocumentor/reflection-docblock": "^3.1",
- "phpunit/phpunit": "^5.4",
"zircote/swagger-php": "^2.0",
- "api-platform/core": "dev-master"
+ "api-platform/core": "dev-master",
+ "friendsofsymfony/rest-bundle": "^2.0"
},
"suggest": {
"nelmio/api-doc-bundle": "For using the ApiDoc annotation.",
"phpdocumentor/reflection-docblock": "For parsing php docs.",
"zircote/swagger-php": "For using swagger annotations.",
- "api-platform/core": "For using an API oriented framework."
+ "api-platform/core": "For using an API oriented framework.",
+ "friendsofsymfony/rest-bundle": "For using the parameters annotations."
},
"autoload": {
"psr-4": {