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
This commit is contained in:
Fabien Potencier 2017-10-11 08:25:57 -07:00
commit 0f5e38c732
3 changed files with 99 additions and 10 deletions

View File

@ -79,7 +79,7 @@ class PropertyNormalizer extends AbstractObjectNormalizer
}
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 @@ class PropertyNormalizer extends AbstractObjectNormalizer
$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 @@ class PropertyNormalizer extends AbstractObjectNormalizer
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 @@ class PropertyNormalizer extends AbstractObjectNormalizer
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 @@ class PropertyNormalizer extends AbstractObjectNormalizer
$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;
}
}
}
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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;
}
}

View File

@ -20,6 +20,7 @@ use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
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 @@ class PropertyNormalizerTest extends TestCase
$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 @@ class PropertyNormalizerTest extends TestCase
'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'))));
}