PHP server generator ze-ph (Zend Expressive + Path Handler) (#4559)

* Server generator ze-ph (Zend Expressive + Path Handler)

* Command line scripts for new ze-ph generator
This commit is contained in:
Articus 2017-01-15 21:05:04 +04:00 committed by wing328
parent f0cddd21fd
commit 4001503e63
52 changed files with 1965 additions and 0 deletions

View File

@ -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
java %JAVA_OPTS% -jar %executable% %ags%

View File

@ -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

View File

@ -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());
}
}
}

View File

@ -59,3 +59,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

View File

@ -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'));
}
}

View File

@ -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'));
}
}

View File

@ -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);
}
}

View File

@ -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/)

View File

@ -0,0 +1,71 @@
<?php
namespace {{invokerPackage}}\Validator;
use Zend\Validator\AbstractValidator;
use Zend\Validator\Exception;
class Type extends AbstractValidator
{
const INVALID = 'typeInvalid';
/**
* Validation failure message template definitions
*
* @var array
*/
protected $messageTemplates = [
self::INVALID => 'Invalid type given.',
];
/**
* @var string
*/
protected $type;
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param string $type
* @return self
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @inheritDoc
*/
public function isValid($value)
{
$result = true;
if (!$this->checkType($value)) {
$this->error(self::INVALID);
$result = false;
}
return $result;
}
protected function checkType($value)
{
switch ($this->type) {
case 'int':
return is_int($value);
case 'bool':
return is_bool($value);
case 'float':
return is_float($value) || is_int($value);
case 'string':
return is_string($value);
default:
throw new \InvalidArgumentException(sprintf('Can not check for type %s.', $this->type));
}
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace {{package}};
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
{{#operations}}
{{#description}}
/**
* {{&description}}
*/
{{/description}}
class {{classname}} implements {{interfacesToImplement}}
{
{{#operation}}
/**
{{#summary}}
* {{summary}}
{{/summary}}
{{#description}}
* {{description}}
{{/description}}
{{#bodyParam}}
{{#consumes}}
* TODO check if consumer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Consumer(name=PHConsumer\Json::class, mediaType="{{mediaType}}")
{{/consumes}}
{{^isPrimitiveType}}
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":{{dataType}}::class,"objectAttr":"{{paramName}}"})
{{/isPrimitiveType}}
{{/bodyParam}}
{{#produces}}
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="{{mediaType}}")
{{/produces}}
{{#returnType}}
* @return {{returnType}}
{{/returnType}}
*/
public function {{httpMethod}}(ServerRequestInterface $request)
{
//TODO implement method
{{#bodyParam}}
{{^isPrimitiveType}}
/** @var {{dataType}} ${{paramName}} */
${{paramName}} = $request->getAttribute("{{paramName}}");
{{/isPrimitiveType}}
{{/bodyParam}}
throw new PHException\HttpCode(500, "Not implemented");
}
{{/operation}}
}
{{/operations}}

View File

@ -0,0 +1,19 @@
dependencies:
invokables:
#Has to add this line because currently router is strict requirement for Zend\Expressive\Application even if only middleware_pipeline is used
Zend\Expressive\Router\RouterInterface: Zend\Expressive\Router\ZendRouter
Zend\Diactoros\Response\EmitterInterface: Zend\Diactoros\Response\SapiStreamEmitter
{{invokerPackage}}\ErrorMiddleware: {{invokerPackage}}\ErrorMiddleware
factories:
Zend\Expressive\Application: Zend\Expressive\Container\ApplicationFactory
Articus\PathHandler\Middleware: Articus\PathHandler\MiddlewareFactory
Articus\DataTransfer\Service: Articus\DataTransfer\ServiceFactory
middleware_pipeline:
api:
middleware: Articus\PathHandler\Middleware
path: {{basePathWithoutHost}}
error:
middleware: {{invokerPackage}}\ErrorMiddleware
error: true
priority: -10000

View File

@ -0,0 +1,22 @@
{
"name": "{{gitUserId}}/{{gitRepoId}}",
"description": "{{description}}",
"license": "proprietary",
"version": "{{artifactVersion}}",
"type": "project",
"require": {
"php": "^5.6 || ^7.0",
"ext-yaml" : "^1.2 || ^2.0",
"zendframework/zend-expressive": "^1.0",
"zendframework/zend-expressive-router": "1.2.*",
"articus/path-handler": "0.1.*",
"articus/data-transfer": "*",
"zendframework/zend-serializer": "*",
"zendframework/zend-config": "*"
},
"autoload": {
"psr-4": {
"": "src/"
}
}
}

View File

@ -0,0 +1,2 @@
#App
cache_configuration: false

View File

@ -0,0 +1,46 @@
<?php
use Zend\Config\Factory as ConfigFactory;
//Use Composer autoload that includes code both from ../src and ../vendor
require __DIR__ . '/../vendor/autoload.php';
//Path to file for caching full configuration
const CONFIG_CACHE_PATH = __DIR__ . '/../data/cache/config.php';
//Get full configuration
$config = [];
if (is_readable(CONFIG_CACHE_PATH)) {
$config = include CONFIG_CACHE_PATH;
} else {
//Register extra extension for YAML files
ConfigFactory::registerReader('yml', 'yaml');
//Combine all configuration files in right order
$config = ConfigFactory::fromFiles([
__DIR__ . '/config/data_transfer.yml',
__DIR__ . '/config/path_handler.yml',
__DIR__ . '/config/app.yml',
__DIR__ . '/config.yml',
]);
//Cache full configuration
if (isset($config['cache_configuration']) && $config['cache_configuration']) {
if (!ConfigFactory::toFile(CONFIG_CACHE_PATH, $config)) {
throw new \RuntimeException('Failed to cache configuration');
}
}
}
//Get configuration for container
$dependencies = [];
if (isset($config['dependencies'])) {
$dependencies = $config['dependencies'];
}
//Create container
$container = new \Zend\ServiceManager\ServiceManager($dependencies);
//Register full configuration as a service
$container->setService('config', $config);
$container->setAlias('Config', 'config');
return $container;

View File

@ -0,0 +1,28 @@
data_transfer:
metadata_cache:
adapter:
name: blackhole
# adapter:
# name: filesystem
# options:
# cache_dir: data/cache/data_transfer
# namespace: dt
strategies:
invokables:
{{invokerPackage}}\Strategy\Date: {{invokerPackage}}\Strategy\Date
{{invokerPackage}}\Strategy\DateTime: {{invokerPackage}}\Strategy\DateTime
# factories:
aliases:
Date: {{invokerPackage}}\Strategy\Date
DateTime: {{invokerPackage}}\Strategy\DateTime
validators:
invokables:
{{invokerPackage}}\Validator\Type: {{invokerPackage}}\Validator\Type
factories:
Articus\DataTransfer\Validator\Dictionary: Articus\DataTransfer\Validator\Factory
Articus\DataTransfer\Validator\Collection: Articus\DataTransfer\Validator\Factory
aliases:
Dictionary: Articus\DataTransfer\Validator\Dictionary
Collection: Articus\DataTransfer\Validator\Collection
Type: {{invokerPackage}}\Validator\Type

View File

@ -0,0 +1,10 @@
<?php
chdir(dirname(__DIR__));
/** @var \Zend\ServiceManager\ServiceManager $container */
$container = require_once __DIR__.'/../application/container.php';
/** @var \Zend\Expressive\Application $app */
$app = $container->get(\Zend\Expressive\Application::class);
$app->run();

View File

@ -0,0 +1,131 @@
<?php
{{#models}}{{#model}}
namespace {{package}};
use Articus\DataTransfer\Annotation as DTA;
/**
{{#description}}
* {{description}}
{{/description}}
*/
class {{classname}}
{
{{#vars}}
/**
{{#description}}
* {{description}}
{{/description}}
* @DTA\Data(field="{{baseName}}"{{^required}}, nullable=true{{/required}})
{{^isPrimitiveType}}
{{^isListContainer}}
{{^isDate}}
{{^isDateTime}}
* @DTA\Strategy(name="Object", options={"type":{{datatype}}::class})
* @DTA\Validator(name="Dictionary", options={"type":{{datatype}}::class})
{{/isDateTime}}
{{/isDate}}
{{#isDate}}
* @DTA\Strategy(name="Date")
* @DTA\Validator(name="Date")
{{/isDate}}
{{#isDateTime}}
* @DTA\Strategy(name="DateTime")
* @DTA\Validator(name="Date", options={"format": \DateTime::RFC3339})
{{/isDateTime}}
{{/isListContainer}}
{{#isListContainer}}
* @DTA\Strategy(name="ObjectArray", options={"type":{{#items}}{{datatype}}{{/items}}::class})
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Dictionary", "options":{"type":{{#items}}{{datatype}}{{/items}}::class}}
* }})
{{/isListContainer}}
{{/isPrimitiveType}}
{{#isPrimitiveType}}
{{#isListContainer}}
{{#items}}
{{#isString}}
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Type", "options":{"type":"string"}}
* }})
{{/isString}}
{{#isInteger}}
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Type", "options":{"type":"int"}}
* }})
{{/isInteger}}
{{#isLong}}
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Type", "options":{"type":"int"}}
* }})
{{/isLong}}
{{#isBoolean}}
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Type", "options":{"type":"bool"}}
* }})
{{/isBoolean}}
{{#isFloat}}
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Type", "options":{"type":"float"}}
* }})
{{/isFloat}}
{{#isDouble}}
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Type", "options":{"type":"float"}}
* }})
{{/isDouble}}
{{/items}}
{{/isListContainer}}
{{^isListContainer}}
{{#isString}}
* @DTA\Validator(name="Type", options={"type":"string"})
{{/isString}}
{{#isInteger}}
* @DTA\Validator(name="Type", options={"type":"int"})
{{/isInteger}}
{{#isLong}}
* @DTA\Validator(name="Type", options={"type":"int"})
{{/isLong}}
{{#isBoolean}}
* @DTA\Validator(name="Type", options={"type":"bool"})
{{/isBoolean}}
{{#isFloat}}
* @DTA\Validator(name="Type", options={"type":"float"})
{{/isFloat}}
{{#isDouble}}
* @DTA\Validator(name="Type", options={"type":"float"})
{{/isDouble}}
{{/isListContainer}}
{{/isPrimitiveType}}
{{#hasValidation}}
{{#minLength}}
{{#maxLength}}
* @DTA\Validator(name="StringLength", options={"min":{{minLength}}, "max":{{maxLength}}})
{{/maxLength}}
{{/minLength}}
{{^minLength}}
{{#maxLength}}
* @DTA\Validator(name="StringLength", options={"max":{{maxLength}}})
{{/maxLength}}
{{/minLength}}
{{#minLength}}
{{^maxLength}}
* @DTA\Validator(name="StringLength", options={"min":{{minLength}}})
{{/maxLength}}
{{/minLength}}
{{#minimum}}
* @DTA\Validator(name="GreaterThan", options={"min":{{minimum}}{{^exclusiveMinimum}}, "inclusive":true{{/exclusiveMinimum}}})
{{/minimum}}
{{#maximum}}
* @DTA\Validator(name="LessThan", options={"max":{{maximum}}{{^exclusiveMaximum}}, "inclusive":true{{/exclusiveMaximum}}})
{{/maximum}}
{{#pattern}}
* @DTA\Validator(name="Regex", options={"pattern":"{{pattern}}})
{{/pattern}}
{{/hasValidation}}
* @var {{datatype}}
*/
public ${{name}};
{{/vars}}
}
{{/model}}{{/models}}

View File

@ -0,0 +1,27 @@
path_handler:
routes:
routes:
{{#routes}}{{>route}}{{/routes}}
default_params:
middleware: ''
metadata_cache:
adapter:
name: blackhole
# adapter:
# name: filesystem
# options:
# cache_dir: data/cache/path_handler
# namespace: ph
handlers:
invokables:
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{classname}}: {{package}}\{{classname}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
# consumers:
# attributes:
# producers:

View File

@ -0,0 +1,15 @@
{{padding}}'{{name}}':
{{padding}} type: {{type}}
{{padding}} options:
{{padding}} route: {{route}}
{{#handler}}
{{padding}} defaults:
{{padding}} handler: {{handler}}
{{/handler}}
{{#hasChildren}}
{{#handler}}
{{padding}} may_terminate: true
{{/handler}}
{{padding}} child_routes:
{{/hasChildren}}
{{#children}}{{>route}}{{/children}}

View File

@ -0,0 +1,23 @@
# Swagger Codegen Ignore
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -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/)

View File

@ -0,0 +1,2 @@
#App
cache_configuration: false

View File

@ -0,0 +1,19 @@
dependencies:
invokables:
#Has to add this line because currently router is strict requirement for Zend\Expressive\Application even if only middleware_pipeline is used
Zend\Expressive\Router\RouterInterface: Zend\Expressive\Router\ZendRouter
Zend\Diactoros\Response\EmitterInterface: Zend\Diactoros\Response\SapiStreamEmitter
App\ErrorMiddleware: App\ErrorMiddleware
factories:
Zend\Expressive\Application: Zend\Expressive\Container\ApplicationFactory
Articus\PathHandler\Middleware: Articus\PathHandler\MiddlewareFactory
Articus\DataTransfer\Service: Articus\DataTransfer\ServiceFactory
middleware_pipeline:
api:
middleware: Articus\PathHandler\Middleware
path: /v2
error:
middleware: App\ErrorMiddleware
error: true
priority: -10000

View File

@ -0,0 +1,28 @@
data_transfer:
metadata_cache:
adapter:
name: blackhole
# adapter:
# name: filesystem
# options:
# cache_dir: data/cache/data_transfer
# namespace: dt
strategies:
invokables:
App\Strategy\Date: App\Strategy\Date
App\Strategy\DateTime: App\Strategy\DateTime
# factories:
aliases:
Date: App\Strategy\Date
DateTime: App\Strategy\DateTime
validators:
invokables:
App\Validator\Type: App\Validator\Type
factories:
Articus\DataTransfer\Validator\Dictionary: Articus\DataTransfer\Validator\Factory
Articus\DataTransfer\Validator\Collection: Articus\DataTransfer\Validator\Factory
aliases:
Dictionary: Articus\DataTransfer\Validator\Dictionary
Collection: Articus\DataTransfer\Validator\Collection
Type: App\Validator\Type

View File

@ -0,0 +1,131 @@
path_handler:
routes:
routes:
'pet':
type: Literal
options:
route: /pet
defaults:
handler: Pet
may_terminate: true
child_routes:
'findByStatus':
type: Literal
options:
route: /findByStatus
defaults:
handler: PetFindByStatus
'findByTags':
type: Literal
options:
route: /findByTags
defaults:
handler: PetFindByTags
'{petId}':
type: Segment
options:
route: /:petId
defaults:
handler: PetPetId
may_terminate: true
child_routes:
'uploadImage':
type: Literal
options:
route: /uploadImage
defaults:
handler: PetPetIdUploadImage
'store':
type: Literal
options:
route: /store
child_routes:
'inventory':
type: Literal
options:
route: /inventory
defaults:
handler: StoreInventory
'order':
type: Literal
options:
route: /order
defaults:
handler: StoreOrder
may_terminate: true
child_routes:
'{orderId}':
type: Segment
options:
route: /:orderId
defaults:
handler: StoreOrderOrderId
'user':
type: Literal
options:
route: /user
defaults:
handler: User
may_terminate: true
child_routes:
'createWithArray':
type: Literal
options:
route: /createWithArray
defaults:
handler: UserCreateWithArray
'createWithList':
type: Literal
options:
route: /createWithList
defaults:
handler: UserCreateWithList
'login':
type: Literal
options:
route: /login
defaults:
handler: UserLogin
'logout':
type: Literal
options:
route: /logout
defaults:
handler: UserLogout
'{username}':
type: Segment
options:
route: /:username
defaults:
handler: UserUsername
default_params:
middleware: ''
metadata_cache:
adapter:
name: blackhole
# adapter:
# name: filesystem
# options:
# cache_dir: data/cache/path_handler
# namespace: ph
handlers:
invokables:
Pet: App\Handler\Pet
PetFindByStatus: App\Handler\PetFindByStatus
PetFindByTags: App\Handler\PetFindByTags
PetPetId: App\Handler\PetPetId
PetPetIdUploadImage: App\Handler\PetPetIdUploadImage
StoreInventory: App\Handler\StoreInventory
StoreOrder: App\Handler\StoreOrder
StoreOrderOrderId: App\Handler\StoreOrderOrderId
User: App\Handler\User
UserCreateWithArray: App\Handler\UserCreateWithArray
UserCreateWithList: App\Handler\UserCreateWithList
UserLogin: App\Handler\UserLogin
UserLogout: App\Handler\UserLogout
UserUsername: App\Handler\UserUsername
# consumers:
# attributes:
# producers:

View File

@ -0,0 +1,46 @@
<?php
use Zend\Config\Factory as ConfigFactory;
//Use Composer autoload that includes code both from ../src and ../vendor
require __DIR__ . '/../vendor/autoload.php';
//Path to file for caching full configuration
const CONFIG_CACHE_PATH = __DIR__ . '/../data/cache/config.php';
//Get full configuration
$config = [];
if (is_readable(CONFIG_CACHE_PATH)) {
$config = include CONFIG_CACHE_PATH;
} else {
//Register extra extension for YAML files
ConfigFactory::registerReader('yml', 'yaml');
//Combine all configuration files in right order
$config = ConfigFactory::fromFiles([
__DIR__ . '/config/data_transfer.yml',
__DIR__ . '/config/path_handler.yml',
__DIR__ . '/config/app.yml',
__DIR__ . '/config.yml',
]);
//Cache full configuration
if (isset($config['cache_configuration']) && $config['cache_configuration']) {
if (!ConfigFactory::toFile(CONFIG_CACHE_PATH, $config)) {
throw new \RuntimeException('Failed to cache configuration');
}
}
}
//Get configuration for container
$dependencies = [];
if (isset($config['dependencies'])) {
$dependencies = $config['dependencies'];
}
//Create container
$container = new \Zend\ServiceManager\ServiceManager($dependencies);
//Register full configuration as a service
$container->setService('config', $config);
$container->setAlias('Config', 'config');
return $container;

View File

@ -0,0 +1,22 @@
{
"name": "GIT_USER_ID/GIT_REPO_ID",
"description": "",
"license": "proprietary",
"version": "1.0.0",
"type": "project",
"require": {
"php": "^5.6 || ^7.0",
"ext-yaml" : "^1.2 || ^2.0",
"zendframework/zend-expressive": "^1.0",
"zendframework/zend-expressive-router": "1.2.*",
"articus/path-handler": "0.1.*",
"articus/data-transfer": "*",
"zendframework/zend-serializer": "*",
"zendframework/zend-config": "*"
},
"autoload": {
"psr-4": {
"": "src/"
}
}
}

View File

@ -0,0 +1,10 @@
<?php
chdir(dirname(__DIR__));
/** @var \Zend\ServiceManager\ServiceManager $container */
$container = require_once __DIR__.'/../application/container.php';
/** @var \Zend\Expressive\Application $app */
$app = $container->get(\Zend\Expressive\Application::class);
$app->run();

View File

@ -0,0 +1,30 @@
<?php
namespace App\DTO;
use Articus\DataTransfer\Annotation as DTA;
/**
*/
class ApiResponse
{
/**
* @DTA\Data(field="code", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $code;
/**
* @DTA\Data(field="type", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $type;
/**
* @DTA\Data(field="message", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $message;
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\DTO;
use Articus\DataTransfer\Annotation as DTA;
/**
*/
class Category
{
/**
* @DTA\Data(field="id", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $id;
/**
* @DTA\Data(field="name", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $name;
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\DTO;
use Articus\DataTransfer\Annotation as DTA;
/**
*/
class Order
{
/**
* @DTA\Data(field="id", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $id;
/**
* @DTA\Data(field="petId", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $pet_id;
/**
* @DTA\Data(field="quantity", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $quantity;
/**
* @DTA\Data(field="shipDate", nullable=true)
* @DTA\Strategy(name="DateTime")
* @DTA\Validator(name="Date", options={"format": \DateTime::RFC3339})
* @var \DateTime
*/
public $ship_date;
/**
* Order Status
* @DTA\Data(field="status", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $status;
/**
* @DTA\Data(field="complete", nullable=true)
* @DTA\Validator(name="Type", options={"type":"bool"})
* @var bool
*/
public $complete;
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\DTO;
use Articus\DataTransfer\Annotation as DTA;
/**
*/
class Pet
{
/**
* @DTA\Data(field="id", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $id;
/**
* @DTA\Data(field="category", nullable=true)
* @DTA\Strategy(name="Object", options={"type":\App\DTO\Category::class})
* @DTA\Validator(name="Dictionary", options={"type":\App\DTO\Category::class})
* @var \App\DTO\Category
*/
public $category;
/**
* @DTA\Data(field="name")
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $name;
/**
* @DTA\Data(field="photoUrls")
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Type", "options":{"type":"string"}}
* }})
* @var string[]
*/
public $photo_urls;
/**
* @DTA\Data(field="tags", nullable=true)
* @DTA\Strategy(name="ObjectArray", options={"type":\App\DTO\Tag::class})
* @DTA\Validator(name="Collection", options={"validators":{
* {"name":"Dictionary", "options":{"type":\App\DTO\Tag::class}}
* }})
* @var \App\DTO\Tag[]
*/
public $tags;
/**
* pet status in the store
* @DTA\Data(field="status", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $status;
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\DTO;
use Articus\DataTransfer\Annotation as DTA;
/**
*/
class Tag
{
/**
* @DTA\Data(field="id", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $id;
/**
* @DTA\Data(field="name", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $name;
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\DTO;
use Articus\DataTransfer\Annotation as DTA;
/**
*/
class User
{
/**
* @DTA\Data(field="id", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $id;
/**
* @DTA\Data(field="username", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $username;
/**
* @DTA\Data(field="firstName", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $first_name;
/**
* @DTA\Data(field="lastName", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $last_name;
/**
* @DTA\Data(field="email", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $email;
/**
* @DTA\Data(field="password", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $password;
/**
* @DTA\Data(field="phone", nullable=true)
* @DTA\Validator(name="Type", options={"type":"string"})
* @var string
*/
public $phone;
/**
* User Status
* @DTA\Data(field="userStatus", nullable=true)
* @DTA\Validator(name="Type", options={"type":"int"})
* @var int
*/
public $user_status;
}

View File

@ -0,0 +1,20 @@
<?php
namespace App;
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);
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class Pet implements Operation\PostInterface, Operation\PutInterface
{
/**
* Add a new pet to the store
* TODO check if consumer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Consumer(name=PHConsumer\Json::class, mediaType="application/json")
* TODO check if consumer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Consumer(name=PHConsumer\Json::class, mediaType="application/xml")
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Pet::class,"objectAttr":"body"})
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handlePost(ServerRequestInterface $request)
{
//TODO implement method
/** @var \App\DTO\Pet $body */
$body = $request->getAttribute("body");
throw new PHException\HttpCode(500, "Not implemented");
}
/**
* Update an existing pet
* TODO check if consumer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Consumer(name=PHConsumer\Json::class, mediaType="application/json")
* TODO check if consumer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Consumer(name=PHConsumer\Json::class, mediaType="application/xml")
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Pet::class,"objectAttr":"body"})
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handlePut(ServerRequestInterface $request)
{
//TODO implement method
/** @var \App\DTO\Pet $body */
$body = $request->getAttribute("body");
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class PetFindByStatus implements Operation\GetInterface
{
/**
* Finds Pets by status
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return \App\DTO\Pet[]
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class PetFindByTags implements Operation\GetInterface
{
/**
* Finds Pets by tags
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return \App\DTO\Pet[]
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class PetPetId implements Operation\DeleteInterface, Operation\GetInterface, Operation\PostInterface
{
/**
* Deletes a pet
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handleDelete(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
/**
* Find pet by ID
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return \App\DTO\Pet
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
/**
* Updates a pet in the store with form data
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handlePost(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class PetPetIdUploadImage implements Operation\PostInterface
{
/**
* uploads an image
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return \App\DTO\ApiResponse
*/
public function handlePost(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class StoreInventory implements Operation\GetInterface
{
/**
* Returns pet inventories by status
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return map[string,int]
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class StoreOrder implements Operation\PostInterface
{
/**
* Place an order for a pet
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Order::class,"objectAttr":"body"})
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return \App\DTO\Order
*/
public function handlePost(ServerRequestInterface $request)
{
//TODO implement method
/** @var \App\DTO\Order $body */
$body = $request->getAttribute("body");
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class StoreOrderOrderId implements Operation\DeleteInterface, Operation\GetInterface
{
/**
* Delete purchase order by ID
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handleDelete(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
/**
* Find purchase order by ID
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return \App\DTO\Order
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class User implements Operation\PostInterface
{
/**
* Create user
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User::class,"objectAttr":"body"})
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handlePost(ServerRequestInterface $request)
{
//TODO implement method
/** @var \App\DTO\User $body */
$body = $request->getAttribute("body");
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class UserCreateWithArray implements Operation\PostInterface
{
/**
* Creates list of users with given input array
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User[]::class,"objectAttr":"body"})
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handlePost(ServerRequestInterface $request)
{
//TODO implement method
/** @var \App\DTO\User[] $body */
$body = $request->getAttribute("body");
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class UserCreateWithList implements Operation\PostInterface
{
/**
* Creates list of users with given input array
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User[]::class,"objectAttr":"body"})
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handlePost(ServerRequestInterface $request)
{
//TODO implement method
/** @var \App\DTO\User[] $body */
$body = $request->getAttribute("body");
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class UserLogin implements Operation\GetInterface
{
/**
* Logs user into the system
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return string
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class UserLogout implements Operation\GetInterface
{
/**
* Logs out current logged in user session
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Handler;
use Articus\PathHandler\Operation;
use Articus\PathHandler\Annotation as PHA;
use Articus\PathHandler\Consumer as PHConsumer;
use Articus\PathHandler\Producer as PHProducer;
use Articus\PathHandler\Attribute as PHAttribute;
use Articus\PathHandler\Exception as PHException;
use Psr\Http\Message\ServerRequestInterface;
class UserUsername implements Operation\DeleteInterface, Operation\GetInterface, Operation\PutInterface
{
/**
* Delete user
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handleDelete(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
/**
* Get user by user name
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
* @return \App\DTO\User
*/
public function handleGet(ServerRequestInterface $request)
{
//TODO implement method
throw new PHException\HttpCode(500, "Not implemented");
}
/**
* Updated user
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User::class,"objectAttr":"body"})
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml")
* TODO check if producer is valid, if it has correct priority and if it can be moved to class annotation
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json")
*/
public function handlePut(ServerRequestInterface $request)
{
//TODO implement method
/** @var \App\DTO\User $body */
$body = $request->getAttribute("body");
throw new PHException\HttpCode(500, "Not implemented");
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\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'));
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\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'));
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Validator;
use Zend\Validator\AbstractValidator;
use Zend\Validator\Exception;
class Type extends AbstractValidator
{
const INVALID = 'typeInvalid';
/**
* Validation failure message template definitions
*
* @var array
*/
protected $messageTemplates = [
self::INVALID => 'Invalid type given.',
];
/**
* @var string
*/
protected $type;
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param string $type
* @return self
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @inheritDoc
*/
public function isValid($value)
{
$result = true;
if (!$this->checkType($value)) {
$this->error(self::INVALID);
$result = false;
}
return $result;
}
protected function checkType($value)
{
switch ($this->type) {
case 'int':
return is_int($value);
case 'bool':
return is_bool($value);
case 'float':
return is_float($value) || is_int($value);
case 'string':
return is_string($value);
default:
throw new \InvalidArgumentException(sprintf('Can not check for type %s.', $this->type));
}
}
}