From 5ecafc5e25aa073f6cf109a6b87453689369c4a4 Mon Sep 17 00:00:00 2001 From: Ivo Bathke Date: Mon, 25 Sep 2017 18:15:09 +0200 Subject: [PATCH] added ability to handle parent classes for PropertyNormalizer --- .../Normalizer/PropertyNormalizer.php | 42 +++++++++++++++---- .../Tests/Fixtures/GroupDummyChild.php | 33 +++++++++++++++ .../Normalizer/PropertyNormalizerTest.php | 34 ++++++++++++++- 3 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/GroupDummyChild.php diff --git a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php index 2d96608ff240..2921e5baf953 100644 --- a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php @@ -79,7 +79,7 @@ protected function isAllowedAttribute($classOrObject, $attribute, $format = null } try { - $reflectionProperty = new \ReflectionProperty(is_string($classOrObject) ? $classOrObject : get_class($classOrObject), $attribute); + $reflectionProperty = $this->getReflectionProperty($classOrObject, $attribute); if ($reflectionProperty->isStatic()) { return false; } @@ -98,13 +98,15 @@ protected function extractAttributes($object, $format = null, array $context = a $reflectionObject = new \ReflectionObject($object); $attributes = array(); - foreach ($reflectionObject->getProperties() as $property) { - if (!$this->isAllowedAttribute($object, $property->name)) { - continue; - } + do { + foreach ($reflectionObject->getProperties() as $property) { + if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name)) { + continue; + } - $attributes[] = $property->name; - } + $attributes[] = $property->name; + } + } while ($reflectionObject = $reflectionObject->getParentClass()); return $attributes; } @@ -115,7 +117,7 @@ protected function extractAttributes($object, $format = null, array $context = a protected function getAttributeValue($object, $attribute, $format = null, array $context = array()) { try { - $reflectionProperty = new \ReflectionProperty(get_class($object), $attribute); + $reflectionProperty = $this->getReflectionProperty($object, $attribute); } catch (\ReflectionException $reflectionException) { return; } @@ -134,7 +136,7 @@ protected function getAttributeValue($object, $attribute, $format = null, array protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array()) { try { - $reflectionProperty = new \ReflectionProperty(get_class($object), $attribute); + $reflectionProperty = $this->getReflectionProperty($object, $attribute); } catch (\ReflectionException $reflectionException) { return; } @@ -150,4 +152,26 @@ protected function setAttributeValue($object, $attribute, $value, $format = null $reflectionProperty->setValue($object, $value); } + + /** + * @param string|object $classOrObject + * @param string $attribute + * + * @return \ReflectionProperty + * + * @throws \ReflectionException + */ + private function getReflectionProperty($classOrObject, $attribute) + { + $reflectionClass = new \ReflectionClass($classOrObject); + while (true) { + try { + return $reflectionClass->getProperty($attribute); + } catch (\ReflectionException $e) { + if (!$reflectionClass = $reflectionClass->getParentClass()) { + throw $e; + } + } + } + } } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/GroupDummyChild.php b/src/Symfony/Component/Serializer/Tests/Fixtures/GroupDummyChild.php new file mode 100644 index 000000000000..fa72160ec657 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/GroupDummyChild.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +class GroupDummyChild extends GroupDummy +{ + private $baz; + + /** + * @return mixed + */ + public function getBaz() + { + return $this->baz; + } + + /** + * @param mixed $baz + */ + public function setBaz($baz) + { + $this->baz = $baz; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php index 73b5f689c1d9..954de0b03e32 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php @@ -20,6 +20,7 @@ use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy; +use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyChild; use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy; use Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy; use Symfony\Component\Serializer\Tests\Fixtures\PropertySiblingHolder; @@ -65,6 +66,35 @@ public function testDenormalize() $this->assertEquals('bar', $obj->getBar()); } + public function testNormalizeWithParentClass() + { + $group = new GroupDummyChild(); + $group->setBaz('baz'); + $group->setFoo('foo'); + $group->setBar('bar'); + $group->setKevin('Kevin'); + $group->setCoopTilleuls('coop'); + $this->assertEquals( + array('foo' => 'foo', 'bar' => 'bar', 'kevin' => 'Kevin', + 'coopTilleuls' => 'coop', 'fooBar' => null, 'symfony' => null, 'baz' => 'baz', ), + $this->normalizer->normalize($group, 'any') + ); + } + + public function testDenormalizeWithParentClass() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => 'bar', 'kevin' => 'Kevin', 'baz' => 'baz'), + GroupDummyChild::class, + 'any' + ); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + $this->assertEquals('Kevin', $obj->getKevin()); + $this->assertEquals('baz', $obj->getBaz()); + $this->assertNull($obj->getSymfony()); + } + public function testConstructorDenormalize() { $obj = $this->normalizer->denormalize( @@ -147,12 +177,14 @@ public function testGroupsNormalize() 'bar' => 'bar', ), $this->normalizer->normalize($obj, null, array(PropertyNormalizer::GROUPS => array('c')))); - // The PropertyNormalizer is not able to hydrate properties from parent classes + // The PropertyNormalizer is also able to hydrate properties from parent classes $this->assertEquals(array( 'symfony' => 'symfony', 'foo' => 'foo', 'fooBar' => 'fooBar', 'bar' => 'bar', + 'kevin' => 'kevin', + 'coopTilleuls' => 'coopTilleuls', ), $this->normalizer->normalize($obj, null, array(PropertyNormalizer::GROUPS => array('a', 'c')))); }