From d522236cec17d90c7189892a6a691858a23b63a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Simon=20Maria=20M=C3=B6llers?= Date: Mon, 10 Jul 2017 18:34:43 +0200 Subject: [PATCH] Symfony generator enhancements (#6016) * Fix error in Symfony models #5985 * Parse Symfony params #5985 * Implement auth metods in Symfony #5985 * Make "get" to "is" in Symfony's booleans #5985 * Use `camelize` instead of `initialCaps` in Symfony #5985 * Use File.separator instead of "/" in PHP/Symfony #5985 * Improve README generation for Symfony #5985 * Create an options test for Symfony #5985 --- .../codegen/languages/AbstractPhpCodegen.java | 24 +- .../languages/SymfonyServerCodegen.java | 64 +++-- .../resources/php-symfony/Controller.mustache | 270 +++++++++++++----- .../resources/php-symfony/README.mustache | 114 +++++--- .../main/resources/php-symfony/api.mustache | 11 + .../php-symfony/api_controller.mustache | 39 ++- .../resources/php-symfony/api_doc.mustache | 73 +++-- .../php-symfony/model_generic.mustache | 19 +- .../options/SymfonyServerOptionsProvider.java | 59 ++++ .../PhpSymfonyServerOptionsTest.java | 57 ++++ 10 files changed, 547 insertions(+), 183 deletions(-) create mode 100644 modules/swagger-codegen/src/test/java/io/swagger/codegen/options/SymfonyServerOptionsProvider.java create mode 100644 modules/swagger-codegen/src/test/java/io/swagger/codegen/phpsymfony/PhpSymfonyServerOptionsTest.java diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractPhpCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractPhpCodegen.java index f38e692c6bf..28a6d4fb996 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractPhpCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractPhpCodegen.java @@ -45,8 +45,8 @@ public abstract class AbstractPhpCodegen extends DefaultCodegen implements Codeg protected String apiDirName = "Api"; protected String modelDirName = "Model"; protected String variableNamingConvention= "snake_case"; - protected String apiDocPath = docsBasePath + "/" + apiDirName; - protected String modelDocPath = docsBasePath + "/" + modelDirName; + protected String apiDocPath = docsBasePath + File.separator + apiDirName; + protected String modelDocPath = docsBasePath + File.separator + modelDirName; public AbstractPhpCodegen() { super(); @@ -198,10 +198,10 @@ public abstract class AbstractPhpCodegen extends DefaultCodegen implements Codeg additionalProperties.put("escapedInvokerPackage", invokerPackage.replace("\\", "\\\\")); // make api and model src path available in mustache template - additionalProperties.put("apiSrcPath", "./" + toSrcPath(apiPackage, srcBasePath)); - additionalProperties.put("modelSrcPath", "./" + toSrcPath(modelPackage, srcBasePath)); - additionalProperties.put("apiTestPath", "./" + testBasePath + "/" + apiDirName); - additionalProperties.put("modelTestPath", "./" + testBasePath + "/" + modelDirName); + additionalProperties.put("apiSrcPath", "." + File.separator + toSrcPath(apiPackage, srcBasePath)); + additionalProperties.put("modelSrcPath", "." + File.separator + toSrcPath(modelPackage, srcBasePath)); + additionalProperties.put("apiTestPath", "." + File.separator + testBasePath + File.separator + apiDirName); + additionalProperties.put("modelTestPath", "." + File.separator + testBasePath + File.separator + modelDirName); // make api and model doc path available in mustache template additionalProperties.put("apiDocPath", apiDocPath); @@ -261,32 +261,32 @@ public abstract class AbstractPhpCodegen extends DefaultCodegen implements Codeg @Override public String apiFileFolder() { - return (outputFolder + "/" + toPackagePath(apiPackage, srcBasePath)); + return (outputFolder + File.separator + toPackagePath(apiPackage, srcBasePath)); } @Override public String modelFileFolder() { - return (outputFolder + "/" + toPackagePath(modelPackage, srcBasePath)); + return (outputFolder + File.separator + toPackagePath(modelPackage, srcBasePath)); } @Override public String apiTestFileFolder() { - return (outputFolder + "/" + getPackagePath() + "/" + testBasePath + "/" + apiDirName); + return (outputFolder + File.separator + getPackagePath() + File.separator + testBasePath + File.separator + apiDirName); } @Override public String modelTestFileFolder() { - return (outputFolder + "/" + getPackagePath() + "/" + testBasePath + "/" + modelDirName); + return (outputFolder + File.separator + getPackagePath() + File.separator + testBasePath + File.separator + modelDirName); } @Override public String apiDocFileFolder() { - return (outputFolder + "/" + getPackagePath() + "/" + apiDocPath); + return (outputFolder + File.separator + getPackagePath() + File.separator + apiDocPath); } @Override public String modelDocFileFolder() { - return (outputFolder + "/" + getPackagePath() + "/" + modelDocPath); + return (outputFolder + File.separator + getPackagePath() + File.separator + modelDocPath); } @Override diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SymfonyServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SymfonyServerCodegen.java index cbac5e779af..05d4ba7ddd6 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SymfonyServerCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SymfonyServerCodegen.java @@ -16,7 +16,6 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC @SuppressWarnings("hiding") static Logger LOGGER = LoggerFactory.getLogger(SymfonyServerCodegen.class); - public static final String VARIABLE_NAMING_CONVENTION = "variableNamingConvention"; public static final String BUNDLE_NAME = "bundleName"; public static final String COMPOSER_VENDOR_NAME = "composerVendorName"; public static final String COMPOSER_PROJECT_NAME = "composerProjectName"; @@ -66,9 +65,9 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC setBundleName("SwaggerServer"); packagePath = "SymfonyBundle-php"; modelDirName = "Model"; - docsBasePath = "Resources/docs"; - apiDocPath = docsBasePath + "/" + apiDirName; - modelDocPath = docsBasePath + "/" + modelDirName; + docsBasePath = "Resources" + File.separator + "docs"; + apiDocPath = docsBasePath + File.separator + apiDirName; + modelDocPath = docsBasePath + File.separator + modelDirName; outputFolder = "generated-code" + File.separator + "php"; apiTemplateFiles.put("api_controller.mustache", ".php"); modelTestTemplateFiles.put("model_test.mustache", ".php"); @@ -153,7 +152,7 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC public String controllerFileFolder() { - return (outputFolder + "/" + toPackagePath(controllerPackage, srcBasePath)); + return (outputFolder + File.separator + toPackagePath(controllerPackage, srcBasePath)); } @Override @@ -219,16 +218,6 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC additionalProperties.put(COMPOSER_VENDOR_NAME, composerVendorName); } - if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_VERSION)) { - this.setArtifactVersion((String) additionalProperties.get(CodegenConstants.ARTIFACT_VERSION)); - } else { - additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion); - } - - if (additionalProperties.containsKey(VARIABLE_NAMING_CONVENTION)) { - this.setParameterNamingConvention((String) additionalProperties.get(VARIABLE_NAMING_CONVENTION)); - } - additionalProperties.put("escapedInvokerPackage", invokerPackage.replace("\\", "\\\\")); additionalProperties.put("controllerPackage", controllerPackage); additionalProperties.put("apiTestsPackage", apiTestsPackage); @@ -241,13 +230,13 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC additionalProperties.put("bundleAlias", bundleAlias); // make api and model src path available in mustache template - additionalProperties.put("apiSrcPath", "./" + toSrcPath(apiPackage, srcBasePath)); - additionalProperties.put("modelSrcPath", "./" + toSrcPath(modelPackage, srcBasePath)); - additionalProperties.put("testsSrcPath", "./" + toSrcPath(testsPackage, srcBasePath)); - additionalProperties.put("apiTestsSrcPath", "./" + toSrcPath(apiTestsPackage, srcBasePath)); - additionalProperties.put("modelTestsSrcPath", "./" + toSrcPath(modelTestsPackage, srcBasePath)); - additionalProperties.put("apiTestPath", "./" + testsDirName + "/" + apiDirName); - additionalProperties.put("modelTestPath", "./" + testsDirName + "/" + modelDirName); + additionalProperties.put("apiSrcPath", "." + File.separator + toSrcPath(apiPackage, srcBasePath)); + additionalProperties.put("modelSrcPath", "." + File.separator + toSrcPath(modelPackage, srcBasePath)); + additionalProperties.put("testsSrcPath", "." + File.separator + toSrcPath(testsPackage, srcBasePath)); + additionalProperties.put("apiTestsSrcPath", "." + File.separator + toSrcPath(apiTestsPackage, srcBasePath)); + additionalProperties.put("modelTestsSrcPath", "." + File.separator + toSrcPath(modelTestsPackage, srcBasePath)); + additionalProperties.put("apiTestPath", "." + File.separator + testsDirName + File.separator + apiDirName); + additionalProperties.put("modelTestPath", "." + File.separator + testsDirName + File.separator + modelDirName); // make api and model doc path available in mustache template additionalProperties.put("apiDocPath", apiDocPath); @@ -256,15 +245,18 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC // make test path available in mustache template additionalProperties.put("testsDirName", testsDirName); + final String configDir = getPackagePath() + File.separator + "Resources" + File.separator + "config"; + final String dependencyInjectionDir = getPackagePath() + File.separator + "DependencyInjection"; + supportingFiles.add(new SupportingFile("Controller.mustache", toPackagePath(controllerPackage, srcBasePath), "Controller.php")); supportingFiles.add(new SupportingFile("Bundle.mustache", getPackagePath(), bundleClassName + ".php")); - supportingFiles.add(new SupportingFile("Extension.mustache", getPackagePath() + "/DependencyInjection", bundleExtensionName + ".php")); - supportingFiles.add(new SupportingFile("ApiPass.mustache", getPackagePath() + "/DependencyInjection/Compiler", bundleName + "ApiPass.php")); + supportingFiles.add(new SupportingFile("Extension.mustache", dependencyInjectionDir, bundleExtensionName + ".php")); + supportingFiles.add(new SupportingFile("ApiPass.mustache", dependencyInjectionDir + File.separator + "Compiler", bundleName + "ApiPass.php")); supportingFiles.add(new SupportingFile("ApiServer.mustache", toPackagePath(apiPackage, srcBasePath), "ApiServer.php")); supportingFiles.add(new SupportingFile("ModelSerializer.mustache", toPackagePath(modelPackage, srcBasePath), "ModelSerializer.php")); supportingFiles.add(new SupportingFile("ModelInterface.mustache", toPackagePath(modelPackage, srcBasePath), "ModelInterface.php")); - supportingFiles.add(new SupportingFile("routing.mustache", getPackagePath() + "/Resources/config", "routing.yml")); - supportingFiles.add(new SupportingFile("services.mustache", getPackagePath() + "/Resources/config", "services.yml")); + supportingFiles.add(new SupportingFile("routing.mustache", configDir, "routing.yml")); + supportingFiles.add(new SupportingFile("services.mustache", configDir, "services.yml")); supportingFiles.add(new SupportingFile("composer.mustache", getPackagePath(), "composer.json")); supportingFiles.add(new SupportingFile("autoload.mustache", getPackagePath(), "autoload.php")); supportingFiles.add(new SupportingFile("README.mustache", getPackagePath(), "README.md")); @@ -281,6 +273,7 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC operations.put("controllerName", toControllerName((String) operations.get("pathPrefix"))); operations.put("symfonyService", toSymfonyService((String) operations.get("pathPrefix"))); + HashSet authMethods = new HashSet<>(); HashSet imports = new HashSet<>(); List operationList = (List) operations.get("operation"); for (CodegenOperation op : operationList) { @@ -310,9 +303,15 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC imports.add(exception); } } + + // Add operation's authentication methods to whole interface + if (op.authMethods != null) { + authMethods.addAll(op.authMethods); + } } operations.put("imports", new ArrayList<>(imports)); + operations.put("authMethods", authMethods); return objs; } @@ -332,11 +331,16 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC final String importType = var.datatype.replaceFirst("\\[\\]$", ""); final String dataType = extractSimpleName(var.datatype); final boolean isScalarType = typeMapping.containsValue(importType); + var.vendorExtensions.put("x-fullType", var.datatype); if (!isScalarType) { var.vendorExtensions.put("x-typeAnnotation", dataType.endsWith("[]") ? "array" : dataType); imports.add(importType); var.datatype = dataType; } + + if (var.isBoolean) { + var.getter = var.getter.replaceAll("^get", "is"); + } } } @@ -355,12 +359,12 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC @Override public String apiTestFileFolder() { - return (outputFolder + "/" + toPackagePath(apiTestsPackage, srcBasePath)); + return (outputFolder + File.separator + toPackagePath(apiTestsPackage, srcBasePath)); } @Override public String modelTestFileFolder() { - return (outputFolder + "/" + toPackagePath(modelTestsPackage, srcBasePath)); + return (outputFolder + File.separator + toPackagePath(modelTestsPackage, srcBasePath)); } public void setComposerVendorName(String composerVendorName) { @@ -429,14 +433,14 @@ public class SymfonyServerCodegen extends AbstractPhpCodegen implements CodegenC if (name.isEmpty()) { return "DefaultApiInterface"; } - return initialCaps(name) + "ApiInterface"; + return camelize(name, false) + "ApiInterface"; } protected String toControllerName(String name) { if (name.isEmpty()) { return "DefaultController"; } - return initialCaps(name) + "Controller"; + return camelize(name, false) + "Controller"; } protected String toSymfonyService(String name) { diff --git a/modules/swagger-codegen/src/main/resources/php-symfony/Controller.mustache b/modules/swagger-codegen/src/main/resources/php-symfony/Controller.mustache index e5561f01345..af937c7d99f 100644 --- a/modules/swagger-codegen/src/main/resources/php-symfony/Controller.mustache +++ b/modules/swagger-codegen/src/main/resources/php-symfony/Controller.mustache @@ -34,83 +34,209 @@ use Symfony\Component\HttpKernel\Exception\HttpException; class Controller extends BaseController { - /** - * This will return a response with code 400. Usage example: - * - * return $this->createBadRequestResponse('Unable to access this page!'); - * - * @param string $message A message - * - * @return Response - */ - public function createBadRequestResponse($message = 'Bad Request.') - { - return new Response($message, 400); - } + /** + * This will return a response with code 400. Usage example: + * return $this->createBadRequestResponse('Unable to access this page!'); + * + * @param string $message A message + * + * @return Response + */ + public function createBadRequestResponse($message = 'Bad Request.') + { + return new Response($message, 400); + } - /** - * This will return an error response. Usage example: - * - * return $this->createErrorResponse(new UnauthorizedHttpException()); - * - * @param HttpException $exception An HTTP exception - * - * @return Response - */ - public function createErrorResponse(HttpException $exception) - { - $statusCode = $exception->getStatusCode(); - $headers = array_merge($exception->getHeaders(), ['Content-Type' => 'application/json']); + /** + * This will return an error response. Usage example: + * return $this->createErrorResponse(new UnauthorizedHttpException()); + * + * @param HttpException $exception An HTTP exception + * + * @return Response + */ + public function createErrorResponse(HttpException $exception) + { + $statusCode = $exception->getStatusCode(); + $headers = array_merge($exception->getHeaders(), ['Content-Type' => 'application/json']); - $json = $this->exceptionToArray($exception); - $json["statusCode"] = $statusCode; + $json = $this->exceptionToArray($exception); + $json['statusCode'] = $statusCode; - return new Response(json_encode($json, 15, 512), $statusCode, $headers); - } + return new Response(json_encode($json, 15, 512), $statusCode, $headers); + } - /** - * Serializes data to a given type format. - * - * @param mixed $data The data to serialize. - * @param string $class The source data class. - * @param string $format The target serialization format. - * @return string A serialized data string. - */ - public function serialize($data, $format) - { - return $this->get('{{bundleAlias}}.model.model_serializer')->serialize($data, $format); - } + /** + * Serializes data to a given type format. + * + * @param mixed $data The data to serialize. + * @param string $class The source data class. + * @param string $format The target serialization format. + * + * @return string A serialized data string. + */ + public function serialize($data, $format) + { + return $this->get('{{bundleAlias}}.model.model_serializer')->serialize($data, $format); + } - /** - * Deserializes data from a given type format. - * - * @param string $data The data to deserialize. - * @param string $class The target data class. - * @param string $format The source serialization format. - * @return mixed A deserialized data. - */ - public function deserialize($data, $class, $format) - { - return $this->get('{{bundleAlias}}.model.model_serializer')->deserialize($data, $class, $format); - } + /** + * Deserializes data from a given type format. + * + * @param string $data The data to deserialize. + * @param string $class The target data class. + * @param string $format The source serialization format. + * + * @return mixed A deserialized data. + */ + public function deserialize($data, $class, $format) + { + return $this->get('{{bundleAlias}}.model.model_serializer')->deserialize($data, $class, $format); + } - /** - * Converts an exception to a serializable array. - * - * @param \Exception|null $exception - * - * @return array - */ - private function exceptionToArray(\Exception $exception = null) - { - if (null === $exception) { - return null; - } + /** + * Decodes a string value. + * + * @param string $string The string value to decode. + * @param string $dataType The data type of the parameter. + * + * @return mixed The decoded value. + */ + public function fromString($string, $dataType) + { + if ($dataType === 'integer' || $dataType === 'number') { + return $this->toNumber($string); + } + if ($dataType === 'bool') { + return $this->toBoolean($string); + } + if ($dataType === '\DateTime') { + return $this->toDateTime($string); + } - return [ - "message" => $exception->getMessage(), - "type" => get_class($exception), - "previous" => $this->exceptionToArray($exception->getPrevious()), - ]; - } + return $string; + } + + /** + * Decodes a header value. + * + * @param string $header The header value to decode. + * @param string $dataType The data type of the parameter. + * + * @return mixed The decoded value. + */ + public function fromHeader($header, $dataType) + { + return $this->fromString($header, $dataType); + } + + /** + * Decodes a query value. + * + * @param string $query The query value to decode. + * @param string $dataType The data type of the parameter. + * + * @return mixed The decoded value. + */ + public function fromQuery($query, $dataType) + { + return $this->fromString($query, $dataType); + } + + /** + * Decodes a path value. + * + * @param string $path The path value to decode. + * @param string $dataType The data type of the parameter. + * + * @return mixed The decoded value. + */ + public function fromPath($path, $dataType) + { + return $this->fromString($path, $dataType); + } + + /** + * Decodes a form value. + * + * @param string $form The form value to decode. + * @param string $dataType The data type of the parameter. + * + * @return mixed The decoded value. + */ + public function fromForm($form, $dataType) + { + return $this->fromString($form, $dataType); + } + + /** + * Decoded a string to a number. + * + * @param string $string The string to decode. + * + * @return number|null A decoded number, or null, if not a valid string. + */ + private function toNumber($string) + { + if (is_numeric($string)) { + return $string + 0; + } + + return null; + } + + /** + * Decoded a string to a boolean. + * + * @param string $string The string to decode. + * + * @return boolean|null A decoded boolean, or null, if not a valid string. + */ + private function toBoolean($string) + { + if ($string === 'true') { + return true; + } + if ($string === 'false') { + return false; + } + + return null; + } + + /** + * Decoded a string to a date time. + * + * @param string $string The string to decode. + * + * @return \DateTime|null A decoded date time, or null, if not a valid string. + */ + private function toDateTime($string) + { + if ($dateTime = date_create($string)) { + return $dateTime; + } + + return null; + } + + /** + * Converts an exception to a serializable array. + * + * @param \Exception|null $exception + * + * @return array + */ + private function exceptionToArray(\Exception $exception = null) + { + if (null === $exception) { + return null; + } + + return [ + 'message' => $exception->getMessage(), + 'type' => get_class($exception), + 'previous' => $this->exceptionToArray($exception->getPrevious()), + ]; + } } diff --git a/modules/swagger-codegen/src/main/resources/php-symfony/README.mustache b/modules/swagger-codegen/src/main/resources/php-symfony/README.mustache index ab0da1711f2..d61acfa1c84 100644 --- a/modules/swagger-codegen/src/main/resources/php-symfony/README.mustache +++ b/modules/swagger-codegen/src/main/resources/php-symfony/README.mustache @@ -1,9 +1,9 @@ -# {{packagePath}} +# {{bundleName}} {{#appDescription}} {{{appDescription}}} {{/appDescription}} -This PHP package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: +This [Symfony](https://symfony.com/) bundle is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: - API version: {{appVersion}} {{#artifactVersion}} @@ -22,7 +22,6 @@ For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) PHP 5.4.0 and later ## Installation & Usage -### Composer To install the bindings via [Composer](http://getcomposer.org/), add the following to `composer.json`: @@ -42,13 +41,6 @@ To install the bindings via [Composer](http://getcomposer.org/), add the followi Then run `composer install` -### Manual Installation - -Download the files and include `autoload.php`: - -```php - require_once('/path/to/{{packagePath}}/autoload.php'); -``` ## Tests @@ -59,39 +51,93 @@ composer install ./vendor/bin/phpunit ``` + ## Getting Started -Please follow the [installation procedure](#installation--usage) and then run the following: +Step 1: Please follow the [installation procedure](#installation--usage) first. + +Step 2: Enable the bundle in the kernel: ```php setUsername('YOUR_USERNAME'); -{{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setPassword('YOUR_PASSWORD');{{/isBasic}}{{#isApiKey}} -// Configure API key authorization: {{{name}}} -{{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKey('{{{keyParamName}}}', 'YOUR_API_KEY'); -// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -// {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKeyPrefix('{{{keyParamName}}}', 'Bearer');{{/isApiKey}}{{#isOAuth}} -// Configure OAuth2 access token for authorization: {{{name}}} -{{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setAccessToken('YOUR_ACCESS_TOKEN');{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} +// app/AppKernel.php -$api_instance = new {{invokerPackage}}\Api\{{classname}}(); -{{#allParams}}${{paramName}} = {{{example}}}; // {{{dataType}}} | {{{description}}} -{{/allParams}} - -try { - {{#returnType}}$result = {{/returnType}}$api_instance->{{{operationId}}}({{#allParams}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{#returnType}} - print_r($result);{{/returnType}} -} catch (Exception $e) { - echo 'Exception when calling {{classname}}->{{operationId}}: ', $e->getMessage(), PHP_EOL; +public function registerBundles() +{ + $bundles = array( + // ... + new {{invokerPackage}}\{{bundleClassName}}(), + // ... + ); } -{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}} -?> ``` +Step 3: Register the routes: + +```yaml +# app/config/routing.yml +{{bundleAlias}}: + resource: "@{{bundleName}}Bundle/Resources/config/routing.yml" +``` + +Step 4: Implement the API calls: + +```php +headers->get('{{keyParamName}}'); + {{/isKeyInHeader}} + {{#isKeyInQuery}} + // Set key with prefix in query string + $security{{name}} = $request->query->get('{{keyParamName}}'); + {{/isKeyInQuery}} + {{/isApiKey}} + {{#isBasic}} + // HTTP basic authentication required + $security{{name}} = $request->headers->get('authorization'); + {{/isBasic}} + {{#isOAuth}} + // Oauth required + $security{{name}} = $request->headers->get('authorization'); + {{/isOAuth}} + {{/authMethods}} {{#queryParams}} // Handle query params - ${{paramName}} = $request->query->get('{{paramName}}'); + ${{paramName}} = $this->fromQuery($request->query->get('{{paramName}}'), '{{dataType}}'); {{/queryParams}} {{#headerParams}} // Handle header params - ${{paramName}} = $request->headers->get('{{paramName}}'); + ${{paramName}} = $this->fromHeader($request->headers->get('{{paramName}}'), '{{dataType}}'); {{/headerParams}} {{#pathParams}} // Handle path params - ${{paramName}} = $request->attributes->get('{{paramName}}'); + ${{paramName}} = $this->fromPath($request->attributes->get('{{paramName}}'), '{{dataType}}'); {{/pathParams}} {{#formParams}} {{#isFile}} @@ -74,7 +95,7 @@ class {{controllerName}} extends Controller {{/isFile}} {{^isFile}} // Handle form params - ${{paramName}} = $request->request->get('{{paramName}}'); + ${{paramName}} = $this->fromForm($request->request->get('{{paramName}}'), '{{dataType}}'); {{/isFile}} {{/formParams}} {{#bodyParams}} @@ -131,9 +152,15 @@ class {{controllerName}} extends Controller // Call the API interface try { + $handler = $this->getApiHandler(); + + {{#authMethods}} + // Set authentication method '{{name}}' + $handler->set{{name}}($security{{name}}); + {{/authMethods}} {{#returnType}} // Expecting a return value (exception otherwise) - $result = $this->getApiHandler()->{{operationId}}({{#allParams}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); + $result = $handler->{{operationId}}({{#allParams}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); {{#responses}} {{^vendorExtensions.x-symfonyExceptionSimple}} @@ -148,7 +175,7 @@ class {{controllerName}} extends Controller {{/returnType}} {{^returnType}} // No return type expected; return empty response - $this->getApiHandler()->{{operationId}}({{#allParams}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); + $handler->{{operationId}}({{#allParams}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); return new Response('', 204); {{/returnType}} {{#responses}} diff --git a/modules/swagger-codegen/src/main/resources/php-symfony/api_doc.mustache b/modules/swagger-codegen/src/main/resources/php-symfony/api_doc.mustache index 75ec5f8acd8..e5cd83f2f42 100644 --- a/modules/swagger-codegen/src/main/resources/php-symfony/api_doc.mustache +++ b/modules/swagger-codegen/src/main/resources/php-symfony/api_doc.mustache @@ -1,4 +1,4 @@ -# {{invokerPackage}}\{{classname}}{{#description}} +# {{apiPackage}}\{{classname}}{{#description}} {{description}}{{/description}} All URIs are relative to *{{basePath}}* @@ -9,41 +9,66 @@ Method | HTTP request | Description {{/operation}}{{/operations}} {{#operations}} +## Service Declaration +```yaml +# src/Acme/MyBundle/Resources/services.yml +services: + # ... + acme.my_bundle.api.{{pathPrefix}}: + class: Acme\MyBundle\Api\{{baseName}}Api + tags: + - { name: "{{bundleAlias}}.api", api: "{{pathPrefix}}" } + # ... +``` + {{#operation}} -# **{{{operationId}}}** +## **{{{operationId}}}** > {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#allParams}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) {{{summary}}}{{#notes}} {{{notes}}}{{/notes}} -### Example +### Example Implementation ```php setUsername('YOUR_USERNAME'); -{{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setPassword('YOUR_PASSWORD');{{/isBasic}}{{#isApiKey}} -// Configure API key authorization: {{{name}}} -{{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKey('{{{keyParamName}}}', 'YOUR_API_KEY'); -// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -// {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKeyPrefix('{{{keyParamName}}}', 'Bearer');{{/isApiKey}}{{#isOAuth}} -// Configure OAuth2 access token for authorization: {{{name}}} -{{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setAccessToken('YOUR_ACCESS_TOKEN');{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} +// src/Acme/MyBundle/Api/{{classname}}.php -$api_instance = new {{invokerPackage}}\Api\{{classname}}(); -{{#allParams}}${{paramName}} = {{{example}}}; // {{{dataType}}} | {{{description}}} -{{/allParams}} +namespace Acme\MyBundle\Api; -try { - {{#returnType}}$result = {{/returnType}}$api_instance->{{{operationId}}}({{#allParams}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{#returnType}} - print_r($result);{{/returnType}} -} catch (Exception $e) { - echo 'Exception when calling {{classname}}->{{operationId}}: ', $e->getMessage(), PHP_EOL; +use {{apiPackage}}\{{classname}}; + +class {{baseName}}Api implements {{classname}} +{ +{{#authMethods}}{{#isApiKey}} + /** + * Configure API key authorization: {{{name}}} + */ + public function set{{name}}($apiKey) + { + // Retrieve logged in user from $apiKey ... + } +{{/isApiKey}}{{#isOAuth}} + /** + * Configure OAuth2 access token for authorization: {{{name}}} + */ + public function set{{name}}($oauthToken) + { + // Retrieve logged in user from $oauthToken ... + } +{{/isOAuth}}{{/authMethods}} + // ... + + /** + * Implementation of {{classname}}#{{operationId}} + */ + public function {{operationId}}({{#allParams}}{{#vendorExtensions.x-parameterType}}{{vendorExtensions.x-parameterType}} {{/vendorExtensions.x-parameterType}}${{paramName}}{{^required}} = {{#defaultValue}}'{{{.}}}'{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) + { + // Implement the operation ... + } + + // ... } -?> ``` ### Parameters diff --git a/modules/swagger-codegen/src/main/resources/php-symfony/model_generic.mustache b/modules/swagger-codegen/src/main/resources/php-symfony/model_generic.mustache index b00366590c2..165a96adc06 100644 --- a/modules/swagger-codegen/src/main/resources/php-symfony/model_generic.mustache +++ b/modules/swagger-codegen/src/main/resources/php-symfony/model_generic.mustache @@ -13,11 +13,14 @@ class {{classname}} {{#parentSchema}}extends {{{parent}}} {{/parentSchema}}imple * @var array[] */ protected static $_attributes = [{{#vars}} - '{{name}}' => ['{{baseName}}', '{{{datatype}}}', {{#dataFormat}}'{{{dataFormat}}}'{{/dataFormat}}{{^dataFormat}}null{{/dataFormat}}, '{{setter}}', '{{getter}}'],{{/vars}} + '{{name}}' => ['{{baseName}}', '{{{vendorExtensions.x-fullType}}}', {{#dataFormat}}'{{{dataFormat}}}'{{/dataFormat}}{{^dataFormat}}null{{/dataFormat}}, '{{setter}}', '{{getter}}'],{{/vars}} ]; - {{#vars}}{{#isEnum}}{{#allowableValues}}{{#enumVars}} - const {{enumName}}_{{{name}}} = {{{value}}}; - {{/enumVars}}{{/allowableValues}}{{/isEnum}}{{/vars}} + {{#vars}}{{#isEnum}} + + /** + * Allowed values of {{name}} + */{{#allowableValues}}{{#enumVars}} + const {{enumName}}_{{{name}}} = {{{value}}};{{/enumVars}}{{/allowableValues}}{{/isEnum}}{{/vars}} {{#vars}}{{#isEnum}} /** @@ -33,7 +36,10 @@ class {{classname}} {{#parentSchema}}extends {{{parent}}} {{/parentSchema}}imple } {{/isEnum}}{{/vars}} {{#vars}} - /** + /**{{#description}} + * {{description}} + * + {{/description}} * @var {{{datatype}}}{{^required}}|null{{/required}} */ protected ${{name}}; @@ -237,6 +243,7 @@ class {{classname}} {{#parentSchema}}extends {{{parent}}} {{/parentSchema}}imple /** * Gets {{name}}. + * * @return {{{datatype}}}{{^required}}|null{{/required}} */ public function {{getter}}() @@ -246,7 +253,9 @@ class {{classname}} {{#parentSchema}}extends {{{parent}}} {{/parentSchema}}imple /** * Sets {{name}}. + * * @param {{{datatype}}}{{^required}}|null{{/required}} ${{name}}{{#description}} {{{description}}}{{/description}} + * * @return $this */ public function {{setter}}({{#vendorExtensions.x-typeAnnotation}}{{vendorExtensions.x-typeAnnotation}} {{/vendorExtensions.x-typeAnnotation}}${{name}}{{^required}} = null{{/required}}) diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/SymfonyServerOptionsProvider.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/SymfonyServerOptionsProvider.java new file mode 100644 index 00000000000..4e975100f5e --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/SymfonyServerOptionsProvider.java @@ -0,0 +1,59 @@ +package io.swagger.codegen.options; + +import com.google.common.collect.ImmutableMap; +import io.swagger.codegen.CodegenConstants; +import io.swagger.codegen.languages.SymfonyServerCodegen; +import io.swagger.codegen.languages.SymfonyServerCodegen; + +import java.util.Map; + +public class SymfonyServerOptionsProvider implements OptionsProvider { + public static final String BUNDLE_NAME_VALUE = "AcmeSwagger"; + public static final String MODEL_PACKAGE_VALUE = "package"; + public static final String API_PACKAGE_VALUE = "apiPackage"; + public static final String SORT_PARAMS_VALUE = "false"; + public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true"; + public static final String VARIABLE_NAMING_CONVENTION_VALUE = "snake_case"; + public static final String INVOKER_PACKAGE_VALUE = "Acme\\Bundle\\SwaggerBundle"; + public static final String PACKAGE_PATH_VALUE = "SwaggerClient-php"; + public static final String SRC_BASE_PATH_VALUE = "libPhp"; + public static final String COMPOSER_VENDOR_NAME_VALUE = "swaggerPhp"; + public static final String COMPOSER_PROJECT_NAME_VALUE = "swagger-client-php"; + public static final String GIT_USER_ID_VALUE = "gitSwaggerPhp"; + public static final String GIT_REPO_ID_VALUE = "git-swagger-client-php"; + public static final String ARTIFACT_VERSION_VALUE = "1.0.0-SNAPSHOT"; + public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false"; + + + @Override + public String getLanguage() { + return "php-symfony"; + } + + @Override + public Map createOptions() { + ImmutableMap.Builder builder = new ImmutableMap.Builder(); + return builder.put(CodegenConstants.MODEL_PACKAGE, MODEL_PACKAGE_VALUE) + .put(SymfonyServerCodegen.BUNDLE_NAME, BUNDLE_NAME_VALUE) + .put(CodegenConstants.API_PACKAGE, API_PACKAGE_VALUE) + .put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE) + .put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE) + .put(SymfonyServerCodegen.VARIABLE_NAMING_CONVENTION, VARIABLE_NAMING_CONVENTION_VALUE) + .put(CodegenConstants.INVOKER_PACKAGE, INVOKER_PACKAGE_VALUE) + .put(SymfonyServerCodegen.PACKAGE_PATH, PACKAGE_PATH_VALUE) + .put(SymfonyServerCodegen.SRC_BASE_PATH, SRC_BASE_PATH_VALUE) + .put(SymfonyServerCodegen.COMPOSER_VENDOR_NAME, COMPOSER_VENDOR_NAME_VALUE) + .put(CodegenConstants.GIT_USER_ID, GIT_USER_ID_VALUE) + .put(SymfonyServerCodegen.COMPOSER_PROJECT_NAME, COMPOSER_PROJECT_NAME_VALUE) + .put(CodegenConstants.GIT_REPO_ID, GIT_REPO_ID_VALUE) + .put(CodegenConstants.ARTIFACT_VERSION, ARTIFACT_VERSION_VALUE) + .put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "true") + .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) + .build(); + } + + @Override + public boolean isServer() { + return true; + } +} diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/phpsymfony/PhpSymfonyServerOptionsTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/phpsymfony/PhpSymfonyServerOptionsTest.java new file mode 100644 index 00000000000..24727df8f0a --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/phpsymfony/PhpSymfonyServerOptionsTest.java @@ -0,0 +1,57 @@ +package io.swagger.codegen.phpsymfony; + +import io.swagger.codegen.AbstractOptionsTest; +import io.swagger.codegen.CodegenConfig; +import io.swagger.codegen.languages.AbstractPhpCodegen; +import io.swagger.codegen.languages.SymfonyServerCodegen; +import io.swagger.codegen.options.SymfonyServerOptionsProvider; +import mockit.Expectations; +import mockit.Tested; + +public class PhpSymfonyServerOptionsTest extends AbstractOptionsTest { + + @Tested + private SymfonyServerCodegen symfonyCodegen; + + public PhpSymfonyServerOptionsTest() { + super(new SymfonyServerOptionsProvider()); + } + + @Override + protected CodegenConfig getCodegenConfig() { + return symfonyCodegen; + } + + @SuppressWarnings("unused") + @Override + protected void setExpectations() { + new Expectations(symfonyCodegen) {{ + symfonyCodegen.setBundleName(SymfonyServerOptionsProvider.BUNDLE_NAME_VALUE); + times = 1; + symfonyCodegen.setModelPackage(SymfonyServerOptionsProvider.MODEL_PACKAGE_VALUE); + times = 1; + symfonyCodegen.setApiPackage(SymfonyServerOptionsProvider.API_PACKAGE_VALUE); + times = 1; + symfonyCodegen.setSortParamsByRequiredFlag(Boolean.valueOf(SymfonyServerOptionsProvider.SORT_PARAMS_VALUE)); + times = 1; + symfonyCodegen.setParameterNamingConvention(SymfonyServerOptionsProvider.VARIABLE_NAMING_CONVENTION_VALUE); + times = 1; + symfonyCodegen.setInvokerPackage(SymfonyServerOptionsProvider.INVOKER_PACKAGE_VALUE); + times = 1; + symfonyCodegen.setPackagePath(SymfonyServerOptionsProvider.PACKAGE_PATH_VALUE); + times = 1; + symfonyCodegen.setSrcBasePath(SymfonyServerOptionsProvider.SRC_BASE_PATH_VALUE); + times = 1; + symfonyCodegen.setComposerVendorName(SymfonyServerOptionsProvider.COMPOSER_VENDOR_NAME_VALUE); + times = 1; + symfonyCodegen.setGitUserId(SymfonyServerOptionsProvider.GIT_USER_ID_VALUE); + times = 1; + symfonyCodegen.setComposerProjectName(SymfonyServerOptionsProvider.COMPOSER_PROJECT_NAME_VALUE); + times = 1; + symfonyCodegen.setGitRepoId(SymfonyServerOptionsProvider.GIT_REPO_ID_VALUE); + times = 1; + symfonyCodegen.setArtifactVersion(SymfonyServerOptionsProvider.ARTIFACT_VERSION_VALUE); + times = 1; + }}; + } +}