added map support for #360

This commit is contained in:
Tony Tam 2014-12-25 08:17:41 -08:00
parent 93eca2a6b6
commit 21396d0797
3 changed files with 152 additions and 143 deletions

View File

@ -44,6 +44,7 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
languageSpecificPrimitives.add("int"); languageSpecificPrimitives.add("int");
languageSpecificPrimitives.add("array"); languageSpecificPrimitives.add("array");
languageSpecificPrimitives.add("map");
languageSpecificPrimitives.add("string"); languageSpecificPrimitives.add("string");
languageSpecificPrimitives.add("DateTime"); languageSpecificPrimitives.add("DateTime");
@ -52,7 +53,7 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
typeMapping.put("Array", "array"); typeMapping.put("Array", "array");
typeMapping.put("String", "string"); typeMapping.put("String", "string");
typeMapping.put("List", "array"); typeMapping.put("List", "array");
typeMapping.put("map", "array"); typeMapping.put("map", "map");
supportingFiles.add(new SupportingFile("Swagger.mustache", "", "Swagger.php")); supportingFiles.add(new SupportingFile("Swagger.mustache", "", "Swagger.php"));
} }
@ -81,7 +82,7 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
else if (p instanceof MapProperty) { else if (p instanceof MapProperty) {
MapProperty mp = (MapProperty) p; MapProperty mp = (MapProperty) p;
Property inner = mp.getAdditionalProperties(); Property inner = mp.getAdditionalProperties();
return getSwaggerType(p) + "[string]"; return getSwaggerType(p) + "[string," + getTypeDeclaration(inner) + "]";
} }
return super.getTypeDeclaration(p); return super.getTypeDeclaration(p);
} }

View File

