Skip to content

Commit

Permalink
[PHP] error when deserializing enums #4032 (#4886)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
baartosz authored and wing328 committed Mar 8, 2017
1 parent 2bb7626 commit d21e156
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions modules/swagger-codegen/src/main/resources/php/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
*/

namespace {{modelPackage}};
{{^isEnum}}

use \ArrayAccess;
{{/isEnum}}

/**
* {{classname}} Class Doc Comment
Expand Down
Original file line number Diff line number Diff line change
@@ -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}}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@

namespace Swagger\Client\Model;

use \ArrayAccess;

/**
* EnumClass Class Doc Comment
*
Expand All @@ -40,11 +38,25 @@
* @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,
];
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@

namespace Swagger\Client\Model;

use \ArrayAccess;

/**
* OuterEnum Class Doc Comment
*
Expand All @@ -40,11 +38,25 @@
* @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,
];
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,16 @@ public static function sanitizeForSerialization($data)
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;
Expand Down Expand Up @@ -269,6 +275,12 @@ public static function deserialize($data, $class, $httpHeaders = null)
}

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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}

0 comments on commit d21e156

Please sign in to comment.