Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions bin/windows/ze-ph-petstore.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar

If Not Exist %executable% (
mvn clean package
)

REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
set ags=generate -i modules\swagger-codegen\src\test\resources\2_0\petstore.json -l ze-ph -o samples\client\petstore\ze-ph
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI. I'll update this line to use modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml and output the generated code under samples\server\petstore\ze-ph instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, thanks for noticing) And sorry for not checking this "copy-paste" from bin/windows/php-petstore.bat thoroughly. For actual testing I used IDEA's "Run/Debug configuration".


java %JAVA_OPTS% -jar %executable% %ags%
31 changes: 31 additions & 0 deletions bin/ze-ph-petstore-server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

SCRIPT="$0"

while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi

executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"

if [ ! -f "$executable" ]
then
mvn clean package
fi

# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="$@ generate -t modules/swagger-codegen/src/main/resources/ze-ph -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l ze-ph -o samples/server/petstore/ze-ph"

java $JAVA_OPTS -jar $executable $ags
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package io.swagger.codegen.languages;

import io.swagger.codegen.*;
import io.swagger.models.Operation;
import org.apache.commons.lang3.StringUtils;


import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ZendExpressivePathHandlerServerCodegen extends AbstractPhpCodegen {
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}

@Override
public String getName() {
return "ze-ph";
}

@Override
public String getHelp() {
return "Generates PHP server stub using Zend Expressive ( https://zendframework.github.io/zend-expressive ) and Path Handler ( https://github.com/Articus/PathHandler ).";
}

public ZendExpressivePathHandlerServerCodegen() {
super();

embeddedTemplateDir = templateDir = "ze-ph";
invokerPackage = "App";
packagePath = "";
srcBasePath = "src" + File.separator + "App";
apiDirName = "Handler";
modelDirName = "DTO";
apiPackage = invokerPackage + "\\" + apiDirName;
modelPackage = invokerPackage + "\\" + modelDirName;

apiTestTemplateFiles.clear();
modelTestTemplateFiles.clear();
apiDocTemplateFiles.clear();
modelDocTemplateFiles.clear();

supportingFiles.add(new SupportingFile("README.md.mustache", packagePath, "README.md"));
supportingFiles.add(new SupportingFile("composer.json.mustache", packagePath, "composer.json"));
supportingFiles.add(new SupportingFile("index.php", packagePath + File.separator + "public", "index.php"));
supportingFiles.add(new SupportingFile("container.php", packagePath + File.separator + "application", "container.php"));
supportingFiles.add(new SupportingFile("config.yml", packagePath + File.separator + "application", "config.yml"));
supportingFiles.add(new SupportingFile("app.yml.mustache", packagePath + File.separator + "application" + File.separator + "config", "app.yml"));
supportingFiles.add(new SupportingFile("path_handler.yml.mustache", packagePath + File.separator + "application" + File.separator + "config", "path_handler.yml"));
supportingFiles.add(new SupportingFile("data_transfer.yml.mustache", packagePath + File.separator + "application" + File.separator + "config", "data_transfer.yml"));
supportingFiles.add(new SupportingFile("Date.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Strategy", "Date.php"));
supportingFiles.add(new SupportingFile("DateTime.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Strategy", "DateTime.php"));
supportingFiles.add(new SupportingFile("Type.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Validator", "Type.php"));
supportingFiles.add(new SupportingFile("ErrorMiddleware.php.mustache", packagePath + File.separator + srcBasePath, "ErrorMiddleware.php"));

additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, "1.0.0");
}

/**
* Add operation to group
* Override of default grouping - group by resource path, not tag
*
* @param tag name of the tag
* @param resourcePath path of the resource
* @param operation Swagger Operation object
* @param co Codegen Operation object
* @param operations map of Codegen operations
*/
@Override
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map<String, List<CodegenOperation>> operations) {
List<CodegenOperation> opList = operations.get(resourcePath);
if (opList == null) {
opList = new ArrayList<CodegenOperation>();
operations.put(resourcePath, opList);
}
//ignore duplicate operation ids - that means that operation has several tags
int counter = 0;
for (CodegenOperation op : opList) {
if (co.operationId.equals(op.operationId)) {
counter++;
}
}
if (counter == 0) {
co.operationIdLowerCase = co.operationId.toLowerCase();
opList.add(co);
co.baseName = tag;
}
}

/**
* Return the file name of the Api Test
*
* @param name the file name of the Api
* @return the file name of the Api
*/
@Override
public String toApiFilename(String name) {
return toApiName(name);
}

/**
* Output the API (class) name (capitalized) ending with "Api"
* Return DefaultApi if name is empty
*
* @param name the name of the Api
* @return capitalized Api name ending with "Api"
*/
@Override
public String toApiName(String name) {
//Remove }
name = name.replaceAll("[\\}]", "");
return super.toModelName(name);
}

@Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
objs = super.postProcessOperations(objs);
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
String interfaceToImplement;
StringBuilder interfacesToImplement = new StringBuilder();
String classMethod;
for (CodegenOperation op : operationList) {
switch (op.httpMethod) {
case "GET":
interfaceToImplement = "Operation\\GetInterface";
classMethod = "handleGet";
break;
case "POST":
interfaceToImplement = "Operation\\PostInterface";
classMethod = "handlePost";
break;
case "PATCH":
interfaceToImplement = "Operation\\PatchInterface";
classMethod = "handlePatch";
break;
case "PUT":
interfaceToImplement = "Operation\\PutInterface";
classMethod = "handlePut";
break;
case "DELETE":
interfaceToImplement = "Operation\\DeleteInterface";
classMethod = "handleDelete";
break;
default:
throw new RuntimeException("Unknown HTTP Method " + op.httpMethod + " not allowed");
}
if (interfacesToImplement.length() > 0) {
interfacesToImplement.append(", ");
}
interfacesToImplement.append(interfaceToImplement);
op.httpMethod = classMethod;
}
operations.put("interfacesToImplement", interfacesToImplement.toString());