@ -11,117 +11,116 @@
* @param string $className the class to attempt to load * @param string $className the class to attempt to load
*/ */
function swagger_autoloader($className) { function swagger_autoloader($className) {
$currentDir = dirname(__FILE__); $currentDir = dirname(__FILE__);
if (file_exists($currentDir . '/' . $className . '.php')) { if (file_exists($currentDir . '/' . $className . '.php')) {
include $currentDir . '/' . $className . '.php'; include $currentDir . '/' . $className . '.php';
} elseif (file_exists($currentDir . '/models/' . $className . '.php')) { } elseif (file_exists($currentDir . '/models/' . $className . '.php')) {
include $currentDir . '/models/' . $className . '.php'; include $currentDir . '/models/' . $className . '.php';
} }
} }
spl_autoload_register('swagger_autoloader'); spl_autoload_register('swagger_autoloader');
class APIClient { class APIClient {
public static $POST = "POST"; public static $POST = "POST";
public static $GET = "GET"; public static $GET = "GET";
public static $PUT = "PUT"; public static $PUT = "PUT";
public static $DELETE = "DELETE"; public static $DELETE = "DELETE";
/** /**
* @param string $apiKey your API key * @param string $apiKey your API key
* @param string $apiServer the address of the API server * @param string $apiServer the address of the API server
*/ */
function __construct($apiKey, $apiServer) { function __construct($apiKey, $apiServer) {
$this->apiKey = $apiKey; $this->apiKey = $apiKey;
$this->apiServer = $apiServer; $this->apiServer = $apiServer;
} }
/** /**
* @param string $resourcePath path to method endpoint * @param string $resourcePath path to method endpoint
* @param string $method method to call * @param string $method method to call
* @param array $queryParams parameters to be place in query URL * @param array $queryParams parameters to be place in query URL
* @param array $postData parameters to be placed in POST body * @param array $postData parameters to be placed in POST body
* @param array $headerParams parameters to be place in request header * @param array $headerParams parameters to be place in request header
* @return mixed * @return mixed
*/ */
public function callAPI($resourcePath, $method, $queryParams, $postData, public function callAPI($resourcePath, $method, $queryParams, $postData,
$headerParams) { $headerParams) {
$headers = array(); $headers = array();
# Allow API key from $headerParams to override default # Allow API key from $headerParams to override default
$added_api_key = False; $added_api_key = False;
if ($headerParams != null) { if ($headerParams != null) {
foreach ($headerParams as $key => $val) { foreach ($headerParams as $key => $val) {
$headers[] = "$key: $val"; $headers[] = "$key: $val";
if ($key == 'api_key') { if ($key == 'api_key') {
$added_api_key = True; $added_api_key = True;
} }
} }
} }
if (! $added_api_key) { if (! $added_api_key) {
$headers[] = "api_key: " . $this->apiKey; $headers[] = "api_key: " . $this->apiKey;
} }
if (is_object($postData) or is_array($postData)) { if (is_object($postData) or is_array($postData)) {
$postData = json_encode($this->sanitizeForSerialization($postData)); $postData = json_encode($this->sanitizeForSerialization($postData));
} }
$url = $this->apiServer . $resourcePath; $url = $this->apiServer . $resourcePath;
$curl = curl_init(); $curl = curl_init();
curl_setopt($curl, CURLOPT_TIMEOUT, 5); curl_setopt($curl, CURLOPT_TIMEOUT, 5);
// return the result on success, rather than just TRUE // return the result on success, rather than just TRUE
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
if (! empty($queryParams)) { if (! empty($queryParams)) {
$url = ($url . '?' . http_build_query($queryParams)); $url = ($url . '?' . http_build_query($queryParams));
} }
if ($method == self::$POST) { if ($method == self::$POST) {
curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
} else if ($method == self::$PUT) { } else if ($method == self::$PUT) {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
} else if ($method == self::$DELETE) { } else if ($method == self::$DELETE) {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
} else if ($method != self::$GET) { } else if ($method != self::$GET) {
throw new Exception('Method ' . $method . ' is not recognized.'); throw new Exception('Method ' . $method . ' is not recognized.');
} }
curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_URL, $url);
// Make the request // Make the request
$response = curl_exec($curl); $response = curl_exec($curl);
$response_info = curl_getinfo($curl); $response_info = curl_getinfo($curl);
// Handle the response // Handle the response
if ($response_info['http_code'] == 0) { if ($response_info['http_code'] == 0) {
throw new Exception("TIMEOUT: api call to " . $url . throw new Exception("TIMEOUT: api call to " . $url .
" took more than 5s to return" ); " took more than 5s to return" );
} else if ($response_info['http_code'] == 200) { } else if ($response_info['http_code'] == 200) {
$data = json_decode($response); $data = json_decode($response);
} else if ($response_info['http_code'] == 401) { } else if ($response_info['http_code'] == 401) {
throw new Exception("Unauthorized API request to " . $url . throw new Exception("Unauthorized API request to " . $url .
": ".json_decode($response)->message ); ": ".json_decode($response)->message );
} else if ($response_info['http_code'] == 404) { } else if ($response_info['http_code'] == 404) {
$data = null; $data = null;
} else { } else {
throw new Exception("Can't connect to the api: " . $url . throw new Exception("Can't connect to the api: " . $url .
" response code: " . " response code: " .
$response_info['http_code']); $response_info['http_code']);
} }
return $data;
}
return $data; /**
} * Build a JSON POST object
*/
/**
* Build a JSON POST object
*/
protected function sanitizeForSerialization($data) protected function sanitizeForSerialization($data)
{ {
if (is_scalar($data) || null === $data) { if (is_scalar($data) || null === $data) {
@ -146,41 +145,41 @@ class APIClient {
return $sanitized; return $sanitized;
} }
/** /**
* Take value and turn it into a string suitable for inclusion in * Take value and turn it into a string suitable for inclusion in
* the path, by url-encoding. * the path, by url-encoding.
* @param string $value a string which will be part of the path * @param string $value a string which will be part of the path
* @return string the serialized object * @return string the serialized object
*/ */
public static function toPathValue($value) { public static function toPathValue($value) {
return rawurlencode($value); return rawurlencode($value);
} }
/** /**
* Take value and turn it into a string suitable for inclusion in * Take value and turn it into a string suitable for inclusion in
* the query, by imploding comma-separated if it's an object. * the query, by imploding comma-separated if it's an object.
* If it's a string, pass through unchanged. It will be url-encoded * If it's a string, pass through unchanged. It will be url-encoded
* later. * later.
* @param object $object an object to be serialized to a string * @param object $object an object to be serialized to a string
* @return string the serialized object * @return string the serialized object
*/ */
public static function toQueryValue($object) { public static function toQueryValue($object) {
if (is_array($object)) { if (is_array($object)) {
return implode(',', $object); return implode(',', $object);
} else { } else {
return $object; return $object;
} }
} }
/** /**
* Just pass through the header value for now. Placeholder in case we * Just pass through the header value for now. Placeholder in case we
* find out we need to do something with header values. * find out we need to do something with header values.
* @param string $value a string which will be part of the header * @param string $value a string which will be part of the header
* @return string the header string * @return string the header string
*/ */
public static function toHeaderValue($value) { public static function toHeaderValue($value) {
return $value; return $value;
} }
/** /**
* Deserialize a JSON string into an object * Deserialize a JSON string into an object
@ -194,10 +193,19 @@ class APIClient {
{ {
if (null === $data) { if (null === $data) {
$deserialized = null; $deserialized = null;
} else if (substr($class, 0, 6) == 'array[') { } elseif (substr($class, 0, 4) == 'map[') {
$subClass = substr($class, 6, -1); $inner = substr($class, 4, -1);
$values = array(); $values = array();
foreach ($data as $value) { if(strrpos($inner, ",") !== false) {
$subClass = explode(',', $inner, 2)[1];
foreach ($data as $key => $value) {
$values[] = array($key => self::deserialize($value, $subClass));
}
}
$deserialized = $values;
} elseif (substr($class, 0, 6) == 'array[') {
$subClass = substr($class, 6, -1);
foreach ($data as $key => $value) {
$values[] = self::deserialize($value, $subClass); $values[] = self::deserialize($value, $subClass);
} }
$deserialized = $values; $deserialized = $values;

View File

@ -1,10 +1,12 @@
package php package php
import com.wordnik.swagger.codegen.languages.PhpClientCodegen import com.wordnik.swagger.codegen.languages.PhpClientCodegen
import com.wordnik.swagger.util.{ Json, SwaggerLoader } import com.wordnik.swagger.util.Json
import com.wordnik.swagger.models._ import com.wordnik.swagger.models._
import com.wordnik.swagger.models.properties._ import com.wordnik.swagger.models.properties._
import io.swagger.parser.SwaggerParser
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner import org.scalatest.junit.JUnitRunner
import org.scalatest.FlatSpec import org.scalatest.FlatSpec
@ -121,9 +123,9 @@ class PhpModelTest extends FlatSpec with Matchers {
val vars = cm.vars val vars = cm.vars
vars.get(0).baseName should be ("translations") vars.get(0).baseName should be ("translations")
vars.get(0).datatype should be ("array[string]") vars.get(0).datatype should be ("map[string,string]")
vars.get(0).name should be ("translations") vars.get(0).name should be ("translations")
vars.get(0).baseType should be ("array") vars.get(0).baseType should be ("map")
vars.get(0).containerType should be ("map") vars.get(0).containerType should be ("map")
vars.get(0).required should equal (false) vars.get(0).required should equal (false)
vars.get(0).isContainer should equal (true) vars.get(0).isContainer should equal (true)
@ -151,7 +153,7 @@ class PhpModelTest extends FlatSpec with Matchers {
vars.get(0).required should equal (false) vars.get(0).required should equal (false)
vars.get(0).isNotContainer should equal (true) vars.get(0).isNotContainer should equal (true)
} }
/*
it should "convert a model with complex list property" in { it should "convert a model with complex list property" in {
val model = new ModelImpl() val model = new ModelImpl()
.description("a sample model") .description("a sample model")
@ -168,10 +170,10 @@ class PhpModelTest extends FlatSpec with Matchers {
val vars = cm.vars val vars = cm.vars
vars.get(0).baseName should be ("children") vars.get(0).baseName should be ("children")
vars.get(0).complexType should be ("SWGChildren") vars.get(0).complexType should be ("Children")
vars.get(0).datatype should be ("NSArray*") vars.get(0).datatype should be ("array[Children]")
vars.get(0).name should be ("children") vars.get(0).name should be ("children")
vars.get(0).baseType should be ("NSArray") vars.get(0).baseType should be ("array")
vars.get(0).containerType should be ("array") vars.get(0).containerType should be ("array")
vars.get(0).required should equal (false) vars.get(0).required should equal (false)
vars.get(0).isContainer should equal (true) vars.get(0).isContainer should equal (true)
@ -190,14 +192,14 @@ class PhpModelTest extends FlatSpec with Matchers {
cm.classname should be ("Sample") cm.classname should be ("Sample")
cm.description should be ("a sample model") cm.description should be ("a sample model")
cm.vars.size should be (1) cm.vars.size should be (1)
(cm.imports.asScala.toSet & Set("SWGChildren")).size should be (1) (cm.imports.asScala.toSet & Set("Children")).size should be (1)
val vars = cm.vars val vars = cm.vars
vars.get(0).baseName should be ("children") vars.get(0).baseName should be ("children")
vars.get(0).complexType should be ("SWGChildren") vars.get(0).complexType should be ("Children")
vars.get(0).datatype should be ("NSDictionary*") vars.get(0).datatype should be ("map[string,Children]")
vars.get(0).name should be ("children") vars.get(0).name should be ("children")
vars.get(0).baseType should be ("NSDictionary") vars.get(0).baseType should be ("map")
vars.get(0).containerType should be ("map") vars.get(0).containerType should be ("map")
vars.get(0).required should equal (false) vars.get(0).required should equal (false)
vars.get(0).isContainer should equal (true) vars.get(0).isContainer should equal (true)
@ -215,9 +217,8 @@ class PhpModelTest extends FlatSpec with Matchers {
cm.classname should be ("Sample") cm.classname should be ("Sample")
cm.description should be ("an array model") cm.description should be ("an array model")
cm.vars.size should be (0) cm.vars.size should be (0)
cm.parent should be ("NSMutableArray") cm.imports.size should be (1)
cm.imports.size should be (3) (cm.imports.asScala.toSet & Set("Children")).size should be (1)
(cm.imports.asScala.toSet & Set("SWGChildren", "NSArray", "NSMutableArray")).size should be (3)
} }
it should "convert an map model" in { it should "convert an map model" in {
@ -232,13 +233,13 @@ class PhpModelTest extends FlatSpec with Matchers {
cm.classname should be ("Sample") cm.classname should be ("Sample")
cm.description should be ("an map model") cm.description should be ("an map model")
cm.vars.size should be (0) cm.vars.size should be (0)
cm.parent should be ("NSMutableDictionary") cm.imports.size should be (2)
cm.imports.size should be (3) (cm.imports.asScala.toSet & Set("Children")).size should be (1)
(cm.imports.asScala.toSet & Set("SWGChildren", "NSDictionary", "NSMutableDictionary")).size should be (3)
} }
it should "create proper imports per #316" in { it should "create proper imports per #316" in {
val model = new SwaggerLoader().read("src/test/resources/postBodyTest.json") val model = new SwaggerParser()
.read("src/test/resources/postBodyTest.json")
val codegen = new PhpClientCodegen() val codegen = new PhpClientCodegen()
val animalPaths = model.getPaths() val animalPaths = model.getPaths()
@ -246,14 +247,13 @@ class PhpModelTest extends FlatSpec with Matchers {
animalOps.getPost() should not be (null) animalOps.getPost() should not be (null)
val animalCo = codegen.fromOperation("/animals", "POST", animalOps.getPost()) val animalCo = codegen.fromOperation("/animals", "POST", animalOps.getPost())
animalCo.imports.size should be (1) animalCo.imports.size should be (1)
animalCo.imports.contains("SWGAnimal") should equal (true) animalCo.imports.contains("Animal") should equal (true)
val insectPaths = model.getPaths() val insectPaths = model.getPaths()
val insectOps = insectPaths.get("/insects") val insectOps = insectPaths.get("/insects")
insectOps.getPost() should not be (null) insectOps.getPost() should not be (null)
val insectCo = codegen.fromOperation("/insects", "POST", insectOps.getPost()) val insectCo = codegen.fromOperation("/insects", "POST", insectOps.getPost())
insectCo.imports.size should be (1) insectCo.imports.size should be (1)
insectCo.imports.contains("SWGInsect") should equal (true) insectCo.imports.contains("Insect") should equal (true)
} }
*/
} }