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.
This commit is contained in:
Christian Flothmann 2014-07-20 16:43:00 +02:00
parent 9572918064
commit 123fc62652
2 changed files with 48 additions and 4 deletions

View File

@ -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)) {

View File

@ -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
*/