[Serializer] Add the possibility to filter attributes

This commit is contained in:
Kévin Dunglas 2016-05-22 09:54:16 +02:00
parent 7c5dcfcdb8
commit b3826fb0e7
No known key found for this signature in database
GPG Key ID: 4D04EBEF06AAF3A6
3 changed files with 123 additions and 5 deletions

View File

@ -236,7 +236,20 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
*/
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array())
{
return !in_array($attribute, $this->ignoredAttributes);
if (in_array($attribute, $this->ignoredAttributes)) {
return false;
}
if (isset($context['attributes'][$attribute])) {
// Nested attributes
return true;
}
if (isset($context['attributes']) && is_array($context['attributes'])) {
return in_array($attribute, $context['attributes'], true);
}
return true;
}
/**
@ -324,7 +337,7 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
$key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName;
$allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes);
$ignored = in_array($paramName, $this->ignoredAttributes);
$ignored = !$this->isAllowedAttribute($class, $paramName, $format, $context);
if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) {
if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) {
if (!is_array($data[$paramName])) {
@ -341,7 +354,7 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $constructorParameter->getClass(), static::class));
}
$parameterClass = $constructorParameter->getClass()->getName();
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $context);
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $paramName));
}
} catch (\ReflectionException $e) {
throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e);
@ -372,4 +385,21 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
return new $class();
}
/**
* @param array $parentContext
* @param string $attribute
*
* @return array
*
* @internal
*/
protected function createChildContext(array $parentContext, $attribute)
{
if (isset($parentContext['attributes'][$attribute])) {
$parentContext['attributes'] = $parentContext['attributes'][$attribute];
}
return $parentContext;
}
}

View File

@ -95,7 +95,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
throw new LogicException(sprintf('Cannot normalize attribute "%s" because the injected serializer is not a normalizer', $attribute));
}
$data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $context));
$data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute)));
}
return $data;
@ -268,7 +268,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
}
if ($this->serializer->supportsDenormalization($data, $class, $format)) {
return $this->serializer->denormalize($data, $class, $format, $context);
return $this->serializer->denormalize($data, $class, $format, $this->createChildContext($context, $attribute));
}
}

View File

@ -643,6 +643,70 @@ class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array('foo' => 'bar', 'bar' => 'foo'), $normalizer->normalize($data, null, array('include_foo_and_bar' => true)));
}
public function testAttributesContextNormalize()
{
$normalizer = new ObjectNormalizer();
$serializer = new Serializer(array($normalizer));
$objectInner = new ObjectInner();
$objectInner->foo = 'innerFoo';
$objectInner->bar = 'innerBar';
$objectDummy = new ObjectDummy();
$objectDummy->setFoo('foo');
$objectDummy->setBaz(true);
$objectDummy->setObject($objectInner);
$context = array('attributes' => array('foo', 'baz', 'object' => array('foo')));
$this->assertEquals(
array(
'foo' => 'foo',
'baz' => true,
'object' => array('foo' => 'innerFoo'),
),
$serializer->normalize($objectDummy, null, $context)
);
}
public function testAttributesContextDenormalize()
{
$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());
$serializer = new Serializer(array($normalizer));
$objectInner = new ObjectInner();
$objectInner->foo = 'innerFoo';
$objectOuter = new ObjectOuter();
$objectOuter->bar = 'bar';
$objectOuter->setInner($objectInner);
$context = array('attributes' => array('bar', 'inner' => array('foo')));
$this->assertEquals($objectOuter, $serializer->denormalize(
array(
'foo' => 'foo',
'bar' => 'bar',
'date' => '2017-02-03',
'inner' => array('foo' => 'innerFoo', 'bar' => 'innerBar'),
), ObjectOuter::class, null, $context));
}
public function testAttributesContextDenormalizeConstructor()
{
$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());
$serializer = new Serializer(array($normalizer));
$objectInner = new ObjectInner();
$objectInner->bar = 'bar';
$obj = new DummyWithConstructorObjectAndDefaultValue('a', $objectInner);
$context = array('attributes' => array('inner' => array('bar')));
$this->assertEquals($obj, $serializer->denormalize(array(
'foo' => 'b',
'inner' => array('foo' => 'foo', 'bar' => 'bar'),
), DummyWithConstructorObjectAndDefaultValue::class, null, $context));
}
}
class ObjectDummy
@ -813,6 +877,8 @@ class ObjectTypeHinted
class ObjectOuter
{
public $foo;
public $bar;
private $inner;
private $date;
@ -910,3 +976,25 @@ class JsonNumber
*/
public $number;
}
class DummyWithConstructorObjectAndDefaultValue
{
private $foo;
private $inner;
public function __construct($foo = 'a', ObjectInner $inner)
{
$this->foo = $foo;
$this->inner = $inner;
}
public function getFoo()
{
return $this->foo;
}
public function getInner()
{
return $this->inner;
}
}