Skip to content

[Serializer] Serialization groups support #12092

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
Dec 21, 2014

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Oct 1, 2014

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
License MIT
Doc PR symfony/symfony-docs#4675

This PR is a first attempt adding serialization groups to the Serializer component. Btw, it also add supports of ignored attributes for denormalization (only normalization is currently supported).

Groups support is totally optional and is not enabled by default (in that case, the Serializer will have the current behavior). No BC spotted for now.

To use it:

use Symfony\Component\Serializer\Annotation\Groups;

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;

class MyObj
{
    /**
     * @Groups({"group1", "group2"})
     */
    public $foo;
    /**
     * @Groups({"group3"})
     */
    public $bar;
}

$obj = new MyObj();
$obj->foo = 'foo';
$obj->bar = 'bar';

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new PropertyNormalizer($classMetadataFactory);

$serializer = new Serializer([$normalizer]);
$data = $serializer->normalize($obj, null, ['groups' => ['group1']]);
// $data = ['foo' => 'foo'];

$obj2 = $serializer->denormalize(['foo' => 'foo', 'bar' => 'bar'], 'MyObj', null, ['groups' => ['group1', 'group3']);
// $obj2 = MyObj(foo: 'foo', bar: 'bar')

Some work still need to be done:

  • Add XML mapping
  • Add YAML mapping
  • Refactor tests

The ClassMetadata code is largely inspired from the code of the Validator component. Duplicated code in PropertyNormalizer and GetSetMethodNormalizer has been moved in a new AbstractNormalizer class.

This PR also make the interface of PropertyNormalizer fluent (like the current behavior of GetSetMethodNormalizer.

@dunglas dunglas force-pushed the serializer_groups branch from b405e14 to 86c81a1 Compare October 1, 2014 15:52
@jjsaunier
Copy link

👎

The serializer Symfony meets the needs, and that's enough (well I think), and for further applications, there JMSSerializer exists, and have an exellent approach to resolve this problematic. I find that having a "simple" serializer (sf) and serializer under "Steroid" (jms) is good. What is the motivation to add this kind of functionality?

@dunglas
Copy link
Member Author

dunglas commented Oct 1, 2014

@Prophet777 the initial motivation is adding groups support to HydraBundle. Of course this can be done directly in that bundle but as the code is generic and will work with any encoder (Hydra or anything else) I've opened this PR here. Note that this does not break BC and that groups support is not enabled by default. Pass no parameter to the normalizer's constructor and the Serializer will behave exactly as before.

Other motivations are:

  • have a powerful MIT serializer (JMSSerializer is under Apache license, so we cannot use it in a GPLv2 project - and it's my case)
  • have all tools needed to easily create REST APIs directly in Symfony (and groups support or something similar is a must have)

And btw, the Serializer currently does not meet the need. Circular references are not handled and serializing a typical set of entities can lead to an infinite loop. I'll submit a PR to fix that soon.

@dunglas
Copy link
Member Author

dunglas commented Oct 1, 2014

About the licensing issue see symfony/symfony-standard#535

$metadata->addAttributeGroup(lcfirst($matches[2]), $group);
}
} else {
throw new \BadMethodCallException(sprintf('The constraint on "%s::%s" cannot be added. Constraints can only be added on methods beginning with "get", "is" or "has".', $className, $method->name));
Copy link
Member

Choose a reason for hiding this comment

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

looks like you copied the code from the Validator component without being careful about changing it to you needs

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right!
I'll change the exception message.

@dunglas
Copy link
Member Author

dunglas commented Oct 2, 2014

@stof fixed.

@stof stof added the Serializer label Oct 6, 2014
@dunglas dunglas changed the title [WIP] [Serializer] Serialization groups support [Serializer] Serialization groups support Oct 6, 2014
@dunglas
Copy link
Member Author

dunglas commented Oct 6, 2014

This PR is almost done. I've added a YAML and a XML loader.
Something still bothers me: some code (especially LoaderChain) is almost copy/pasted from the Validation component. Should it be refactored?

@stof
Copy link
Member

stof commented Oct 7, 2014

@dunglas we have the time to figure a way to handle this, given that it won't be part of 2.6 (we have reach the feature freeze)

@dunglas
Copy link
Member Author

dunglas commented Oct 7, 2014

I've looked more in depth to this piece of code. Only LoaderChain is duplicated and it's only 50 lines of very generic code. Other loaders are similar in structure but have different responsibilities (because serializer's metadata have nothing to do with validator's metadata).
It seems acceptable to me to duplicate this particular (LoaderChain) small piece of code.

@lsmith77
Copy link
Contributor

btw .. need a rebase now

@dunglas
Copy link
Member Author

dunglas commented Oct 20, 2014

Rebased.

@dunglas
Copy link
Member Author

dunglas commented Dec 11, 2014

Rebased against master. Any update about the status of this PR now that 2.6 has been released?

@fabpot
Copy link
Member

fabpot commented Dec 12, 2014

I agree with @dunglas that getting a better serializer in code in a good idea for reasons he explained above; of course, we need to keep the current philosophy of the component.

Seeing that @dunglas is investing a lot of time in this component with great ideas and PRs, no one is really maintaining this component, I propose to let him move the component forward. What do you think @lsmith77 @Seldaek?

@lsmith77
Copy link
Contributor

+1 .. I have full trust in him

@Seldaek
Copy link
Member

Seldaek commented Dec 12, 2014

+1 for me too, run with it and do great things! :)

@dunglas
Copy link
Member Author

dunglas commented Dec 13, 2014

😺

@dunglas
Copy link
Member Author

dunglas commented Dec 15, 2014

@fabpot It's possible to host the new xsd on symfony.com to make Travis happy?

@fabpot
Copy link
Member

fabpot commented Dec 21, 2014

@dunglas I think the next step would be to open a PR on the docs as it needs to be documented before merge.

@dunglas
Copy link
Member Author

dunglas commented Dec 21, 2014

Submitted a doc: symfony/symfony-docs/pull/4675

@fabpot
Copy link
Member

fabpot commented Dec 21, 2014

Thank you @dunglas.

@fabpot fabpot merged commit dcf1d97 into symfony:master Dec 21, 2014
fabpot added a commit that referenced this pull request Dec 21, 2014
This PR was merged into the 3.0-dev branch.

Discussion
----------

[Serializer] Serialization groups support

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT
| Doc PR        | symfony/symfony-docs#4675

This PR is a first attempt adding serialization groups to the `Serializer` component. Btw, it also add supports of ignored attributes for denormalization (only normalization is currently supported).

Groups support is totally optional and is not enabled by default (in that case, the `Serializer` will have the current behavior). No BC spotted for now.

To use it:
```php
use Symfony\Component\Serializer\Annotation\Groups;

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;

class MyObj
{
    /**
     * @groups({"group1", "group2"})
     */
    public $foo;
    /**
     * @groups({"group3"})
     */
    public $bar;
}

$obj = new MyObj();
$obj->foo = 'foo';
$obj->bar = 'bar';

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new PropertyNormalizer($classMetadataFactory);

$serializer = new Serializer([$normalizer]);
$data = $serializer->normalize($obj, null, ['groups' => ['group1']]);
// $data = ['foo' => 'foo'];

$obj2 = $serializer->denormalize(['foo' => 'foo', 'bar' => 'bar'], 'MyObj', null, ['groups' => ['group1', 'group3']);
// $obj2 = MyObj(foo: 'foo', bar: 'bar')
```

Some work still need to be done:
- [x] Add XML mapping
- [x] Add YAML mapping
- [x] Refactor tests

The `ClassMetadata` code is largely inspired from the code of the `Validator` component. Duplicated code in `PropertyNormalizer` and `GetSetMethodNormalizer` has been moved in a new `AbstractNormalizer` class.

This PR also make the interface of `PropertyNormalizer` fluent (like the current behavior of `GetSetMethodNormalizer`.

Commits
-------

dcf1d97 [Serializer] Serialization groups support
@dunglas
Copy link
Member Author

dunglas commented Dec 21, 2014

Can this feature be merged in 2.7?

@fabpot
Copy link
Member

fabpot commented Dec 21, 2014

done

fabpot added a commit that referenced this pull request Dec 21, 2014
This PR was submitted for the master branch but it was merged into the 2.7 branch instead (closes #12092).

Discussion
----------

[Serializer] Serialization groups support

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT
| Doc PR        | symfony/symfony-docs#4675

This PR is a first attempt adding serialization groups to the `Serializer` component. Btw, it also add supports of ignored attributes for denormalization (only normalization is currently supported).

Groups support is totally optional and is not enabled by default (in that case, the `Serializer` will have the current behavior). No BC spotted for now.

To use it:
```php
use Symfony\Component\Serializer\Annotation\Groups;

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;

class MyObj
{
    /**
     * @groups({"group1", "group2"})
     */
    public $foo;
    /**
     * @groups({"group3"})
     */
    public $bar;
}

$obj = new MyObj();
$obj->foo = 'foo';
$obj->bar = 'bar';

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new PropertyNormalizer($classMetadataFactory);

$serializer = new Serializer([$normalizer]);
$data = $serializer->normalize($obj, null, ['groups' => ['group1']]);
// $data = ['foo' => 'foo'];

$obj2 = $serializer->denormalize(['foo' => 'foo', 'bar' => 'bar'], 'MyObj', null, ['groups' => ['group1', 'group3']);
// $obj2 = MyObj(foo: 'foo', bar: 'bar')
```

Some work still need to be done:
- [x] Add XML mapping
- [x] Add YAML mapping
- [x] Refactor tests

The `ClassMetadata` code is largely inspired from the code of the `Validator` component. Duplicated code in `PropertyNormalizer` and `GetSetMethodNormalizer` has been moved in a new `AbstractNormalizer` class.

This PR also make the interface of `PropertyNormalizer` fluent (like the current behavior of `GetSetMethodNormalizer`.

Commits
-------

57a191b [Serializer] Serialization groups support
@dunglas
Copy link
Member Author

dunglas commented Dec 21, 2014

Thanks!

@dunglas
Copy link
Member Author

dunglas commented Dec 24, 2014

@fabpot can you upload the XSD at the following URL http://symfony.com/schema/dic/services/services-1.0.xsd to make the XmlFileLoader working?

Thanks!

@wouterj
Copy link
Member

wouterj commented Dec 24, 2014

@dunglas the file loader is not based on the XSD on that url, but instead on the XSD downloaded with symfony.

@dunglas
Copy link
Member Author

dunglas commented Dec 24, 2014

@wouterj not yet for the serializer but I'll add it soon.

@dunglas
Copy link
Member Author

dunglas commented Dec 25, 2014

@wouterj sorry I'm wrong and you're right. The feature is present but tests use a wrong (old) XML format (#13108).

weaverryan added a commit to symfony/symfony-docs that referenced this pull request May 22, 2015
This PR was merged into the 2.7 branch.

Discussion
----------

[Serializer] Doc for groups support

| Q                | A
| --------------- | ---
| Doc fix?      | no
| New docs? | yes symfony/symfony#12092
| Applies to   | 2.7

This is the documentation for serialization groups support.

Commits
-------

e417395 [Serializer] Fix CS
ae2b78c [Serializer] Add getter group example
745f412 [Serializer] Doc for groups support
@dunglas dunglas deleted the serializer_groups branch December 5, 2015 09:01
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