Skip to content

[Serializer] ObjectNormalizer #13257

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

Merged
merged 1 commit into from
Mar 6, 2015

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Jan 4, 2015

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
License MIT
Doc PR not yet

PropertyAccessNormalizer is a new normalizer leveraging the PropertyAccess Component. It is able to handle classes containing both public properties and properties only accessibles trough getters / setters / issers / hassers...

As it extends AbstractNormalizer, it supports circular reference handling, name converters and existing object population.
What do you think about making this new normalizer the default one as it's the most convenient to use and the most consistent with the behavior of other components.
#13120, #13252 and #13255 need to be merged to make this PR working.

@dunglas
Copy link
Member Author

dunglas commented Jan 6, 2015

If you want to play with this new normalizer (or hack it), I've created a branch including all Serializer PR waiting to be merged (including this one): https://github.com/dunglas/symfony/tree/new_serializer

To use it in a standard edition install, add the following lines to your composer.json:

    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/dunglas/symfony"
        }
    ],

Then replace with Symfony line to use this experimental branch:

        "symfony/symfony": "dev-new_serializer as 2.7.0",

@mickaelandrieu
Copy link
Contributor

hi @dunglas, can you provide a practical sample of what this feature can do ?

@dunglas
Copy link
Member Author

dunglas commented Jan 6, 2015

class MyObj
{
    public $foo = 'foo';

    public getBar()
    {
       return 'bar';
    }

    public isBaz()
    {
        return true;
    }
}

$normalizer = new \Symfony\Component\Serializer\Normalizer\PropertyAccessNormalizer();
var_dump($normalizer->normalize(new MyObj()));
// Should output something like ['foo' => 'foo', 'bar' => 'bar', 'baz' => true]

@dunglas
Copy link
Member Author

dunglas commented Jan 6, 2015

