mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-05-12 20:50:55 +00:00
[Feature][PHP] Update for ze-ph generator (#7472)
* update for ze-ph generator stub to support Zend Expressive 2.1 and Path Handler 0.3 * ze-ph: for each operation generator creates special DTO model from its query parameters * ze-ph: generation of extra TODO's for complex container type and update for samples
This commit is contained in:
parent
5a3a33b3c8
commit
60e3339aa6
@ -1,8 +1,10 @@
|
||||
package io.swagger.codegen.languages;
|
||||
|
||||
import io.swagger.codegen.*;
|
||||
import io.swagger.models.Operation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import io.swagger.models.*;
|
||||
import io.swagger.models.parameters.Parameter;
|
||||
import io.swagger.models.parameters.QueryParameter;
|
||||
import io.swagger.models.properties.*;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
@ -12,6 +14,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ZendExpressivePathHandlerServerCodegen extends AbstractPhpCodegen {
|
||||
|
||||
public static final String VEN_FROM_QUERY = "internal.ze-ph.fromQuery";
|
||||
public static final String VEN_COLLECTION_FORMAT = "internal.ze-ph.collectionFormat";
|
||||
public static final String VEN_QUERY_DATA_TYPE = "internal.ze-ph.queryDataType";
|
||||
public static final String VEN_HAS_QUERY_DATA = "internal.ze-ph.hasQueryData";
|
||||
|
||||
@Override
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.SERVER;
|
||||
@ -29,6 +37,8 @@ public class ZendExpressivePathHandlerServerCodegen extends AbstractPhpCodegen {
|
||||
|
||||
public ZendExpressivePathHandlerServerCodegen() {
|
||||
super();
|
||||
//no point to use double - http://php.net/manual/en/language.types.float.php , especially because of PHP 7+ float type declaration
|
||||
typeMapping.put("double", "float");
|
||||
|
||||
embeddedTemplateDir = templateDir = "ze-ph";
|
||||
invokerPackage = "App";
|
||||
@ -52,9 +62,14 @@ public class ZendExpressivePathHandlerServerCodegen extends AbstractPhpCodegen {
|
||||
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("ErrorMiddleware.php.mustache", packagePath + File.separator + srcBasePath, "ErrorMiddleware.php"));
|
||||
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("QueryParameter.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Strategy", "QueryParameter.php"));
|
||||
supportingFiles.add(new SupportingFile("QueryParameterArray.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Strategy", "QueryParameterArray.php"));
|
||||
supportingFiles.add(new SupportingFile("Type.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Validator", "Type.php"));
|
||||
supportingFiles.add(new SupportingFile("QueryParameterType.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Validator", "QueryParameterType.php"));
|
||||
supportingFiles.add(new SupportingFile("QueryParameterArrayType.php.mustache", packagePath + File.separator + srcBasePath + File.separator + "Validator", "QueryParameterArrayType.php"));
|
||||
|
||||
additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, "1.0.0");
|
||||
}
|
||||
@ -115,6 +130,121 @@ public class ZendExpressivePathHandlerServerCodegen extends AbstractPhpCodegen {
|
||||
return super.toModelName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate additional model definitions from query parameters
|
||||
*
|
||||
* @param swagger
|
||||
*/
|
||||
@Override
|
||||
public void preprocessSwagger(Swagger swagger) {
|
||||
super.preprocessSwagger(swagger);
|
||||
for (String pathKey : swagger.getPaths().keySet())
|
||||
{
|
||||
Path path = swagger.getPath(pathKey);
|
||||
Map<HttpMethod, Operation> operations = path.getOperationMap();
|
||||
for (HttpMethod method : operations.keySet())
|
||||
{
|
||||
Operation operation = operations.get(method);
|
||||
Map<String, Property> properties = new HashMap<>();
|
||||
for (Parameter parameter : operation.getParameters())
|
||||
{
|
||||
Property property = convertParameterToProperty(parameter);
|
||||
if (property != null)
|
||||
{
|
||||
properties.put(property.getName(), property);
|
||||
}
|
||||
}
|
||||
if (!properties.isEmpty())
|
||||
{
|
||||
Model model = new ModelImpl();
|
||||
String operationId = getOrGenerateOperationId(operation, pathKey, method.name());
|
||||
model.setDescription("Query parameters for " + operationId);
|
||||
model.setProperties(properties);
|
||||
model.getVendorExtensions().put(VEN_FROM_QUERY, Boolean.TRUE);
|
||||
String definitionName = generateUniqueDefinitionName(operationId + "QueryData", swagger);
|
||||
swagger.addDefinition(definitionName, model);
|
||||
String definitionModel = "\\" + modelPackage + "\\" + toModelName(definitionName);
|
||||
operation.getVendorExtensions().put(VEN_QUERY_DATA_TYPE, definitionModel);
|
||||
operation.getVendorExtensions().put(VEN_HAS_QUERY_DATA, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Property convertParameterToProperty(Parameter parameter) {
|
||||
Property property = null;
|
||||
if (parameter instanceof QueryParameter)
|
||||
{
|
||||
QueryParameter queryParameter = (QueryParameter) parameter;
|
||||
switch (queryParameter.getType())
|
||||
{
|
||||
case "string":
|
||||
StringProperty stringProperty = new StringProperty();
|
||||
stringProperty.setMinLength(queryParameter.getMinLength());
|
||||
stringProperty.setMaxLength(queryParameter.getMaxLength());
|
||||
stringProperty.setPattern(queryParameter.getPattern());
|
||||
stringProperty.setEnum(queryParameter.getEnum());
|
||||
property = stringProperty;
|
||||
break;
|
||||
case "integer":
|
||||
IntegerProperty integerProperty = new IntegerProperty();
|
||||
integerProperty.setMinimum(queryParameter.getMinimum());
|
||||
integerProperty.setMaximum(queryParameter.getMaximum());
|
||||
property = integerProperty;
|
||||
break;
|
||||
case "number":
|
||||
FloatProperty floatProperty = new FloatProperty();
|
||||
floatProperty.setMinimum(queryParameter.getMinimum());
|
||||
floatProperty.setMaximum(queryParameter.getMaximum());
|
||||
property = floatProperty;
|
||||
break;
|
||||
case "boolean":
|
||||
property = new BooleanProperty();
|
||||
break;
|
||||
case "array":
|
||||
ArrayProperty arrayProperty = new ArrayProperty();
|
||||
arrayProperty.setMinItems(queryParameter.getMinItems());
|
||||
arrayProperty.setMaxItems(queryParameter.getMaxItems());
|
||||
arrayProperty.setItems(queryParameter.getItems());
|
||||
String collectionFormat = queryParameter.getCollectionFormat();
|
||||
if (collectionFormat == null) {
|
||||
collectionFormat = "csv";
|
||||
}
|
||||
arrayProperty.getVendorExtensions().put(VEN_COLLECTION_FORMAT, collectionFormat);
|
||||
property = arrayProperty;
|
||||
break;
|
||||
case "date":
|
||||
property = new DateProperty();
|
||||
break;
|
||||
case "date-time":
|
||||
property = new DateTimeProperty();
|
||||
break;
|
||||
}
|
||||
if (property != null)
|
||||
{
|
||||
property.setName(queryParameter.getName());
|
||||
property.setDescription(queryParameter.getDescription());
|
||||
property.setRequired(queryParameter.getRequired());
|
||||
property.getVendorExtensions().put(VEN_FROM_QUERY, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
protected String generateUniqueDefinitionName(String name, Swagger swagger)
|
||||
{
|
||||
String result = name;
|
||||
if (swagger.getDefinitions() != null) {
|
||||
int count = 1;
|
||||
while (swagger.getDefinitions().containsKey(result))
|
||||
{
|
||||
result = name + "_" + count;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
|
||||
objs = super.postProcessOperations(objs);
|
||||
@ -123,6 +253,7 @@ public class ZendExpressivePathHandlerServerCodegen extends AbstractPhpCodegen {
|
||||
String interfaceToImplement;
|
||||
StringBuilder interfacesToImplement = new StringBuilder();
|
||||
String classMethod;
|
||||
String pathPattern = null;
|
||||
for (CodegenOperation op : operationList) {
|
||||
switch (op.httpMethod) {
|
||||
case "GET":
|
||||
@ -153,63 +284,41 @@ public class ZendExpressivePathHandlerServerCodegen extends AbstractPhpCodegen {
|
||||
}
|
||||
interfacesToImplement.append(interfaceToImplement);
|
||||
op.httpMethod = classMethod;
|
||||
//All operations have same path because of custom operation grouping, so path pattern can be calculated only once
|
||||
if (pathPattern == null) {
|
||||
pathPattern = generatePathPattern(op);
|
||||
}
|
||||
}
|
||||
operations.put("interfacesToImplement", interfacesToImplement.toString());
|
||||
operations.put("pathPattern", pathPattern);
|
||||
|
||||
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;
|
||||
protected String generatePathPattern(CodegenOperation op) {
|
||||
String result = op.path;
|
||||
for (CodegenParameter pp : op.pathParams) {
|
||||
StringBuilder replacement = new StringBuilder( "{" + pp.paramName);
|
||||
if (pp.isEnum) {
|
||||
StringBuilder enumRegExp = new StringBuilder();
|
||||
for (String enumValue : pp._enum) {
|
||||
if (enumRegExp.length() > 0) {
|
||||
enumRegExp.append("|");
|
||||
}
|
||||
enumRegExp.append(enumValue.replaceAll("[\\Q<>()[]{}|^$-=!?*+.\\\\E]", "\\\\$0"));
|
||||
}
|
||||
replacement.append(":");
|
||||
replacement.append(enumRegExp);
|
||||
} else if (pp.isInteger) {
|
||||
replacement.append(":0|(?:-?[1-9][0-9]*)");
|
||||
} else if (pp.isString && (pp.pattern != null) && (!pp.pattern.isEmpty())) {
|
||||
replacement.append(":");
|
||||
replacement.append(pp.pattern);
|
||||
}
|
||||
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());
|
||||
//TODO add regular expressions for other types if they are actually used for path parameters
|
||||
replacement.append("}");
|
||||
result = result.replace("{" + pp.paramName + "}", replacement);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace {{invokerPackage}};
|
||||
|
||||
use Interop\Http\ServerMiddleware\DelegateInterface;
|
||||
use Interop\Http\ServerMiddleware\MiddlewareInterface;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Zend\Stdlib\ErrorHandler;
|
||||
|
||||
class ErrorMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, DelegateInterface $delegate)
|
||||
{
|
||||
$result = null;
|
||||
try {
|
||||
ErrorHandler::start();
|
||||
$result = $delegate->process($request);
|
||||
ErrorHandler::stop(true);
|
||||
if (!($result instanceof Response)) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Invalid response: expecting %s, got %s',
|
||||
Response::class,
|
||||
is_object($result)? get_class($result) : gettype($result)
|
||||
));
|
||||
}
|
||||
}
|
||||
catch (\Exception $error) {
|
||||
$result = (new \Zend\Diactoros\Response())->withStatus(500, 'Internal server error');
|
||||
error_log((string)$error);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace {{invokerPackage}}\Strategy;
|
||||
|
||||
use Articus\DataTransfer\Strategy\StrategyInterface;
|
||||
|
||||
class QueryParameter implements StrategyInterface
|
||||
{
|
||||
const TYPE_INT = 'int';
|
||||
const TYPE_FLOAT = 'float';
|
||||
const TYPE_BOOL = 'bool';
|
||||
const TYPE_STRING = 'string';
|
||||
|
||||
const TYPE_MAP = [
|
||||
self::TYPE_INT => true,
|
||||
self::TYPE_FLOAT => true,
|
||||
self::TYPE_BOOL => true,
|
||||
self::TYPE_STRING => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* QueryParameterArray constructor.
|
||||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
if (empty($options['type'])) {
|
||||
throw new \InvalidArgumentException('Option "type" is required.');
|
||||
} elseif (!isset(self::TYPE_MAP[$options['type']])) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown type "%s".', $options['type']));
|
||||
}
|
||||
$this->type = $options['type'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function extract($objectValue, $object = null)
|
||||
{
|
||||
$result = null;
|
||||
if ($objectValue !== null) {
|
||||
$result = (string)$objectValue;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function hydrate($arrayValue, $objectValue, array $array = null)
|
||||
{
|
||||
$result = null;
|
||||
if ($arrayValue !== null) {
|
||||
switch ($this->type) {
|
||||
case self::TYPE_INT:
|
||||
$result = (int)$arrayValue;
|
||||
break;
|
||||
case self::TYPE_FLOAT:
|
||||
$result = (float)$arrayValue;
|
||||
break;
|
||||
case self::TYPE_BOOL:
|
||||
$result = ($arrayValue === 'true')? true : false;
|
||||
break;
|
||||
case self::TYPE_STRING:
|
||||
$result = (string)$arrayValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace {{invokerPackage}}\Strategy;
|
||||
|
||||
class QueryParameterArray extends QueryParameter
|
||||
{
|
||||
const FORMAT_CSV = 'csv'; //comma separated values foo,bar.
|
||||
const FORMAT_SSV = 'ssv'; //space separated values foo bar.
|
||||
const FORMAT_TSV = 'tsv'; //tab separated values foo\tbar.
|
||||
const FORMAT_PIPES = 'pipes'; //pipe separated values foo|bar.
|
||||
const FORMAT_MULTI = 'multi'; //corresponds to multiple parameter instances instead of multiple values for a single instance foo[]=bar&foo[]=baz.
|
||||
|
||||
const DELIMITER_MAP = [
|
||||
self::FORMAT_CSV => ',',
|
||||
self::FORMAT_SSV => ' ',
|
||||
self::FORMAT_TSV => "\t",
|
||||
self::FORMAT_PIPES => '|',
|
||||
self::FORMAT_MULTI => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $delimiter;
|
||||
|
||||
public function __construct(array $options)
|
||||
{
|
||||
parent::__construct($options);
|
||||
if (empty($options['format'])) {
|
||||
throw new \InvalidArgumentException('Option "format" is required.');
|
||||
} elseif (!array_key_exists($options['format'], self::DELIMITER_MAP)) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown format "%s".', $options['format']));
|
||||
}
|
||||
$this->delimiter = self::DELIMITER_MAP[$options['format']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function extract($objectValue, $object = null)
|
||||
{
|
||||
$result = null;
|
||||
if (is_array($objectValue)) {
|
||||
if ($this->delimiter === null) {
|
||||
$result = $objectValue;
|
||||
} else {
|
||||
$result = implode($this->delimiter, $objectValue);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function hydrate($arrayValue, $objectValue, array $array = null)
|
||||
{
|
||||
$result = null;
|
||||
if ($arrayValue !== null) {
|
||||
$list = null;
|
||||
if ($this->delimiter === null) {
|
||||
$list = (is_array($arrayValue))? $arrayValue : [$arrayValue];
|
||||
} else {
|
||||
$list = explode($this->delimiter, $arrayValue);
|
||||
}
|
||||
$result = [];
|
||||
foreach ($list as $item) {
|
||||
$result[] = parent::hydrate($item, null);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace {{invokerPackage}}\Validator;
|
||||
|
||||
use App\Strategy\QueryParameterArray;
|
||||
|
||||
class QueryParameterArrayType extends QueryParameterType
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $format;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFormat()
|
||||
{
|
||||
return $this->format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $format
|
||||
* @return self
|
||||
*/
|
||||
public function setFormat($format)
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function checkType($value)
|
||||
{
|
||||
$result = true;
|
||||
if (!array_key_exists($this->format, QueryParameterArray::DELIMITER_MAP)) {
|
||||
throw new \InvalidArgumentException(sprintf('Can not check for format %s.', $this->format));
|
||||
}
|
||||
$delimiter = QueryParameterArray::DELIMITER_MAP[$this->format];
|
||||
if ($delimiter === null) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
$result = $result && parent::checkType($item);
|
||||
}
|
||||
} else {
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
switch ($this->type) {
|
||||
case QueryParameterArray::TYPE_INT:
|
||||
$result = is_string($value) && preg_match(self::prepareRepeatingTypeRegExp(self::RE_INT, $delimiter), $value);
|
||||
break;
|
||||
case QueryParameterArray::TYPE_BOOL:
|
||||
$result = is_string($value) && preg_match(self::prepareRepeatingTypeRegExp(self::RE_BOOL, $delimiter), $value);
|
||||
break;
|
||||
case QueryParameterArray::TYPE_FLOAT:
|
||||
$result = is_string($value) && preg_match(self::prepareRepeatingTypeRegExp(self::RE_FLOAT, $delimiter), $value);
|
||||
break;
|
||||
case QueryParameterArray::TYPE_STRING:
|
||||
$result = is_string($value);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Can not check for type %s.', $this->type));
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected static function prepareRepeatingTypeRegExp($typeRegExp, $delimiter)
|
||||
{
|
||||
$escapedDelimiter = preg_quote($delimiter, '/');
|
||||
return '/^(' . $typeRegExp . ')(' . $escapedDelimiter . '('. $typeRegExp . '))*$/';
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace {{invokerPackage}}\Validator;
|
||||
|
||||
use App\Strategy\QueryParameter;
|
||||
|
||||
class QueryParameterType extends Type
|
||||
{
|
||||
const RE_INT = '0|-?[1-9]\d*';
|
||||
const RE_BOOL = 'true|false';
|
||||
const RE_FLOAT = '0(\.\d+)?|-?[1-9]\d*(\.\d+)?|-0\.\d+';
|
||||
|
||||
protected function checkType($value)
|
||||
{
|
||||
switch ($this->type) {
|
||||
case QueryParameter::TYPE_INT:
|
||||
return is_string($value) && preg_match('/^(' . self::RE_INT . ')$/', $value);
|
||||
case QueryParameter::TYPE_BOOL:
|
||||
return is_string($value) && preg_match('/^(' . self::RE_BOOL . ')$/', $value);
|
||||
case QueryParameter::TYPE_FLOAT:
|
||||
return is_string($value) && preg_match('/^(' . self::RE_FLOAT . ')$/', $value);
|
||||
case QueryParameter::TYPE_STRING:
|
||||
return is_string($value);
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Can not check for type %s.', $this->type));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,34 @@
|
||||
# Swagger generated server
|
||||
|
||||
Generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project.
|
||||
|
||||
## 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 server stub aims to provide light, yet comprehensive structure for your API project using:
|
||||
|
||||
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:
|
||||
- PHP: 5.6 or 7.*
|
||||
- [Zend Expressive](https://zendframework.github.io/zend-expressive): 2.1
|
||||
- [Path Handler](https://github.com/Articus/PathHandler): 0.3
|
||||
|
||||
[TEMPLATES](https://github.com/swagger-api/swagger-codegen/tree/master/modules/swagger-codegen/src/main/resources/ze-ph/)
|
||||
## How to use
|
||||
All you have to do to start development is:
|
||||
|
||||
- install dependencies via [Composer](https://getcomposer.org/)
|
||||
- create cache folder: `mkdir -p ./data/cache/ZendCache` (you will need it later for configuration and metadata caches - check comments in `./application/conig.yml`)
|
||||
- start PHP development server: `php -S 0.0.0.0:8080 -t ./public` (or any other SAPI you prefer, just make sure that you configure webroot to `./public` and rewrites to `./public/index.php`)
|
||||
|
||||
After that you should be able to call all methods from your API spec. Most of the negative scenarios should be handled:
|
||||
|
||||
- `404 Not found` for unknown routes
|
||||
- `406 Not acceptable` for invalid `Accept` header
|
||||
- `415 Unsupported media type` for invalid `Content-Type` header
|
||||
- `400 Malformed JSON` for unparsable JSON body
|
||||
- `422 Unprocessable entity` for parsable JSON body that fails validation
|
||||
|
||||
But for obvious reason you will not get any `200 OK`, only `500 Not implemented`. So your next steps are:
|
||||
|
||||
- check all TODOs left in the stub code where generator was not smart enough and could not guarantee correct implementation
|
||||
- implement your API security mechanism (either special attribute or separate middleware) - generator does not do anything about it yet
|
||||
- implement your handlers - the most tricky part :)
|
||||
|
||||
## Enjoy!
|
||||
Hopefully this stub will reduce the amount of boilerplate code you have to write manually. If you have any suggestions or questions about `ze-ph` generator, feel free to create issue either in [Path Handler repository](https://github.com/Articus/PathHandler/issues) or in [Swagger Codegen repository](https://github.com/swagger-api/swagger-codegen/issues).
|
||||
|
@ -11,11 +11,12 @@ use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
{{#operations}}
|
||||
{{#description}}
|
||||
/**
|
||||
{{#description}}
|
||||
* {{&description}}
|
||||
*/
|
||||
{{/description}}
|
||||
* @PHA\Route(pattern="{{pathPattern}}")
|
||||
*/
|
||||
class {{classname}} implements {{interfacesToImplement}}
|
||||
{
|
||||
{{#operation}}
|
||||
@ -26,13 +27,25 @@ class {{classname}} implements {{interfacesToImplement}}
|
||||
{{#description}}
|
||||
* {{description}}
|
||||
{{/description}}
|
||||
{{#vendorExtensions}}
|
||||
{{#internal.ze-ph.hasQueryData}}
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={
|
||||
* "type":{{internal.ze-ph.queryDataType}}::class,
|
||||
* "objectAttr":"queryData",
|
||||
* "source": PHAttribute\Transfer::SOURCE_GET
|
||||
* })
|
||||
{{/internal.ze-ph.hasQueryData}}
|
||||
{{/vendorExtensions}}
|
||||
{{#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}}"})
|
||||
{{#isContainer}}
|
||||
* TODO check if attribute is valid and can handle your container type
|
||||
{{/isContainer}}
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":{{dataType}}::class,"objectAttr":"bodyData"})
|
||||
{{/isPrimitiveType}}
|
||||
{{/bodyParam}}
|
||||
{{#produces}}
|
||||
@ -50,10 +63,16 @@ class {{classname}} implements {{interfacesToImplement}}
|
||||
public function {{httpMethod}}(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
{{#vendorExtensions}}
|
||||
{{#internal.ze-ph.hasQueryData}}
|
||||
/** @var {{internal.ze-ph.queryDataType}} $queryData */
|
||||
$queryData = $request->getAttribute("queryData");
|
||||
{{/internal.ze-ph.hasQueryData}}
|
||||
{{/vendorExtensions}}
|
||||
{{#bodyParam}}
|
||||
{{^isPrimitiveType}}
|
||||
/** @var {{dataType}} ${{paramName}} */
|
||||
${{paramName}} = $request->getAttribute("{{paramName}}");
|
||||
/** @var {{dataType}} $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
{{/isPrimitiveType}}
|
||||
{{/bodyParam}}
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
|
@ -1,26 +1,14 @@
|
||||
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
|
||||
Zend\Stratigility\Middleware\ErrorHandler: Zend\Expressive\Container\ErrorHandlerFactory
|
||||
Zend\Expressive\Middleware\ErrorResponseGenerator: Zend\Expressive\Container\WhoopsErrorResponseGeneratorFactory
|
||||
Zend\Expressive\Whoops: Zend\Expressive\Container\WhoopsFactory
|
||||
Zend\Expressive\WhoopsPageHandler: Zend\Expressive\Container\WhoopsPageHandlerFactory
|
||||
|
||||
middleware_pipeline:
|
||||
error:
|
||||
middleware: Zend\Stratigility\Middleware\ErrorHandler
|
||||
middleware: App\ErrorMiddleware
|
||||
api:
|
||||
middleware: Articus\PathHandler\Middleware
|
||||
path: {{basePathWithoutHost}}
|
||||
|
||||
whoops:
|
||||
json_exceptions:
|
||||
display: true
|
||||
show_trace: true
|
||||
ajax_only: true
|
||||
|
@ -7,18 +7,17 @@
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0",
|
||||
"ext-yaml" : "^1.2 || ^2.0",
|
||||
"zendframework/zend-expressive": "^2.0",
|
||||
"zendframework/zend-expressive-router": "^2.1",
|
||||
"zendframework/zend-expressive-zendrouter": "^2.0",
|
||||
"articus/path-handler": "0.2.*",
|
||||
"articus/data-transfer": "*",
|
||||
"zendframework/zend-serializer": "*",
|
||||
"zendframework/zend-config": "*",
|
||||
"filp/whoops": "^2.1.7"
|
||||
"zendframework/zend-expressive": "^2.1",
|
||||
"articus/path-handler": "^0.3",
|
||||
"articus/data-transfer": "^0.1",
|
||||
"zendframework/zend-serializer": "^2.8",
|
||||
"zendframework/zend-config": "^3.1",
|
||||
"nikic/fast-route": "^1.2",
|
||||
"http-interop/http-middleware": "^0.4.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,41 @@
|
||||
#App
|
||||
cache_configuration: false
|
||||
debug: true
|
||||
#Empty configuration placeholder, remove when you add any real configuration settings to this file
|
||||
{}
|
||||
|
||||
#Enable configuration cache
|
||||
#cache_configuration: true
|
||||
|
||||
#Enable routing cache for handlers
|
||||
#Articus\PathHandler\Router\FastRouteAnnotation:
|
||||
# metadata_cache:
|
||||
# adapter:
|
||||
# name: filesystem
|
||||
# options:
|
||||
# cache_dir: data/cache/ZendCache
|
||||
# namespace: fast-route
|
||||
# plugins:
|
||||
# serializer:
|
||||
# serializer: phpserialize
|
||||
|
||||
#Enable consumer, attribute and producer cache for handlers
|
||||
#Articus\PathHandler\Middleware:
|
||||
# metadata_cache:
|
||||
# adapter:
|
||||
# name: filesystem
|
||||
# options:
|
||||
# cache_dir: data/cache/ZendCache
|
||||
# namespace: path-handler
|
||||
# plugins:
|
||||
# serializer:
|
||||
# serializer: phpserialize
|
||||
|
||||
#Enable data transfer metadata cache for DTOs
|
||||
#data_transfer:
|
||||
# metadata_cache:
|
||||
# adapter:
|
||||
# name: filesystem
|
||||
# options:
|
||||
# cache_dir: data/cache/ZendCache
|
||||
# namespace: data-transfer
|
||||
# plugins:
|
||||
# serializer:
|
||||
# serializer: phpserialize
|
||||
|
@ -1,24 +1,28 @@
|
||||
dependencies:
|
||||
factories:
|
||||
Articus\DataTransfer\Service: Articus\DataTransfer\ServiceFactory
|
||||
|
||||
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
|
||||
{{invokerPackage}}\Strategy\QueryParameter: {{invokerPackage}}\Strategy\QueryParameter
|
||||
{{invokerPackage}}\Strategy\QueryParameterArray: {{invokerPackage}}\Strategy\QueryParameterArray
|
||||
# factories:
|
||||
aliases:
|
||||
Date: {{invokerPackage}}\Strategy\Date
|
||||
DateTime: {{invokerPackage}}\Strategy\DateTime
|
||||
QueryParameter: {{invokerPackage}}\Strategy\QueryParameter
|
||||
QueryParameterArray: {{invokerPackage}}\Strategy\QueryParameterArray
|
||||
validators:
|
||||
invokables:
|
||||
{{invokerPackage}}\Validator\Type: {{invokerPackage}}\Validator\Type
|
||||
{{invokerPackage}}\Validator\QueryParameterType: {{invokerPackage}}\Validator\QueryParameterType
|
||||
{{invokerPackage}}\Validator\QueryParameterArrayType: {{invokerPackage}}\Validator\QueryParameterArrayType
|
||||
factories:
|
||||
Articus\DataTransfer\Validator\Dictionary: Articus\DataTransfer\Validator\Factory
|
||||
Articus\DataTransfer\Validator\Collection: Articus\DataTransfer\Validator\Factory
|
||||
@ -26,3 +30,5 @@ data_transfer:
|
||||
Dictionary: Articus\DataTransfer\Validator\Dictionary
|
||||
Collection: Articus\DataTransfer\Validator\Collection
|
||||
Type: {{invokerPackage}}\Validator\Type
|
||||
QueryParameterType: {{invokerPackage}}\Validator\QueryParameterType
|
||||
QueryParameterArrayType: {{invokerPackage}}\Validator\QueryParameterArrayType
|
||||
|
@ -16,114 +16,10 @@ class {{classname}}
|
||||
{{#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}}
|
||||
* @DTA\Data(field="{{baseName}}"{{^required}}, nullable=true{{/required}}){{#vendorExtensions}}{{#internal.ze-ph.fromQuery}}
|
||||
{{>model_query_var}}{{/internal.ze-ph.fromQuery}}{{/vendorExtensions}}{{#vendorExtensions}}{{^internal.ze-ph.fromQuery}}
|
||||
{{>model_normal_var}}{{/internal.ze-ph.fromQuery}}{{/vendorExtensions}}{{^vendorExtensions}}
|
||||
{{>model_normal_var}}{{/vendorExtensions}} * @var {{datatype}}
|
||||
*/
|
||||
public ${{name}};
|
||||
{{/vars}}
|
||||
|
@ -0,0 +1,64 @@
|
||||
{{^isPrimitiveType}}
|
||||
{{^isContainer}}
|
||||
{{^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}}
|
||||
{{/isContainer}}
|
||||
{{#isContainer}}
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":{{#items}}{{datatype}}{{/items}}::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":{{#items}}{{datatype}}{{/items}}::class}}
|
||||
* }})
|
||||
{{/isContainer}}
|
||||
{{/isPrimitiveType}}
|
||||
{{#isPrimitiveType}}
|
||||
{{#isContainer}}
|
||||
{{#items}}
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Type", "options":{"type":"{{datatype}}"}}
|
||||
* }})
|
||||
{{/items}}
|
||||
{{/isContainer}}
|
||||
{{^isContainer}}
|
||||
* @DTA\Validator(name="Type", options={"type":"{{datatype}}"})
|
||||
{{/isContainer}}
|
||||
{{/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}}
|
@ -0,0 +1,54 @@
|
||||
{{^isPrimitiveType}}
|
||||
{{^isContainer}}
|
||||
{{#isDate}}
|
||||
* @DTA\Strategy(name="Date")
|
||||
* @DTA\Validator(name="Date")
|
||||
{{/isDate}}
|
||||
{{#isDateTime}}
|
||||
* @DTA\Strategy(name="DateTime")
|
||||
* @DTA\Validator(name="Date", options={"format": \DateTime::RFC3339})
|
||||
{{/isDateTime}}
|
||||
{{/isContainer}}
|
||||
{{#isContainer}}
|
||||
* TODO add validator(s) and strategy for {{datatype}} and collection format {{internal.ze-ph.collectionFormat}}
|
||||
{{/isContainer}}
|
||||
{{/isPrimitiveType}}
|
||||
{{#isPrimitiveType}}
|
||||
{{#isContainer}}
|
||||
{{#items}}
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="QueryParameterArray", options={"type":"{{datatype}}", "format":"{{internal.ze-ph.collectionFormat}}"})
|
||||
* @DTA\Validator(name="QueryParameterArrayType", options={"type":"{{datatype}}", "format":"{{internal.ze-ph.collectionFormat}}"})
|
||||
{{/items}}
|
||||
{{/isContainer}}
|
||||
{{^isContainer}}
|
||||
* @DTA\Strategy(name="QueryParameter", options={"type":"{{datatype}}"})
|
||||
* @DTA\Validator(name="QueryParameterType", options={"type":"{{datatype}}"})
|
||||
{{/isContainer}}
|
||||
{{/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}}
|
@ -1,27 +1,42 @@
|
||||
path_handler:
|
||||
routes:
|
||||
routes:
|
||||
{{#routes}}{{>route}}{{/routes}}
|
||||
default_params:
|
||||
middleware: ''
|
||||
dependencies:
|
||||
factories:
|
||||
Zend\Expressive\Router\RouterInterface: Articus\PathHandler\Router\Factory\FastRouteAnnotation
|
||||
|
||||
Articus\PathHandler\Middleware:
|
||||
metadata_cache:
|
||||
adapter:
|
||||
name: blackhole
|
||||
handlers:
|
||||
abstract_factories:
|
||||
- Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory
|
||||
# consumers:
|
||||
# factories:
|
||||
# invokables:
|
||||
# attributes:
|
||||
# factories:
|
||||
# invokables:
|
||||
# producers:
|
||||
# factories:
|
||||
# invokables:
|
||||
|
||||
Articus\PathHandler\Router\FastRouteAnnotation:
|
||||
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}}
|
||||
- {{package}}\{{classname}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory:
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{package}}\{{classname}}: []
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
# consumers:
|
||||
# attributes:
|
||||
# producers:
|
||||
|
@ -1,15 +0,0 @@
|
||||
{{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}}
|
@ -1 +1 @@
|
||||
2.3.0-SNAPSHOT
|
||||
2.4.0-SNAPSHOT
|
@ -1,10 +1,34 @@
|
||||
# Swagger generated server
|
||||
|
||||
Generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project.
|
||||
|
||||
## 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 server stub aims to provide light, yet comprehensive structure for your API project using:
|
||||
|
||||
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:
|
||||
- PHP: 5.6 or 7.*
|
||||
- [Zend Expressive](https://zendframework.github.io/zend-expressive): 2.1
|
||||
- [Path Handler](https://github.com/Articus/PathHandler): 0.3
|
||||
|
||||
[TEMPLATES](https://github.com/swagger-api/swagger-codegen/tree/master/modules/swagger-codegen/src/main/resources/ze-ph/)
|
||||
## How to use
|
||||
All you have to do to start development is:
|
||||
|
||||
- install dependencies via [Composer](https://getcomposer.org/)
|
||||
- create cache folder: `mkdir -p ./data/cache/ZendCache` (you will need it later for configuration and metadata caches - check comments in `./application/conig.yml`)
|
||||
- start PHP development server: `php -S 0.0.0.0:8080 -t ./public` (or any other SAPI you prefer, just make sure that you configure webroot to `./public` and rewrites to `./public/index.php`)
|
||||
|
||||
After that you should be able to call all methods from your API spec. Most of the negative scenarios should be handled:
|
||||
|
||||
- `404 Not found` for unknown routes
|
||||
- `406 Not acceptable` for invalid `Accept` header
|
||||
- `415 Unsupported media type` for invalid `Content-Type` header
|
||||
- `400 Malformed JSON` for unparsable JSON body
|
||||
- `422 Unprocessable entity` for parsable JSON body that fails validation
|
||||
|
||||
But for obvious reason you will not get any `200 OK`, only `500 Not implemented`. So your next steps are:
|
||||
|
||||
- check all TODOs left in the stub code where generator was not smart enough and could not guarantee correct implementation
|
||||
- implement your API security mechanism (either special attribute or separate middleware) - generator does not do anything about it yet
|
||||
- implement your handlers - the most tricky part :)
|
||||
|
||||
## Enjoy!
|
||||
Hopefully this stub will reduce the amount of boilerplate code you have to write manually. If you have any suggestions or questions about `ze-ph` generator, feel free to create issue either in [Path Handler repository](https://github.com/Articus/PathHandler/issues) or in [Swagger Codegen repository](https://github.com/swagger-api/swagger-codegen/issues).
|
||||
|
@ -1,3 +1,41 @@
|
||||
#App
|
||||
cache_configuration: false
|
||||
debug: true
|
||||
#Empty configuration placeholder, remove when you add any real configuration settings to this file
|
||||
{}
|
||||
|
||||
#Enable configuration cache
|
||||
#cache_configuration: true
|
||||
|
||||
#Enable routing cache for handlers
|
||||
#Articus\PathHandler\Router\FastRouteAnnotation:
|
||||
# metadata_cache:
|
||||
# adapter:
|
||||
# name: filesystem
|
||||
# options:
|
||||
# cache_dir: data/cache/ZendCache
|
||||
# namespace: fast-route
|
||||
# plugins:
|
||||
# serializer:
|
||||
# serializer: phpserialize
|
||||
|
||||
#Enable consumer, attribute and producer cache for handlers
|
||||
#Articus\PathHandler\Middleware:
|
||||
# metadata_cache:
|
||||
# adapter:
|
||||
# name: filesystem
|
||||
# options:
|
||||
# cache_dir: data/cache/ZendCache
|
||||
# namespace: path-handler
|
||||
# plugins:
|
||||
# serializer:
|
||||
# serializer: phpserialize
|
||||
|
||||
#Enable data transfer metadata cache for DTOs
|
||||
#data_transfer:
|
||||
# metadata_cache:
|
||||
# adapter:
|
||||
# name: filesystem
|
||||
# options:
|
||||
# cache_dir: data/cache/ZendCache
|
||||
# namespace: data-transfer
|
||||
# plugins:
|
||||
# serializer:
|
||||
# serializer: phpserialize
|
||||
|
@ -1,26 +1,14 @@
|
||||
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
|
||||
Zend\Stratigility\Middleware\ErrorHandler: Zend\Expressive\Container\ErrorHandlerFactory
|
||||
Zend\Expressive\Middleware\ErrorResponseGenerator: Zend\Expressive\Container\WhoopsErrorResponseGeneratorFactory
|
||||
Zend\Expressive\Whoops: Zend\Expressive\Container\WhoopsFactory
|
||||
Zend\Expressive\WhoopsPageHandler: Zend\Expressive\Container\WhoopsPageHandlerFactory
|
||||
|
||||
middleware_pipeline:
|
||||
error:
|
||||
middleware: Zend\Stratigility\Middleware\ErrorHandler
|
||||
middleware: App\ErrorMiddleware
|
||||
api:
|
||||
middleware: Articus\PathHandler\Middleware
|
||||
path: /v2
|
||||
|
||||
whoops:
|
||||
json_exceptions:
|
||||
display: true
|
||||
show_trace: true
|
||||
ajax_only: true
|
||||
|
@ -1,24 +1,28 @@
|
||||
dependencies:
|
||||
factories:
|
||||
Articus\DataTransfer\Service: Articus\DataTransfer\ServiceFactory
|
||||
|
||||
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
|
||||
App\Strategy\QueryParameter: App\Strategy\QueryParameter
|
||||
App\Strategy\QueryParameterArray: App\Strategy\QueryParameterArray
|
||||
# factories:
|
||||
aliases:
|
||||
Date: App\Strategy\Date
|
||||
DateTime: App\Strategy\DateTime
|
||||
QueryParameter: App\Strategy\QueryParameter
|
||||
QueryParameterArray: App\Strategy\QueryParameterArray
|
||||
validators:
|
||||
invokables:
|
||||
App\Validator\Type: App\Validator\Type
|
||||
App\Validator\QueryParameterType: App\Validator\QueryParameterType
|
||||
App\Validator\QueryParameterArrayType: App\Validator\QueryParameterArrayType
|
||||
factories:
|
||||
Articus\DataTransfer\Validator\Dictionary: Articus\DataTransfer\Validator\Factory
|
||||
Articus\DataTransfer\Validator\Collection: Articus\DataTransfer\Validator\Factory
|
||||
@ -26,3 +30,5 @@ data_transfer:
|
||||
Dictionary: Articus\DataTransfer\Validator\Dictionary
|
||||
Collection: Articus\DataTransfer\Validator\Collection
|
||||
Type: App\Validator\Type
|
||||
QueryParameterType: App\Validator\QueryParameterType
|
||||
QueryParameterArrayType: App\Validator\QueryParameterArrayType
|
||||
|
@ -1,187 +1,74 @@
|
||||
path_handler:
|
||||
routes:
|
||||
routes:
|
||||
'fake':
|
||||
type: Literal
|
||||
options:
|
||||
route: /fake
|
||||
defaults:
|
||||
handler: Fake
|
||||
may_terminate: true
|
||||
child_routes:
|
||||
'jsonFormData':
|
||||
type: Literal
|
||||
options:
|
||||
route: /jsonFormData
|
||||
defaults:
|
||||
handler: FakeJsonFormData
|
||||
'outer':
|
||||
type: Literal
|
||||
options:
|
||||
route: /outer
|
||||
child_routes:
|
||||
'boolean':
|
||||
type: Literal
|
||||
options:
|
||||
route: /boolean
|
||||
defaults:
|
||||
handler: FakeOuterBoolean
|
||||
'composite':
|
||||
type: Literal
|
||||
options:
|
||||
route: /composite
|
||||
defaults:
|
||||
handler: FakeOuterComposite
|
||||
'number':
|
||||
type: Literal
|
||||
options:
|
||||
route: /number
|
||||
defaults:
|
||||
handler: FakeOuterNumber
|
||||
'string':
|
||||
type: Literal
|
||||
options:
|
||||
route: /string
|
||||
defaults:
|
||||
handler: FakeOuterString
|
||||
'fake_classname_test':
|
||||
type: Literal
|
||||
options:
|
||||
route: /fake_classname_test
|
||||
defaults:
|
||||
handler: FakeClassnameTest
|
||||
'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:
|
||||
'{order_id}':
|
||||
type: Segment
|
||||
options:
|
||||
route: /:order_id
|
||||
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
|
||||
dependencies:
|
||||
factories:
|
||||
Zend\Expressive\Router\RouterInterface: Articus\PathHandler\Router\Factory\FastRouteAnnotation
|
||||
|
||||
default_params:
|
||||
middleware: ''
|
||||
Articus\PathHandler\Middleware:
|
||||
metadata_cache:
|
||||
adapter:
|
||||
name: blackhole
|
||||
# adapter:
|
||||
# name: filesystem
|
||||
# options:
|
||||
# cache_dir: data/cache/path_handler
|
||||
# namespace: ph
|
||||
|
||||
handlers:
|
||||
invokables:
|
||||
Fake: App\Handler\Fake
|
||||
FakeJsonFormData: App\Handler\FakeJsonFormData
|
||||
FakeOuterBoolean: App\Handler\FakeOuterBoolean
|
||||
FakeOuterComposite: App\Handler\FakeOuterComposite
|
||||
FakeOuterNumber: App\Handler\FakeOuterNumber
|
||||
FakeOuterString: App\Handler\FakeOuterString
|
||||
FakeClassnameTest: App\Handler\FakeClassnameTest
|
||||
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
|
||||
abstract_factories:
|
||||
- Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory
|
||||
# consumers:
|
||||
# factories:
|
||||
# invokables:
|
||||
# attributes:
|
||||
# factories:
|
||||
# invokables:
|
||||
# producers:
|
||||
# factories:
|
||||
# invokables:
|
||||
|
||||
Articus\PathHandler\Router\FastRouteAnnotation:
|
||||
metadata_cache:
|
||||
adapter:
|
||||
name: blackhole
|
||||
handlers:
|
||||
- App\Handler\AnotherFakeDummy
|
||||
- App\Handler\Fake
|
||||
- App\Handler\FakeInlineAdditionalProperties
|
||||
- App\Handler\FakeJsonFormData
|
||||
- App\Handler\FakeOuterBoolean
|
||||
- App\Handler\FakeOuterComposite
|
||||
- App\Handler\FakeOuterNumber
|
||||
- App\Handler\FakeOuterString
|
||||
- App\Handler\FakeClassnameTest
|
||||
- App\Handler\Pet
|
||||
- App\Handler\PetFindByStatus
|
||||
- App\Handler\PetFindByTags
|
||||
- App\Handler\PetPetId
|
||||
- App\Handler\PetPetIdUploadImage
|
||||
- App\Handler\StoreInventory
|
||||
- App\Handler\StoreOrder
|
||||
- App\Handler\StoreOrderOrderId
|
||||
- App\Handler\User
|
||||
- App\Handler\UserCreateWithArray
|
||||
- App\Handler\UserCreateWithList
|
||||
- App\Handler\UserLogin
|
||||
- App\Handler\UserLogout
|
||||
- App\Handler\UserUsername
|
||||
|
||||
Zend\ServiceManager\AbstractFactory\ConfigAbstractFactory:
|
||||
App\Handler\AnotherFakeDummy: []
|
||||
App\Handler\Fake: []
|
||||
App\Handler\FakeInlineAdditionalProperties: []
|
||||
App\Handler\FakeJsonFormData: []
|
||||
App\Handler\FakeOuterBoolean: []
|
||||
App\Handler\FakeOuterComposite: []
|
||||
App\Handler\FakeOuterNumber: []
|
||||
App\Handler\FakeOuterString: []
|
||||
App\Handler\FakeClassnameTest: []
|
||||
App\Handler\Pet: []
|
||||
App\Handler\PetFindByStatus: []
|
||||
App\Handler\PetFindByTags: []
|
||||
App\Handler\PetPetId: []
|
||||
App\Handler\PetPetIdUploadImage: []
|
||||
App\Handler\StoreInventory: []
|
||||
App\Handler\StoreOrder: []
|
||||
App\Handler\StoreOrderOrderId: []
|
||||
App\Handler\User: []
|
||||
App\Handler\UserCreateWithArray: []
|
||||
App\Handler\UserCreateWithList: []
|
||||
App\Handler\UserLogin: []
|
||||
App\Handler\UserLogout: []
|
||||
App\Handler\UserUsername: []
|
||||
|
@ -7,18 +7,17 @@
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0",
|
||||
"ext-yaml" : "^1.2 || ^2.0",
|
||||
"zendframework/zend-expressive": "^2.0",
|
||||
"zendframework/zend-expressive-router": "^2.1",
|
||||
"zendframework/zend-expressive-zendrouter": "^2.0",
|
||||
"articus/path-handler": "0.2.*",
|
||||
"articus/data-transfer": "*",
|
||||
"zendframework/zend-serializer": "*",
|
||||
"zendframework/zend-config": "*",
|
||||
"filp/whoops": "^2.1.7"
|
||||
"zendframework/zend-expressive": "^2.1",
|
||||
"articus/path-handler": "^0.3",
|
||||
"articus/data-transfer": "^0.1",
|
||||
"zendframework/zend-serializer": "^2.8",
|
||||
"zendframework/zend-config": "^3.1",
|
||||
"nikic/fast-route": "^1.2",
|
||||
"http-interop/http-middleware": "^0.4.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,13 +10,20 @@ class AdditionalPropertiesClass
|
||||
{
|
||||
/**
|
||||
* @DTA\Data(field="map_property", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Type", "options":{"type":"string"}}
|
||||
* }})
|
||||
* @var map[string,string]
|
||||
*/
|
||||
public $map_property;
|
||||
/**
|
||||
* @DTA\Data(field="map_of_map_property", nullable=true)
|
||||
* @DTA\Strategy(name="Object", options={"type":map[string,map[string,string]]::class})
|
||||
* @DTA\Validator(name="Dictionary", options={"type":map[string,map[string,string]]::class})
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":map[string,string]::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":map[string,string]::class}}
|
||||
* }})
|
||||
* @var map[string,map[string,string]]
|
||||
*/
|
||||
public $map_of_map_property;
|
||||
|
@ -10,6 +10,7 @@ class ArrayOfArrayOfNumberOnly
|
||||
{
|
||||
/**
|
||||
* @DTA\Data(field="ArrayArrayNumber", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":float[]::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":float[]::class}}
|
||||
|
@ -10,6 +10,7 @@ class ArrayOfNumberOnly
|
||||
{
|
||||
/**
|
||||
* @DTA\Data(field="ArrayNumber", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Type", "options":{"type":"float"}}
|
||||
* }})
|
||||
|
@ -10,6 +10,7 @@ class ArrayTest
|
||||
{
|
||||
/**
|
||||
* @DTA\Data(field="array_of_string", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Type", "options":{"type":"string"}}
|
||||
* }})
|
||||
@ -18,6 +19,7 @@ class ArrayTest
|
||||
public $array_of_string;
|
||||
/**
|
||||
* @DTA\Data(field="array_array_of_integer", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":int[]::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":int[]::class}}
|
||||
@ -27,6 +29,7 @@ class ArrayTest
|
||||
public $array_array_of_integer;
|
||||
/**
|
||||
* @DTA\Data(field="array_array_of_model", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":\App\DTO\ReadOnlyFirst[]::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":\App\DTO\ReadOnlyFirst[]::class}}
|
||||
|
@ -16,6 +16,7 @@ class EnumArrays
|
||||
public $just_symbol;
|
||||
/**
|
||||
* @DTA\Data(field="array_enum", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Type", "options":{"type":"string"}}
|
||||
* }})
|
||||
|
@ -23,7 +23,7 @@ class EnumTest
|
||||
/**
|
||||
* @DTA\Data(field="enum_number", nullable=true)
|
||||
* @DTA\Validator(name="Type", options={"type":"float"})
|
||||
* @var double
|
||||
* @var float
|
||||
*/
|
||||
public $enum_number;
|
||||
/**
|
||||
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\DTO;
|
||||
|
||||
use Articus\DataTransfer\Annotation as DTA;
|
||||
|
||||
/**
|
||||
* Query parameters for findPetsByStatus
|
||||
*/
|
||||
class FindPetsByStatusQueryData
|
||||
{
|
||||
/**
|
||||
* Status values that need to be considered for filter
|
||||
* @DTA\Data(field="status")
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="QueryParameterArray", options={"type":"string", "format":"csv"})
|
||||
* @DTA\Validator(name="QueryParameterArrayType", options={"type":"string", "format":"csv"})
|
||||
* @var string[]
|
||||
*/
|
||||
public $status;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\DTO;
|
||||
|
||||
use Articus\DataTransfer\Annotation as DTA;
|
||||
|
||||
/**
|
||||
* Query parameters for findPetsByTags
|
||||
*/
|
||||
class FindPetsByTagsQueryData
|
||||
{
|
||||
/**
|
||||
* Tags to filter by
|
||||
* @DTA\Data(field="tags")
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="QueryParameterArray", options={"type":"string", "format":"csv"})
|
||||
* @DTA\Validator(name="QueryParameterArrayType", options={"type":"string", "format":"csv"})
|
||||
* @var string[]
|
||||
*/
|
||||
public $tags;
|
||||
}
|
@ -51,7 +51,7 @@ class FormatTest
|
||||
* @DTA\Validator(name="Type", options={"type":"float"})
|
||||
* @DTA\Validator(name="GreaterThan", options={"min":67.8, "inclusive":true})
|
||||
* @DTA\Validator(name="LessThan", options={"max":123.4, "inclusive":true})
|
||||
* @var double
|
||||
* @var float
|
||||
*/
|
||||
public $double;
|
||||
/**
|
||||
@ -70,6 +70,7 @@ class FormatTest
|
||||
public $byte;
|
||||
/**
|
||||
* @DTA\Data(field="binary", nullable=true)
|
||||
* @DTA\Validator(name="Type", options={"type":"string"})
|
||||
* @var string
|
||||
*/
|
||||
public $binary;
|
||||
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\DTO;
|
||||
|
||||
use Articus\DataTransfer\Annotation as DTA;
|
||||
|
||||
/**
|
||||
* Query parameters for loginUser
|
||||
*/
|
||||
class LoginUserQueryData
|
||||
{
|
||||
/**
|
||||
* The password for login in clear text
|
||||
* @DTA\Data(field="password")
|
||||
* @DTA\Strategy(name="QueryParameter", options={"type":"string"})
|
||||
* @DTA\Validator(name="QueryParameterType", options={"type":"string"})
|
||||
* @var string
|
||||
*/
|
||||
public $password;
|
||||
/**
|
||||
* The user name for login
|
||||
* @DTA\Data(field="username")
|
||||
* @DTA\Strategy(name="QueryParameter", options={"type":"string"})
|
||||
* @DTA\Validator(name="QueryParameterType", options={"type":"string"})
|
||||
* @var string
|
||||
*/
|
||||
public $username;
|
||||
}
|
@ -10,13 +10,20 @@ class MapTest
|
||||
{
|
||||
/**
|
||||
* @DTA\Data(field="map_map_of_string", nullable=true)
|
||||
* @DTA\Strategy(name="Object", options={"type":map[string,map[string,string]]::class})
|
||||
* @DTA\Validator(name="Dictionary", options={"type":map[string,map[string,string]]::class})
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":map[string,string]::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":map[string,string]::class}}
|
||||
* }})
|
||||
* @var map[string,map[string,string]]
|
||||
*/
|
||||
public $map_map_of_string;
|
||||
/**
|
||||
* @DTA\Data(field="map_of_enum_string", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Type", "options":{"type":"string"}}
|
||||
* }})
|
||||
* @var map[string,string]
|
||||
*/
|
||||
public $map_of_enum_string;
|
||||
|
@ -23,8 +23,11 @@ class MixedPropertiesAndAdditionalPropertiesClass
|
||||
public $date_time;
|
||||
/**
|
||||
* @DTA\Data(field="map", nullable=true)
|
||||
* @DTA\Strategy(name="Object", options={"type":map[string,\App\DTO\Animal]::class})
|
||||
* @DTA\Validator(name="Dictionary", options={"type":map[string,\App\DTO\Animal]::class})
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":\App\DTO\Animal::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":\App\DTO\Animal::class}}
|
||||
* }})
|
||||
* @var map[string,\App\DTO\Animal]
|
||||
*/
|
||||
public $map;
|
||||
|
@ -29,6 +29,7 @@ class Pet
|
||||
public $name;
|
||||
/**
|
||||
* @DTA\Data(field="photoUrls")
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Type", "options":{"type":"string"}}
|
||||
* }})
|
||||
@ -37,6 +38,7 @@ class Pet
|
||||
public $photo_urls;
|
||||
/**
|
||||
* @DTA\Data(field="tags", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="ObjectArray", options={"type":\App\DTO\Tag::class})
|
||||
* @DTA\Validator(name="Collection", options={"validators":{
|
||||
* {"name":"Dictionary", "options":{"type":\App\DTO\Tag::class}}
|
||||
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\DTO;
|
||||
|
||||
use Articus\DataTransfer\Annotation as DTA;
|
||||
|
||||
/**
|
||||
* Query parameters for testEnumParameters
|
||||
*/
|
||||
class TestEnumParametersQueryData
|
||||
{
|
||||
/**
|
||||
* Query parameter enum test (string)
|
||||
* @DTA\Data(field="enum_query_string", nullable=true)
|
||||
* @DTA\Strategy(name="QueryParameter", options={"type":"string"})
|
||||
* @DTA\Validator(name="QueryParameterType", options={"type":"string"})
|
||||
* @var string
|
||||
*/
|
||||
public $enum_query_string;
|
||||
/**
|
||||
* Query parameter enum test (double)
|
||||
* @DTA\Data(field="enum_query_integer", nullable=true)
|
||||
* @DTA\Strategy(name="QueryParameter", options={"type":"int"})
|
||||
* @DTA\Validator(name="QueryParameterType", options={"type":"int"})
|
||||
* @var int
|
||||
*/
|
||||
public $enum_query_integer;
|
||||
/**
|
||||
* Query parameter enum test (string array)
|
||||
* @DTA\Data(field="enum_query_string_array", nullable=true)
|
||||
* TODO check validator and strategy are correct and can handle container item type
|
||||
* @DTA\Strategy(name="QueryParameterArray", options={"type":"string", "format":"csv"})
|
||||
* @DTA\Validator(name="QueryParameterArrayType", options={"type":"string", "format":"csv"})
|
||||
* @var string[]
|
||||
*/
|
||||
public $enum_query_string_array;
|
||||
}
|
34
samples/server/petstore/ze-ph/src/App/ErrorMiddleware.php
Normal file
34
samples/server/petstore/ze-ph/src/App/ErrorMiddleware.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Interop\Http\ServerMiddleware\DelegateInterface;
|
||||
use Interop\Http\ServerMiddleware\MiddlewareInterface;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Zend\Stdlib\ErrorHandler;
|
||||
|
||||
class ErrorMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, DelegateInterface $delegate)
|
||||
{
|
||||
$result = null;
|
||||
try {
|
||||
ErrorHandler::start();
|
||||
$result = $delegate->process($request);
|
||||
ErrorHandler::stop(true);
|
||||
if (!($result instanceof Response)) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Invalid response: expecting %s, got %s',
|
||||
Response::class,
|
||||
is_object($result)? get_class($result) : gettype($result)
|
||||
));
|
||||
}
|
||||
}
|
||||
catch (\Exception $error) {
|
||||
$result = (new \Zend\Diactoros\Response())->withStatus(500, 'Internal server error');
|
||||
error_log((string)$error);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/another-fake/dummy")
|
||||
*/
|
||||
class AnotherFakeDummy implements Operation\PatchInterface
|
||||
{
|
||||
/**
|
||||
* To test special tags
|
||||
* 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")
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Client::class,"objectAttr":"bodyData"})
|
||||
* 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")
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws PHException\HttpCode 500 if the method is not implemented
|
||||
*
|
||||
* @return \App\DTO\Client
|
||||
*/
|
||||
public function handlePatch(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\Client $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
@ -10,13 +10,16 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake")
|
||||
*/
|
||||
class Fake implements Operation\PatchInterface, Operation\PostInterface, Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
* To test \"client\" model
|
||||
* 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")
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Client::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Client::class,"objectAttr":"bodyData"})
|
||||
* 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")
|
||||
* @param ServerRequestInterface $request
|
||||
@ -28,16 +31,16 @@ class Fake implements Operation\PatchInterface, Operation\PostInterface, Operati
|
||||
public function handlePatch(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\Client $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\Client $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
/**
|
||||
* Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
|
||||
* 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; charset=utf-8")
|
||||
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/xml; charset=utf-8")
|
||||
* 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; charset=utf-8")
|
||||
* @PHA\Producer(name=PHProducer\Transfer::class, mediaType="application/json; charset=utf-8")
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws PHException\HttpCode 500 if the method is not implemented
|
||||
@ -49,6 +52,11 @@ class Fake implements Operation\PatchInterface, Operation\PostInterface, Operati
|
||||
}
|
||||
/**
|
||||
* To test enum parameters
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={
|
||||
* "type":\App\DTO\TestEnumParametersQueryData::class,
|
||||
* "objectAttr":"queryData",
|
||||
* "source": PHAttribute\Transfer::SOURCE_GET
|
||||
* })
|
||||
* 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="*/*")
|
||||
* @param ServerRequestInterface $request
|
||||
@ -58,6 +66,8 @@ class Fake implements Operation\PatchInterface, Operation\PostInterface, Operati
|
||||
public function handleGet(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\TestEnumParametersQueryData $queryData */
|
||||
$queryData = $request->getAttribute("queryData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,16 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake_classname_test")
|
||||
*/
|
||||
class FakeClassnameTest implements Operation\PatchInterface
|
||||
{
|
||||
/**
|
||||
* To test class name in snake case
|
||||
* 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")
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Client::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Client::class,"objectAttr":"bodyData"})
|
||||
* 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")
|
||||
* @param ServerRequestInterface $request
|
||||
@ -28,8 +31,8 @@ class FakeClassnameTest implements Operation\PatchInterface
|
||||
public function handlePatch(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\Client $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\Client $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake/inline-additionalProperties")
|
||||
*/
|
||||
class FakeInlineAdditionalProperties implements Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
* test inline additionalProperties
|
||||
* 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")
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws PHException\HttpCode 500 if the method is not implemented
|
||||
*/
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake/jsonFormData")
|
||||
*/
|
||||
class FakeJsonFormData implements Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
|
@ -10,10 +10,13 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake/outer/boolean")
|
||||
*/
|
||||
class FakeOuterBoolean implements Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterBoolean::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterBoolean::class,"objectAttr":"bodyData"})
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws PHException\HttpCode 500 if the method is not implemented
|
||||
@ -23,8 +26,8 @@ class FakeOuterBoolean implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\OuterBoolean $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\OuterBoolean $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake/outer/composite")
|
||||
*/
|
||||
class FakeOuterComposite implements Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterComposite::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterComposite::class,"objectAttr":"bodyData"})
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws PHException\HttpCode 500 if the method is not implemented
|
||||
@ -23,8 +26,8 @@ class FakeOuterComposite implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\OuterComposite $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\OuterComposite $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake/outer/number")
|
||||
*/
|
||||
class FakeOuterNumber implements Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterNumber::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterNumber::class,"objectAttr":"bodyData"})
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws PHException\HttpCode 500 if the method is not implemented
|
||||
@ -23,8 +26,8 @@ class FakeOuterNumber implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\OuterNumber $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\OuterNumber $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/fake/outer/string")
|
||||
*/
|
||||
class FakeOuterString implements Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterString::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\OuterString::class,"objectAttr":"bodyData"})
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws PHException\HttpCode 500 if the method is not implemented
|
||||
@ -23,8 +26,8 @@ class FakeOuterString implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\OuterString $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\OuterString $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/pet")
|
||||
*/
|
||||
class Pet implements Operation\PostInterface, Operation\PutInterface
|
||||
{
|
||||
/**
|
||||
@ -18,7 +21,7 @@ class Pet implements Operation\PostInterface, Operation\PutInterface
|
||||
* @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"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Pet::class,"objectAttr":"bodyData"})
|
||||
* 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
|
||||
@ -30,8 +33,8 @@ class Pet implements Operation\PostInterface, Operation\PutInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\Pet $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\Pet $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
/**
|
||||
@ -40,7 +43,7 @@ class Pet implements Operation\PostInterface, Operation\PutInterface
|
||||
* @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"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Pet::class,"objectAttr":"bodyData"})
|
||||
* 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
|
||||
@ -52,8 +55,8 @@ class Pet implements Operation\PostInterface, Operation\PutInterface
|
||||
public function handlePut(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\Pet $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\Pet $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,18 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/pet/findByStatus")
|
||||
*/
|
||||
class PetFindByStatus implements Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
* Finds Pets by status
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={
|
||||
* "type":\App\DTO\FindPetsByStatusQueryData::class,
|
||||
* "objectAttr":"queryData",
|
||||
* "source": PHAttribute\Transfer::SOURCE_GET
|
||||
* })
|
||||
* 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
|
||||
@ -27,6 +35,8 @@ class PetFindByStatus implements Operation\GetInterface
|
||||
public function handleGet(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\FindPetsByStatusQueryData $queryData */
|
||||
$queryData = $request->getAttribute("queryData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,18 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/pet/findByTags")
|
||||
*/
|
||||
class PetFindByTags implements Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
* Finds Pets by tags
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={
|
||||
* "type":\App\DTO\FindPetsByTagsQueryData::class,
|
||||
* "objectAttr":"queryData",
|
||||
* "source": PHAttribute\Transfer::SOURCE_GET
|
||||
* })
|
||||
* 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
|
||||
@ -27,6 +35,8 @@ class PetFindByTags implements Operation\GetInterface
|
||||
public function handleGet(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\FindPetsByTagsQueryData $queryData */
|
||||
$queryData = $request->getAttribute("queryData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/pet/{petId}")
|
||||
*/
|
||||
class PetPetId implements Operation\DeleteInterface, Operation\GetInterface, Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/pet/{petId}/uploadImage")
|
||||
*/
|
||||
class PetPetIdUploadImage implements Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/store/inventory")
|
||||
*/
|
||||
class StoreInventory implements Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
|
@ -10,11 +10,14 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/store/order")
|
||||
*/
|
||||
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"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\Order::class,"objectAttr":"bodyData"})
|
||||
* 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
|
||||
@ -28,8 +31,8 @@ class StoreOrder implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\Order $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\Order $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/store/order/{order_id}")
|
||||
*/
|
||||
class StoreOrderOrderId implements Operation\DeleteInterface, Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
|
@ -10,11 +10,14 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/user")
|
||||
*/
|
||||
class User implements Operation\PostInterface
|
||||
{
|
||||
/**
|
||||
* Create user
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User::class,"objectAttr":"bodyData"})
|
||||
* 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
|
||||
@ -26,8 +29,8 @@ class User implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\User $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\User $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,15 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/user/createWithArray")
|
||||
*/
|
||||
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 attribute is valid and can handle your container type
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User[]::class,"objectAttr":"bodyData"})
|
||||
* 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
|
||||
@ -26,8 +30,8 @@ class UserCreateWithArray implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\User[] $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\User[] $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,15 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/user/createWithList")
|
||||
*/
|
||||
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 attribute is valid and can handle your container type
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User[]::class,"objectAttr":"bodyData"})
|
||||
* 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
|
||||
@ -26,8 +30,8 @@ class UserCreateWithList implements Operation\PostInterface
|
||||
public function handlePost(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\User[] $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\User[] $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,18 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/user/login")
|
||||
*/
|
||||
class UserLogin implements Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
* Logs user into the system
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={
|
||||
* "type":\App\DTO\LoginUserQueryData::class,
|
||||
* "objectAttr":"queryData",
|
||||
* "source": PHAttribute\Transfer::SOURCE_GET
|
||||
* })
|
||||
* 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
|
||||
@ -27,6 +35,8 @@ class UserLogin implements Operation\GetInterface
|
||||
public function handleGet(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\LoginUserQueryData $queryData */
|
||||
$queryData = $request->getAttribute("queryData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/user/logout")
|
||||
*/
|
||||
class UserLogout implements Operation\GetInterface
|
||||
{
|
||||
/**
|
||||
|
@ -10,6 +10,9 @@ use Articus\PathHandler\Attribute as PHAttribute;
|
||||
use Articus\PathHandler\Exception as PHException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* @PHA\Route(pattern="/user/{username}")
|
||||
*/
|
||||
class UserUsername implements Operation\DeleteInterface, Operation\GetInterface, Operation\PutInterface
|
||||
{
|
||||
/**
|
||||
@ -46,7 +49,7 @@ class UserUsername implements Operation\DeleteInterface, Operation\GetInterface,
|
||||
}
|
||||
/**
|
||||
* Updated user
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User::class,"objectAttr":"body"})
|
||||
* @PHA\Attribute(name=PHAttribute\Transfer::class, options={"type":\App\DTO\User::class,"objectAttr":"bodyData"})
|
||||
* 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
|
||||
@ -58,8 +61,8 @@ class UserUsername implements Operation\DeleteInterface, Operation\GetInterface,
|
||||
public function handlePut(ServerRequestInterface $request)
|
||||
{
|
||||
//TODO implement method
|
||||
/** @var \App\DTO\User $body */
|
||||
$body = $request->getAttribute("body");
|
||||
/** @var \App\DTO\User $bodyData */
|
||||
$bodyData = $request->getAttribute("bodyData");
|
||||
throw new PHException\HttpCode(500, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Strategy;
|
||||
|
||||
use Articus\DataTransfer\Strategy\StrategyInterface;
|
||||
|
||||
class QueryParameter implements StrategyInterface
|
||||
{
|
||||
const TYPE_INT = 'int';
|
||||
const TYPE_FLOAT = 'float';
|
||||
const TYPE_BOOL = 'bool';
|
||||
const TYPE_STRING = 'string';
|
||||
|
||||
const TYPE_MAP = [
|
||||
self::TYPE_INT => true,
|
||||
self::TYPE_FLOAT => true,
|
||||
self::TYPE_BOOL => true,
|
||||
self::TYPE_STRING => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* QueryParameterArray constructor.
|
||||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
if (empty($options['type'])) {
|
||||
throw new \InvalidArgumentException('Option "type" is required.');
|
||||
} elseif (!isset(self::TYPE_MAP[$options['type']])) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown type "%s".', $options['type']));
|
||||
}
|
||||
$this->type = $options['type'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function extract($objectValue, $object = null)
|
||||
{
|
||||
$result = null;
|
||||
if ($objectValue !== null) {
|
||||
$result = (string)$objectValue;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function hydrate($arrayValue, $objectValue, array $array = null)
|
||||
{
|
||||
$result = null;
|
||||
if ($arrayValue !== null) {
|
||||
switch ($this->type) {
|
||||
case self::TYPE_INT:
|
||||
$result = (int)$arrayValue;
|
||||
break;
|
||||
case self::TYPE_FLOAT:
|
||||
$result = (float)$arrayValue;
|
||||
break;
|
||||
case self::TYPE_BOOL:
|
||||
$result = ($arrayValue === 'true')? true : false;
|
||||
break;
|
||||
case self::TYPE_STRING:
|
||||
$result = (string)$arrayValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Strategy;
|
||||
|
||||
class QueryParameterArray extends QueryParameter
|
||||
{
|
||||
const FORMAT_CSV = 'csv'; //comma separated values foo,bar.
|
||||
const FORMAT_SSV = 'ssv'; //space separated values foo bar.
|
||||
const FORMAT_TSV = 'tsv'; //tab separated values foo\tbar.
|
||||
const FORMAT_PIPES = 'pipes'; //pipe separated values foo|bar.
|
||||
const FORMAT_MULTI = 'multi'; //corresponds to multiple parameter instances instead of multiple values for a single instance foo[]=bar&foo[]=baz.
|
||||
|
||||
const DELIMITER_MAP = [
|
||||
self::FORMAT_CSV => ',',
|
||||
self::FORMAT_SSV => ' ',
|
||||
self::FORMAT_TSV => "\t",
|
||||
self::FORMAT_PIPES => '|',
|
||||
self::FORMAT_MULTI => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $delimiter;
|
||||
|
||||
public function __construct(array $options)
|
||||
{
|
||||
parent::__construct($options);
|
||||
if (empty($options['format'])) {
|
||||
throw new \InvalidArgumentException('Option "format" is required.');
|
||||
} elseif (!array_key_exists($options['format'], self::DELIMITER_MAP)) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown format "%s".', $options['format']));
|
||||
}
|
||||
$this->delimiter = self::DELIMITER_MAP[$options['format']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function extract($objectValue, $object = null)
|
||||
{
|
||||
$result = null;
|
||||
if (is_array($objectValue)) {
|
||||
if ($this->delimiter === null) {
|
||||
$result = $objectValue;
|
||||
} else {
|
||||
$result = implode($this->delimiter, $objectValue);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function hydrate($arrayValue, $objectValue, array $array = null)
|
||||
{
|
||||
$result = null;
|
||||
if ($arrayValue !== null) {
|
||||
$list = null;
|
||||
if ($this->delimiter === null) {
|
||||
$list = (is_array($arrayValue))? $arrayValue : [$arrayValue];
|
||||
} else {
|
||||
$list = explode($this->delimiter, $arrayValue);
|
||||
}
|
||||
$result = [];
|
||||
foreach ($list as $item) {
|
||||
$result[] = parent::hydrate($item, null);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace App\Validator;
|
||||
|
||||
use App\Strategy\QueryParameterArray;
|
||||
|
||||
class QueryParameterArrayType extends QueryParameterType
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $format;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFormat()
|
||||
{
|
||||
return $this->format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $format
|
||||
* @return self
|
||||
*/
|
||||
public function setFormat($format)
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function checkType($value)
|
||||
{
|
||||
$result = true;
|
||||
if (!array_key_exists($this->format, QueryParameterArray::DELIMITER_MAP)) {
|
||||
throw new \InvalidArgumentException(sprintf('Can not check for format %s.', $this->format));
|
||||
}
|
||||
$delimiter = QueryParameterArray::DELIMITER_MAP[$this->format];
|
||||
if ($delimiter === null) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
$result = $result && parent::checkType($item);
|
||||
}
|
||||
} else {
|
||||
$result = false;
|
||||
}
|
||||
} else {
|
||||
switch ($this->type) {
|
||||
case QueryParameterArray::TYPE_INT:
|
||||
$result = is_string($value) && preg_match(self::prepareRepeatingTypeRegExp(self::RE_INT, $delimiter), $value);
|
||||
break;
|
||||
case QueryParameterArray::TYPE_BOOL:
|
||||
$result = is_string($value) && preg_match(self::prepareRepeatingTypeRegExp(self::RE_BOOL, $delimiter), $value);
|
||||
break;
|
||||
case QueryParameterArray::TYPE_FLOAT:
|
||||
$result = is_string($value) && preg_match(self::prepareRepeatingTypeRegExp(self::RE_FLOAT, $delimiter), $value);
|
||||
break;
|
||||
case QueryParameterArray::TYPE_STRING:
|
||||
$result = is_string($value);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Can not check for type %s.', $this->type));
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected static function prepareRepeatingTypeRegExp($typeRegExp, $delimiter)
|
||||
{
|
||||
$escapedDelimiter = preg_quote($delimiter, '/');
|
||||
return '/^(' . $typeRegExp . ')(' . $escapedDelimiter . '('. $typeRegExp . '))*$/';
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace App\Validator;
|
||||
|
||||
use App\Strategy\QueryParameter;
|
||||
|
||||
class QueryParameterType extends Type
|
||||
{
|
||||
const RE_INT = '0|-?[1-9]\d*';
|
||||
const RE_BOOL = 'true|false';
|
||||
const RE_FLOAT = '0(\.\d+)?|-?[1-9]\d*(\.\d+)?|-0\.\d+';
|
||||
|
||||
protected function checkType($value)
|
||||
{
|
||||
switch ($this->type) {
|
||||
case QueryParameter::TYPE_INT:
|
||||
return is_string($value) && preg_match('/^(' . self::RE_INT . ')$/', $value);
|
||||
case QueryParameter::TYPE_BOOL:
|
||||
return is_string($value) && preg_match('/^(' . self::RE_BOOL . ')$/', $value);
|
||||
case QueryParameter::TYPE_FLOAT:
|
||||
return is_string($value) && preg_match('/^(' . self::RE_FLOAT . ')$/', $value);
|
||||
case QueryParameter::TYPE_STRING:
|
||||
return is_string($value);
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Can not check for type %s.', $this->type));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user