From 123fc62652ec712fcf15216e5fca78fbf398d787 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 20 Jul 2014 16:43:00 +0200 Subject: [PATCH] properly handle null data when denormalizing If null is passed to denormalize(), no property values can be set on the denormalized object. Additionally, this fixes passing values to the denormalized object's constructor if the incoming data is an object. --- .../Normalizer/GetSetMethodNormalizer.php | 20 +++++++++--- .../Normalizer/GetSetMethodNormalizerTest.php | 32 +++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php index e4e3d82291..122ab0e5dc 100644 --- a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php @@ -114,6 +114,18 @@ class GetSetMethodNormalizer extends SerializerAwareNormalizer implements Normal */ public function denormalize($data, $class, $format = null, array $context = array()) { + if (is_array($data) || is_object($data) && $data instanceof \ArrayAccess) { + $normalizedData = $data; + } elseif (is_object($data)) { + $normalizedData = array(); + + foreach ($data as $attribute => $value) { + $normalizedData[$attribute] = $value; + } + } else { + $normalizedData = array(); + } + $reflectionClass = new \ReflectionClass($class); $constructor = $reflectionClass->getConstructor(); @@ -124,10 +136,10 @@ class GetSetMethodNormalizer extends SerializerAwareNormalizer implements Normal foreach ($constructorParameters as $constructorParameter) { $paramName = lcfirst($this->formatAttribute($constructorParameter->name)); - if (isset($data[$paramName])) { - $params[] = $data[$paramName]; + if (isset($normalizedData[$paramName])) { + $params[] = $normalizedData[$paramName]; // don't run set for a parameter passed to the constructor - unset($data[$paramName]); + unset($normalizedData[$paramName]); } elseif ($constructorParameter->isOptional()) { $params[] = $constructorParameter->getDefaultValue(); } else { @@ -144,7 +156,7 @@ class GetSetMethodNormalizer extends SerializerAwareNormalizer implements Normal $object = new $class; } - foreach ($data as $attribute => $value) { + foreach ($normalizedData as $attribute => $value) { $setter = 'set'.$this->formatAttribute($attribute); if (method_exists($object, $setter)) { diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php index e4f1b5c656..1cbceece04 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -15,6 +15,11 @@ use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase { + /** + * @var GetSetMethodNormalizer + */ + private $normalizer; + protected function setUp() { $this->normalizer = new GetSetMethodNormalizer(); @@ -44,6 +49,17 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('bar', $obj->getBar()); } + public function testDenormalizeWithObject() + { + $data = new \stdClass(); + $data->foo = 'foo'; + $data->bar = 'bar'; + $data->fooBar = 'foobar'; + $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetSetDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + } + public function testDenormalizeOnCamelCaseFormat() { $this->normalizer->setCamelizedAttributes(array('camel_case')); @@ -54,6 +70,11 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('camelCase', $obj->getCamelCase()); } + public function testDenormalizeNull() + { + $this->assertEquals(new GetSetDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\GetSetDummy')); + } + /** * @dataProvider attributeProvider */ @@ -96,6 +117,17 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array(1, 2, 3), $obj->getBaz()); } + public function testConstructorWithObjectDenormalize() + { + $data = new \stdClass(); + $data->foo = 'foo'; + $data->bar = 'bar'; + $data->fooBar = 'foobar'; + $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetConstructorDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + } + /** * @dataProvider provideCallbacks */