return objs;
}

@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
objs = super.postProcessSupportingFileData(objs);

Map<String, Object> apiInfo = (Map<String, Object>) objs.get("apiInfo");
List<Map<String, Object>> apis = (List<Map<String, Object>>) apiInfo.get("apis");

List<Map<String, Object>> routes = new ArrayList<Map<String, Object>>();
for (Map<String, Object> api : apis) {
String handler = (String) api.get("classname");
String url = (String) api.get("baseName");
if (url.charAt(0) == '/') {
url = url.substring(1);
}
insertRoute(routes, url.split("/"), 0, handler);
}

objs.put("routes", routes);
return objs;
}

private void insertRoute(List<Map<String, Object>> routes, String[] urlParts, int currentUrlPartIndex, String handler) {
if (urlParts.length > currentUrlPartIndex) {
String urlPart = urlParts[currentUrlPartIndex];
//List<Map<String, Object>> subRoutes = null;
Map<String, Object> currentRoute = null;
for (Map<String, Object> route : routes) {
if (urlPart.equals(route.get("name"))) {
currentRoute = route;
break;
}
}
if (currentRoute == null) {
currentRoute = new HashMap<String, Object>();

String routePart = urlPart.replaceAll("^\\{(\\w+)\\}$", ":$1");
boolean isLastUrlPart = currentUrlPartIndex == urlParts.length - 1;

currentRoute.put("name", urlPart);
currentRoute.put("route", "/" + routePart);
currentRoute.put("type", (urlPart == routePart) ? "Literal" : "Segment");
currentRoute.put("handler", isLastUrlPart ? handler : null);
currentRoute.put("hasChildren", false);
currentRoute.put("children", new ArrayList<Map<String, Object>>());
currentRoute.put("padding", StringUtils.repeat(' ', 4 * currentUrlPartIndex));

routes.add(currentRoute);
}
List<Map<String, Object>> subRoutes = (List<Map<String, Object>>) currentRoute.get("children");
insertRoute(subRoutes, urlParts, currentUrlPartIndex + 1, handler);
currentRoute.put("hasChildren", !subRoutes.isEmpty());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,4 @@ io.swagger.codegen.languages.GoServerCodegen
io.swagger.codegen.languages.ErlangServerCodegen
io.swagger.codegen.languages.UndertowCodegen
io.swagger.codegen.languages.JavaMSF4JServerCodegen
io.swagger.codegen.languages.ZendExpressivePathHandlerServerCodegen
17 changes: 17 additions & 0 deletions modules/swagger-codegen/src/main/resources/ze-ph/Date.php.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace {{invokerPackage}}\Strategy;

class Date extends DateTime
{
const DATE_TIME_FORMAT = 'Y-m-d';

/**
* @param $arrayValue
* @return \DateTime
*/
protected function parseDateString($arrayValue)
{
return \DateTime::createFromFormat(static::DATE_TIME_FORMAT.' H:i:sP', $arrayValue.' 00:00:00+00:00', new \DateTimeZone('UTC'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace {{invokerPackage}}\Strategy;
use Articus\DataTransfer\Strategy\StrategyInterface;

class DateTime implements StrategyInterface
{
const DATE_TIME_FORMAT = \DateTime::RFC3339;
/**
* @inheritDoc
*/
public function extract($objectValue, $object = null)
{
$result = null;
if ($objectValue instanceof \DateTime) {
$result = $objectValue->format(static::DATE_TIME_FORMAT);
}
return $result;
}

/**
* @inheritDoc
*/
public function hydrate($arrayValue, $objectValue, array $array = null)
{
$result = null;
if (!empty($arrayValue)) {
$date = $this->parseDateString($arrayValue);
if ($date instanceof \DateTime) {
$result = $date;
}
}
return $result;
}

/**
* @param $arrayValue
* @return \DateTime
*/
protected function parseDateString($arrayValue)
{
return \DateTime::createFromFormat(static::DATE_TIME_FORMAT, $arrayValue, new \DateTimeZone('UTC'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
namespace {{invokerPackage}};

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Stratigility\ErrorMiddlewareInterface;

class ErrorMiddleware implements ErrorMiddlewareInterface
{
/**
* @inheritDoc
*/
public function __invoke($error, Request $request, Response $response, callable $out = null)
{
$response = $response->withStatus(500, 'Internal server error');
$response->getBody()->write((string)$error);
error_log((string) $error);
return ($out === null)? $response : $out($request, $response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Swagger generated server

## Overview
This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the
[OpenAPI-Spec](https://github.com/swagger-api/swagger-core/wiki) from a remote server, you can easily generate a server stub. This
is an example of building a PHP server.

This example uses the [Zend Expressive](https://zendframework.github.io/zend-expressive) micro framework and [Path Handler](https://github.com/Articus/PathHandler) library. To see how to make this your own, please take a look at the template here:

[TEMPLATES](https://github.com/swagger-api/swagger-codegen/tree/master/modules/swagger-codegen/src/main/resources/ze-ph/)
Loading