From 4c12f7d43a28762e091fcba770921a3124f93ecf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Nov 2021 11:50:29 +0100 Subject: [PATCH] [Serializer] fix support for lazy properties --- Normalizer/ObjectNormalizer.php | 4 ++-- Normalizer/PropertyNormalizer.php | 10 ++++++---- Tests/Normalizer/ObjectNormalizerTest.php | 20 ++++++++++++++++++++ Tests/Normalizer/PropertyNormalizerTest.php | 20 ++++++++++++++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/Normalizer/ObjectNormalizer.php b/Normalizer/ObjectNormalizer.php index 1a3ed992e..874b4788d 100644 --- a/Normalizer/ObjectNormalizer.php +++ b/Normalizer/ObjectNormalizer.php @@ -104,9 +104,9 @@ protected function extractAttributes($object, $format = null, array $context = [ } // properties - $propertyValues = (array) $object; + $propertyValues = !method_exists($object, '__get') ? (array) $object : null; foreach ($reflClass->getProperties() as $reflProperty) { - if (!\array_key_exists($reflProperty->name, $propertyValues)) { + if (null !== $propertyValues && !\array_key_exists($reflProperty->name, $propertyValues)) { if ($reflProperty->isPublic() || ($reflProperty->isProtected() && !\array_key_exists("\0*\0{$reflProperty->name}", $propertyValues)) || ($reflProperty->isPrivate() && !\array_key_exists("\0{$reflProperty->class}\0{$reflProperty->name}", $propertyValues)) diff --git a/Normalizer/PropertyNormalizer.php b/Normalizer/PropertyNormalizer.php index 83ec5325b..9989c60e4 100644 --- a/Normalizer/PropertyNormalizer.php +++ b/Normalizer/PropertyNormalizer.php @@ -101,13 +101,15 @@ protected function extractAttributes($object, $format = null, array $context = [ { $reflectionObject = new \ReflectionObject($object); $attributes = []; - $propertyValues = (array) $object; + $propertyValues = !method_exists($object, '__get') ? (array) $object : null; do { foreach ($reflectionObject->getProperties() as $property) { - if (($property->isPublic() && !\array_key_exists($property->name, $propertyValues)) - || ($property->isProtected() && !\array_key_exists("\0*\0{$property->name}", $propertyValues)) - || ($property->isPrivate() && !\array_key_exists("\0{$property->class}\0{$property->name}", $propertyValues)) + if ((null !== $propertyValues && ( + ($property->isPublic() && !\array_key_exists($property->name, $propertyValues)) + || ($property->isProtected() && !\array_key_exists("\0*\0{$property->name}", $propertyValues)) + || ($property->isPrivate() && !\array_key_exists("\0{$property->class}\0{$property->name}", $propertyValues)) + )) || !$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context) ) { continue; diff --git a/Tests/Normalizer/ObjectNormalizerTest.php b/Tests/Normalizer/ObjectNormalizerTest.php index 94c5db936..50ed2ad0f 100644 --- a/Tests/Normalizer/ObjectNormalizerTest.php +++ b/Tests/Normalizer/ObjectNormalizerTest.php @@ -142,6 +142,16 @@ public function testNormalizeObjectWithUnsetProperties() ); } + public function testNormalizeObjectWithLazyProperties() + { + $obj = new LazyObjectInner(); + unset($obj->foo); + $this->assertEquals( + ['foo' => 123, 'bar' => null], + $this->normalizer->normalize($obj, 'any') + ); + } + /** * @requires PHP 7.4 */ @@ -1093,6 +1103,16 @@ class ObjectInner public $bar; } +class LazyObjectInner extends ObjectInner +{ + public function __get($name) + { + if ('foo' === $name) { + return $this->foo = 123; + } + } +} + class FormatAndContextAwareNormalizer extends ObjectNormalizer { protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = []): bool diff --git a/Tests/Normalizer/PropertyNormalizerTest.php b/Tests/Normalizer/PropertyNormalizerTest.php index 98c1fc601..be8b17124 100644 --- a/Tests/Normalizer/PropertyNormalizerTest.php +++ b/Tests/Normalizer/PropertyNormalizerTest.php @@ -111,6 +111,16 @@ public function testNormalizeObjectWithUnsetProperties() ); } + public function testNormalizeObjectWithLazyProperties() + { + $obj = new LazyPropertyDummy(); + unset($obj->foo); + $this->assertEquals( + ['foo' => 123, 'bar' => null, 'camelCase' => null], + $this->normalizer->normalize($obj, 'any') + ); + } + public function testDenormalize() { $obj = $this->normalizer->denormalize( @@ -508,6 +518,16 @@ public function setCamelCase($camelCase) } } +class LazyPropertyDummy extends PropertyDummy +{ + public function __get($name) + { + if ('foo' === $name) { + return $this->foo = 123; + } + } +} + class PropertyConstructorDummy { protected $foo;