This normalizer also supports denormalization (for gettters / setters and properties), serialization groups (http://symfony.com/blog/new-in-symfony-2-7-serialization-groups), name converters (symfony/symfony-docs#4692), circular references handlers (symfony/symfony-docs#4299) and existing object population (#13252).

@fabpot
Copy link
Member

fabpot commented Jan 7, 2015

👍

The only "issue" I see is the name; I understand that you named your class after the property access component but I find it confusing as at first, I thought it was about "just" supporting class properties. If it becomes the default one (which I think is a good idea), we should find a better name.

@dunglas
Copy link
Member Author

dunglas commented Jan 7, 2015

I agree, the name is confusing. What about ObjectNormalizer?

@fabpot
Copy link
Member

fabpot commented Jan 7, 2015

@dunglas If this is the "definitive" serializer, that sounds much better to me.

@mickaelandrieu
Copy link
Contributor

totaly agree with @fabpot , this should become the default serializer!

@@ -28,7 +28,8 @@
"doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.",
"doctrine/cache": "For using the default cached annotation reader and metadata cache.",
"symfony/yaml": "For using the default YAML mapping loader.",
"symfony/config": "For using the XML mapping loader."
"symfony/config": "For using the XML mapping loader.",
"symfony/property-access": "For using the property access normalizer."
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be moved to require if it becomes the default normalizer?

Copy link
Contributor

Choose a reason for hiding this comment

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

This should be the default serializer in the full stack framework, but please don't add more "hard" dependencies between (standalone) components !

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

@mickaelandrieu good point

@dunglas
Copy link
Member Author

dunglas commented Jan 17, 2015

What do you think about moving the code listing accessible "properties" (trough public properties and methods) - https://github.com/dunglas/symfony/blob/seriaizer_property_access_normalizer/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php#L62-L89 - in the PropertyAccess Component?

It can be useful in other contexts (in fact, I've an use case in a private project right now). cc @fabpot @webmozart

use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;

require_once __DIR__.'/../../Annotation/Groups.php';
Copy link
Member

Choose a reason for hiding this comment

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

you should rely on autoloading instead

@dunglas dunglas force-pushed the seriaizer_property_access_normalizer branch 4 times, most recently from b344af7 to 2f69022 Compare February 3, 2015 07:10
@dunglas dunglas changed the title [Serializer] PropertyAccessNormalizer [Serializer] ObjectNormalizer Feb 3, 2015
@dunglas dunglas force-pushed the seriaizer_property_access_normalizer branch 4 times, most recently from 7531332 to e1cf645 Compare February 4, 2015 12:59
@dunglas
Copy link
Member Author

dunglas commented Feb 4, 2015

Rebased. Should be ready for the merge now.

@@ -28,7 +29,8 @@
"doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.",
"doctrine/cache": "For using the default cached annotation reader and metadata cache.",
"symfony/yaml": "For using the default YAML mapping loader.",
"symfony/config": "For using the XML mapping loader."
"symfony/config": "For using the XML mapping loader.",
"symfony/property-access": "For using the ObjectNormalizer."
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 thanks a lot!

@dunglas
Copy link
Member Author

dunglas commented Feb 22, 2015

I've fixed tests with components=low. Is there any more work to be done before getting this PR merged?

continue;
}

$attributeValue = $this->propertyAccessor->getValue($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.

Is it on purpose you don't use an else block on the next statement? It can avoid a call to the this->propertyAccessor->getValue

Copy link
Member Author

Choose a reason for hiding this comment

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

@jeremy-derusse I don't understand what you mean.

Copy link
Member

Choose a reason for hiding this comment

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

You can replace

$attributeValue = $this->propertyAccessor->getValue($object, $attribute);
if (array_key_exists($attribute, $this->callbacks)) {
    $attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
}

by

if (array_key_exists($attribute, $this->callbacks)) {
    $attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
} else {
    $attributeValue = $this->propertyAccessor->getValue($object, $attribute);
}

and avoid to call $this->propertyAccessor->getValue($object, $attribute); when array_key_exists($attribute, $this->callbacks) is false.

Copy link
Member Author

Choose a reason for hiding this comment

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

No because $attributeValue in $attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue); will be undefined.

Copy link
Member Author

Choose a reason for hiding this comment

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

Or worse, the value of the previous loop iteration.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok I got it. But still no because the attribute value will never be retrieved. We need it even if a callback is not registered.

@dunglas dunglas force-pushed the seriaizer_property_access_normalizer branch from a562e42 to a4b6421 Compare March 1, 2015 17:04
@dunglas dunglas force-pushed the seriaizer_property_access_normalizer branch 3 times, most recently from fca94f2 to 6a12f1e Compare March 3, 2015 14:59
@dunglas
Copy link
Member Author

dunglas commented Mar 3, 2015

Rebased.

@dunglas
Copy link
Member Author

dunglas commented Mar 3, 2015

ping @symfony/deciders

@dunglas dunglas force-pushed the seriaizer_property_access_normalizer branch from 6a12f1e to 0050bbb Compare March 6, 2015 10:53
@dunglas dunglas merged commit 0050bbb into symfony:2.7 Mar 6, 2015
dunglas added a commit that referenced this pull request Mar 6, 2015
This PR was merged into the 2.7 branch.

Discussion
----------

[Serializer] ObjectNormalizer

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT
| Doc PR       | not yet

`PropertyAccessNormalizer` is a new normalizer leveraging the PropertyAccess Component. It is able to handle classes containing both public properties and properties only accessibles trough getters / setters / issers / hassers...

As it extends `AbstractNormalizer`, it supports circular reference handling, name converters and existing object population.
What do you think about making this new normalizer the default one as it's the most convenient to use and the most consistent with the behavior of other components.

#13120, #13252 and #13255 need to be merged to make this PR working.

Commits
-------

0050bbb [Serializer] Introduce ObjectNormalizer
@mickaelandrieu
Copy link
Contributor

👍 thanks for this improvement @dunglas !

dunglas added a commit that referenced this pull request Apr 27, 2015
…nnotations (dunglas)

This PR was merged into the 2.7 branch.

Discussion
----------

[Serializer] Supports hassers and setters for groups annotations

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | n/a

For more coherence with the new `ObjectNormalizer` (#13257), this PR allows to add `@Groups` annotations on hasser and setter methods too.

Commits
-------

9c87ecc [Serializer] Supports hassers and setters for groups annotations
@dunglas dunglas deleted the seriaizer_property_access_normalizer branch December 5, 2015 09:02
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.

7 participants