[PHP] error when deserializing enums #4032 (#4886)

* fixed enum template; added enum handling to ObjectSerializer

* regenerated templates

* improved InvalidArgumentException message

* regenerated sample client

* added value check of OuterEnum during sanitization

* regenerated samples
This commit is contained in:
baartosz
2017-03-08 11:08:42 +00:00
committed by wing328
parent 2bb7626202
commit d21e156071
7 changed files with 164 additions and 20 deletions

View File

@@ -49,10 +49,16 @@ class ObjectSerializer
return $data;
} elseif (is_object($data)) {
$values = [];
foreach (array_keys($data::swaggerTypes()) as $property) {
foreach ($data::swaggerTypes() as $property => $swaggerType) {
$getter = $data::getters()[$property];
if ($data->$getter() !== null) {
$values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($data->$getter());
$value = $data->$getter();
if (method_exists($swaggerType, 'getAllowableEnumValues')
&& !in_array($value, $swaggerType::getAllowableEnumValues())) {
$imploded = implode("', '", $swaggerType::getAllowableEnumValues());
throw new \InvalidArgumentException("Invalid value for enum '$swaggerType', must be one of: '$imploded'");
}
if ($value !== null) {
$values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($value);
}
}
return (object)$values;
@@ -259,6 +265,12 @@ class ObjectSerializer
}
return $deserialized;
} elseif (method_exists($class, 'getAllowableEnumValues')) {
if (!in_array($data, $class::getAllowableEnumValues())) {
$imploded = implode("', '", $class::getAllowableEnumValues());
throw new \InvalidArgumentException("Invalid value for enum '$class', must be one of: '$imploded'");
}
return $data;
} else {
// If a discriminator is defined and points to a valid subclass, use it.
$discriminator = $class::DISCRIMINATOR;

View File

@@ -20,8 +20,10 @@
*/
namespace {{modelPackage}};
{{^isEnum}}
use \ArrayAccess;
{{/isEnum}}
/**
* {{classname}} Class Doc Comment

View File

@@ -1,18 +1,18 @@
class {{classname}} {
/**
* Possible values of this enum
*/
{{#allowableValues}}{{#enumVars}}const {{{name}}} = {{{value}}};
{{/enumVars}}{{/allowableValues}}
{{#vars}}{{#isEnum}}
/**
* Gets allowable values of the enum
* @return string[]
*/
public function {{getter}}AllowableValues()
public static function getAllowableEnumValues()
{
return [
{{#allowableValues}}{{#enumVars}}self::{{datatypeWithEnum}}_{{{name}}},{{^-last}}
{{#allowableValues}}{{#enumVars}}self::{{{name}}},{{^-last}}
{{/-last}}{{/enumVars}}{{/allowableValues}}
];
}
{{/isEnum}}{{/vars}}
}

View File

@@ -29,8 +29,6 @@
namespace Swagger\Client\Model;
use \ArrayAccess;
/**
* EnumClass Class Doc Comment
*
@@ -40,11 +38,25 @@ use \ArrayAccess;
* @link https://github.com/swagger-api/swagger-codegen
*/
class EnumClass {
/**
* Possible values of this enum
*/
const ABC = '_abc';
const EFG = '-efg';
const XYZ = '(xyz)';
/**
* Gets allowable values of the enum
* @return string[]
*/
public static function getAllowableEnumValues()
{
return [
self::ABC,
self::EFG,
self::XYZ,
];
}
}

View File

@@ -29,8 +29,6 @@
namespace Swagger\Client\Model;
use \ArrayAccess;
/**
* OuterEnum Class Doc Comment
*
@@ -40,11 +38,25 @@ use \ArrayAccess;
* @link https://github.com/swagger-api/swagger-codegen
*/
class OuterEnum {
/**
* Possible values of this enum
*/
const PLACED = 'placed';
const APPROVED = 'approved';
const DELIVERED = 'delivered';
/**
* Gets allowable values of the enum
* @return string[]
*/
public static function getAllowableEnumValues()
{
return [
self::PLACED,
self::APPROVED,
self::DELIVERED,
];
}
}

View File

@@ -59,10 +59,16 @@ class ObjectSerializer
return $data;
} elseif (is_object($data)) {
$values = [];
foreach (array_keys($data::swaggerTypes()) as $property) {
foreach ($data::swaggerTypes() as $property => $swaggerType) {
$getter = $data::getters()[$property];
if ($data->$getter() !== null) {
$values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($data->$getter());
$value = $data->$getter();
if (method_exists($swaggerType, 'getAllowableEnumValues')
&& !in_array($value, $swaggerType::getAllowableEnumValues())) {
$imploded = implode("', '", $swaggerType::getAllowableEnumValues());
throw new \InvalidArgumentException("Invalid value for enum '$swaggerType', must be one of: '$imploded'");
}
if ($value !== null) {
$values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($value);
}
}
return (object)$values;
@@ -269,6 +275,12 @@ class ObjectSerializer
}
return $deserialized;
} elseif (method_exists($class, 'getAllowableEnumValues')) {
if (!in_array($data, $class::getAllowableEnumValues())) {
$imploded = implode("', '", $class::getAllowableEnumValues());
throw new \InvalidArgumentException("Invalid value for enum '$class', must be one of: '$imploded'");
}
return $data;
} else {
// If a discriminator is defined and points to a valid subclass, use it.
$discriminator = $class::DISCRIMINATOR;

View File

@@ -0,0 +1,94 @@
<?php
namespace Swagger\Client;
use Swagger\Client\Model\EnumTest;
use Swagger\Client\Model\OuterEnum;
class OuterEnumTest extends \PHPUnit_Framework_TestCase
{
public function testDeserialize()
{
$result = ObjectSerializer::deserialize(
"placed",
OuterEnum::class
);
$this->assertInternalType('string', $result);
$this->assertEquals('placed', $result);
}
public function testDeserializeInvalidValue()
{
$this->setExpectedException(\InvalidArgumentException::class, 'Invalid value for enum');
ObjectSerializer::deserialize(
"lkjfalgkdfjg",
OuterEnum::class
);
}
public function testDeserializeNested()
{
$json = '{
"enum_string": "UPPER",
"enum_integer": -1,
"enum_number": -1.2,
"outerEnum": "approved"
}';
/** * @var EnumTest $result */
$result = ObjectSerializer::deserialize(
json_decode($json),
EnumTest::class
);
$this->assertInstanceOf(EnumTest::class, $result);
$this->assertEquals('approved', $result->getOuterEnum());
}
public function testSanitize()
{
$json = "placed";
$result = ObjectSerializer::sanitizeForSerialization(
$json
);
$this->assertInternalType('string', $result);
}
public function testSanitizeNested()
{
$input = new EnumTest([
'enum_string' => 'UPPER',
'enum_integer' => -1,
'enum_number' => -1.2,
'outer_enum' => 'approved'
]);
$result = ObjectSerializer::sanitizeForSerialization(
$input
);
$this->assertInternalType('object', $result);
$this->assertInstanceOf(\stdClass::class, $result);
$this->assertInternalType('string', $result->outerEnum);
$this->assertEquals('approved', $result->outerEnum);
}
public function testSanitizeNestedInvalidValue()
{
$this->setExpectedException(\InvalidArgumentException::class, 'Invalid value for enum');
$input = new EnumTest([
'enum_string' => 'UPPER',
'enum_integer' => -1,
'enum_number' => -1.2,
'outer_enum' => 'invalid_value'
]);
ObjectSerializer::sanitizeForSerialization($input);
}
}