From 1d8b5af3f03c5bf1bcfa3c3d4ee0e670b381bc30 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Tue, 26 Mar 2019 15:05:43 +0100 Subject: [PATCH] [Serializer] Use object class resolver when extracting attributes --- .../Normalizer/ObjectNormalizer.php | 7 +++- .../Tests/Normalizer/ObjectNormalizerTest.php | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index 94ed6d8b6394..88732bbd3e14 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -32,6 +32,8 @@ class ObjectNormalizer extends AbstractObjectNormalizer private $discriminatorCache = []; + private $objectClassResolver; + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyAccessorInterface $propertyAccessor = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = []) { if (!\class_exists(PropertyAccess::class)) { @@ -41,6 +43,7 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory parent::__construct($classMetadataFactory, $nameConverter, $propertyTypeExtractor, $classDiscriminatorResolver, $objectClassResolver, $defaultContext); $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); + $this->objectClassResolver = $objectClassResolver; } /** @@ -60,7 +63,9 @@ protected function extractAttributes($object, $format = null, array $context = [ $attributes = []; // methods - $reflClass = new \ReflectionClass($object); + $class = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); + $reflClass = new \ReflectionClass($class); + foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) { if ( 0 !== $reflMethod->getNumberOfRequiredParameters() || diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index b2bc76a86a90..b4e080528165 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -1003,6 +1003,34 @@ public function denormalize($propertyName, string $class = null, string $format $normalizer = new ObjectNormalizer(null, $nameConverter); $this->assertArrayHasKey('foo-Symfony\Component\Serializer\Tests\Normalizer\ObjectDummy-json-bar', $normalizer->normalize(new ObjectDummy(), 'json', ['foo' => 'bar'])); } + + public function testObjectClassResolver() + { + $classResolver = function ($object) { + return ObjectDummy::class; + }; + + $normalizer = new ObjectNormalizer(null, null, null, null, null, $classResolver); + + $obj = new ProxyObjectDummy(); + $obj->setFoo('foo'); + $obj->bar = 'bar'; + $obj->setBaz(true); + $obj->setCamelCase('camelcase'); + $obj->unwantedProperty = 'notwanted'; + + $this->assertEquals( + [ + 'foo' => 'foo', + 'bar' => 'bar', + 'baz' => true, + 'fooBar' => 'foobar', + 'camelCase' => 'camelcase', + 'object' => null, + ], + $normalizer->normalize($obj, 'any') + ); + } } class ObjectDummy @@ -1064,6 +1092,11 @@ public function getObject() } } +class ProxyObjectDummy extends ObjectDummy +{ + public $unwantedProperty; +} + class ObjectConstructorDummy { protected $foo;