Skip to content

Commit ad3d37a

Browse files
committed
feature #24321 added ability to handle parent classes for PropertyNormalizer (ivoba)
This PR was squashed before being merged into the 3.4 branch (closes #24321). Discussion ---------- added ability to handle parent classes for PropertyNormalizer | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | yes <!-- don't forget updating src/**/CHANGELOG.md files --> | BC breaks? | no | Deprecations? | no <!-- don't forget updating UPGRADE-*.md files --> | Tests pass? | yes | Fixed tickets | #24152 <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#... <!--highly recommended for new features--> <!-- - Bug fixes must be submitted against the lowest branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the 3.4, legacy code removals go to the master branch. - Please fill in this template according to the PR you're about to submit. - Replace this comment by a description of what your PR is solving. --> This adds the ability for PropertyNormalizer to normalize/denormalize properties from parent classes. Commits ------- 5ecafc5e25 added ability to handle parent classes for PropertyNormalizer
2 parents a87df35 + 0fff807 commit ad3d37a

File tree

3 files changed

+99
-10
lines changed

3 files changed

+99
-10
lines changed

Normalizer/PropertyNormalizer.php

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ protected function isAllowedAttribute($classOrObject, $attribute, $format = null
7979
}
8080

8181
try {
82-
$reflectionProperty = new \ReflectionProperty(is_string($classOrObject) ? $classOrObject : get_class($classOrObject), $attribute);
82+
$reflectionProperty = $this->getReflectionProperty($classOrObject, $attribute);
8383
if ($reflectionProperty->isStatic()) {
8484
return false;
8585
}
@@ -98,13 +98,15 @@ protected function extractAttributes($object, $format = null, array $context = a
9898
$reflectionObject = new \ReflectionObject($object);
9999
$attributes = array();
100100

101-
foreach ($reflectionObject->getProperties() as $property) {
102-
if (!$this->isAllowedAttribute($object, $property->name)) {
103-
continue;
104-
}
101+
do {
102+
foreach ($reflectionObject->getProperties() as $property) {
103+
if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name)) {
104+
continue;
105+
}
105106

106-
$attributes[] = $property->name;
107-
}
107+
$attributes[] = $property->name;
108+
}
109+
} while ($reflectionObject = $reflectionObject->getParentClass());
108110

109111
return $attributes;
110112
}
@@ -115,7 +117,7 @@ protected function extractAttributes($object, $format = null, array $context = a
115117
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
116118
{
117119
try {
118-
$reflectionProperty = new \ReflectionProperty(get_class($object), $attribute);
120+
$reflectionProperty = $this->getReflectionProperty($object, $attribute);
119121
} catch (\ReflectionException $reflectionException) {
120122
return;
121123
}
@@ -134,7 +136,7 @@ protected function getAttributeValue($object, $attribute, $format = null, array
134136
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
135137
{
136138
try {
137-
$reflectionProperty = new \ReflectionProperty(get_class($object), $attribute);
139+
$reflectionProperty = $this->getReflectionProperty($object, $attribute);
138140
} catch (\ReflectionException $reflectionException) {
139141
return;
140142
}
@@ -150,4 +152,26 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
150152

151153
$reflectionProperty->setValue($object, $value);
152154
}
155+
156+
/**
157+
* @param string|object $classOrObject
158+
* @param string $attribute
159+
*
160+
* @return \ReflectionProperty
161+
*
162+
* @throws \ReflectionException
163+
*/
164+
private function getReflectionProperty($classOrObject, $attribute)
165+
{
166+
$reflectionClass = new \ReflectionClass($classOrObject);
167+
while (true) {
168+
try {
169+
return $reflectionClass->getProperty($attribute);
170+
} catch (\ReflectionException $e) {
171+
if (!$reflectionClass = $reflectionClass->getParentClass()) {
172+
throw $e;
173+
}
174+
}
175+
}
176+
}
153177
}

Tests/Fixtures/GroupDummyChild.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Tests\Fixtures;
13+
14+
class GroupDummyChild extends GroupDummy
15+
{
16+
private $baz;
17+
18+
/**
19+
* @return mixed
20+
*/
21+
public function getBaz()
22+
{
23+
return $this->baz;
24+
}
25+
26+
/**
27+
* @param mixed $baz
28+
*/
29+
public function setBaz($baz)
30+
{
31+
$this->baz = $baz;
32+
}
33+
}

Tests/Normalizer/PropertyNormalizerTest.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\Serializer\Serializer;
2121
use Symfony\Component\Serializer\SerializerInterface;
2222
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
23+
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyChild;
2324
use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy;
2425
use Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy;
2526
use Symfony\Component\Serializer\Tests\Fixtures\PropertySiblingHolder;
@@ -65,6 +66,35 @@ public function testDenormalize()
6566
$this->assertEquals('bar', $obj->getBar());
6667
}
6768

69+
public function testNormalizeWithParentClass()
70+
{
71+
$group = new GroupDummyChild();
72+
$group->setBaz('baz');
73+
$group->setFoo('foo');
74+
$group->setBar('bar');
75+
$group->setKevin('Kevin');
76+
$group->setCoopTilleuls('coop');
77+
$this->assertEquals(
78+
array('foo' => 'foo', 'bar' => 'bar', 'kevin' => 'Kevin',
79+
'coopTilleuls' => 'coop', 'fooBar' => null, 'symfony' => null, 'baz' => 'baz', ),
80+
$this->normalizer->normalize($group, 'any')
81+
);
82+
}
83+
84+
public function testDenormalizeWithParentClass()
85+
{
86+
$obj = $this->normalizer->denormalize(
87+
array('foo' => 'foo', 'bar' => 'bar', 'kevin' => 'Kevin', 'baz' => 'baz'),
88+
GroupDummyChild::class,
89+
'any'
90+
);
91+
$this->assertEquals('foo', $obj->getFoo());
92+
$this->assertEquals('bar', $obj->getBar());
93+
$this->assertEquals('Kevin', $obj->getKevin());
94+
$this->assertEquals('baz', $obj->getBaz());
95+
$this->assertNull($obj->getSymfony());
96+
}
97+
6898
public function testConstructorDenormalize()
6999
{
70100
$obj = $this->normalizer->denormalize(
@@ -147,12 +177,14 @@ public function testGroupsNormalize()
147177
'bar' => 'bar',
148178
), $this->normalizer->normalize($obj, null, array(PropertyNormalizer::GROUPS => array('c'))));
149179

150-
// The PropertyNormalizer is not able to hydrate properties from parent classes
180+
// The PropertyNormalizer is also able to hydrate properties from parent classes
151181
$this->assertEquals(array(
152182
'symfony' => 'symfony',
153183
'foo' => 'foo',
154184
'fooBar' => 'fooBar',
155185
'bar' => 'bar',
186+
'kevin' => 'kevin',
187+
'coopTilleuls' => 'coopTilleuls',
156188
), $this->normalizer->normalize($obj, null, array(PropertyNormalizer::GROUPS => array('a', 'c'))));
157189
}
158190

0 commit comments

Comments
 (0)