Skip to content

added ability to handle parent classes for PropertyNormalizer #24321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

ivoba
Copy link
Contributor

@ivoba ivoba commented Sep 25, 2017

Q A
Branch? 3.4
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #24152
License MIT
Doc PR symfony/symfony-docs#...

This adds the ability for PropertyNormalizer to normalize/denormalize properties from parent classes.

@@ -84,6 +84,21 @@ protected function isAllowedAttribute($classOrObject, $attribute, $format = null
return false;
}
} catch (\ReflectionException $reflectionException) {
$className = is_string($classOrObject) ? $classOrObject : get_class($classOrObject);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first check (line 82) can also be in the while right?


while ($parent = $class->getParentClass()) {
try {
$reflectionProperty = new \ReflectionProperty($parent->getName(), $attribute);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static methods must be excluded.


while ($parent = $class->getParentClass()) {
try {
$reflectionProperty = new \ReflectionProperty($parent->getName(), $attribute);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you have an instance of ReflectionClass available, maybe can you just call getProperty?

if ($reflectionProperty) {
return true;
}
} catch (\Exception $e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only ReflectionException should be catched.

return;
$class = get_parent_class($object);
do {
$reflectionProperty = new \ReflectionProperty(get_parent_class($object), $attribute);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exceptions aren't caught here.

@@ -117,7 +134,13 @@ protected function getAttributeValue($object, $attribute, $format = null, array
try {
$reflectionProperty = new \ReflectionProperty(get_class($object), $attribute);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, should be in the do/while

$class = get_parent_class($object);
do {
$reflectionProperty = new \ReflectionProperty(get_parent_class($object), $attribute);
if (null === $reflectionProperty) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can it be null?

@@ -136,7 +159,13 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
try {
$reflectionProperty = new \ReflectionProperty(get_class($object), $attribute);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@kbond
Copy link
Member

kbond commented Sep 27, 2017

@ivoba I suggest adding a private method getReflectionProperty to reduce the duplication, ie:

private function getReflectionProperty($classOrObject, $attribute)
{
    $class = is_string($classOrObject) ? $classOrObject : get_class($classOrObject);

    try {
        return new \ReflectionProperty($class, $attribute);
    } catch (\ReflectionException $e) {
        $class = new \ReflectionClass($class);

        while ($parent = $class->getParentClass()) {
            try {
                return new \ReflectionProperty($parent->getName(), $attribute);
            } catch (\ReflectionException $e) {
                $class = $parent;
            }
        }

        throw $e;
    }
}

@ivoba
Copy link
Contributor Author

ivoba commented Sep 28, 2017

i updated the PR and took @kbond suggestion into account.
@dunglas pls review if the changes fit your comments.

i have no idea why the test in PHP7.1 fail, looks not really related??

*
* @throws \ReflectionException
*/
private function getReflectionProperty($classOrObject, $attribute)
Copy link
Member

@dunglas dunglas Sep 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about:

    private function getReflectionProperty($classOrObject, $attribute)
    {
        $class = is_string($classOrObject) ? $classOrObject : get_class($classOrObject);
        while (true) {
            try {
                return isset($reflectionClass) ? $reflectionClass->getProperty($attribute) : new \ReflectionProperty($class, $attribute);
            } catch (\ReflectionException $e) {
                $reflectionClass = new \ReflectionClass($class);
                if (!$reflectionClass = $reflectionClass->getParentClass()) {
                    throw $e;
                }
            }
        }
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This runs into an endless loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would work with this:

... 
$reflectionClass = new \ReflectionClass($class);
$reflectionClass = $reflectionClass->getParentClass();
if ($reflectionClass === false) {
    throw $e;
}
...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated my snippet, it should work now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i updated the PR with the snippet included

@ivoba ivoba force-pushed the ticket_24152 branch 2 times, most recently from 624d7f5 to 880bebe Compare September 28, 2017 16:06
try {
return isset($reflectionClass) ? $reflectionClass->getProperty($attribute) : new \ReflectionProperty($class, $attribute);
} catch (\ReflectionException $e) {
$reflectionClass = new \ReflectionClass($class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to initialize this outside the loop?

try {
return isset($reflectionClass) ? $reflectionClass->getProperty($attribute) : new \ReflectionProperty($class, $attribute);
} catch (\ReflectionException $e) {
$reflectionClass = new \ReflectionClass($class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks wrong to me as you are always overriding $reflectionClass with $class. This statement should only be executed if $reflectionClass is not set. I would add a test with a more complex hierarchy: class < parent < parent. Current code would loop forever.

@ivoba ivoba force-pushed the ticket_24152 branch 2 times, most recently from 8306c91 to 4697028 Compare October 10, 2017 06:45
@ivoba
Copy link
Contributor Author

ivoba commented Oct 10, 2017

I added a new Dummy class with 3 level inheritance and applied suggested fixes.

*/
private function getReflectionProperty($classOrObject, $attribute)
{
$class = is_string($classOrObject) ? $classOrObject : get_class($classOrObject);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed as the ReflectionClass constructor takes either a class or an object as an argument.

@ivoba
Copy link
Contributor Author

ivoba commented Oct 11, 2017

removed mentioned line.
fabbot fails for License Headers but diff is empty. probably a fabbot bug?

@xabbuh
Copy link
Member

xabbuh commented Oct 11, 2017

your GroupDummyChild.php fixtures file is missing the license header

@ivoba
Copy link
Contributor Author

ivoba commented Oct 11, 2017

ok thx, licence header is added

@fabpot
Copy link
Member

fabpot commented Oct 11, 2017

Thank you @ivoba.

@fabpot fabpot closed this Oct 11, 2017
fabpot added a commit that referenced this pull request Oct 11, 2017
…malizer (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
-------

5ecafc5 added ability to handle parent classes for PropertyNormalizer
This was referenced Oct 18, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants