New in Symfony 2.7: Serialization Groups

Contributed by
Kévin Dunglas
in #12092.

The Symfony Serializer component is used to turn PHP objects into a specific format (XML, JSON, YAML, ...) and the other way around. In order to maintain its simplicity, we've limited the scope of the component and that's why it's one of the Symfony components with less new features since its introduction.

In Symfony 2.7 we've decided to reverse this trend and we're introducing a new feature to serialize/deserialize different sets of object attributes. Consider the following object that includes properties aimed to administrators, affiliates and regular users:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Product
{
    // this property is exclusive for administrators
    public $itemsSold;

    // this property is visible by administrators and affiliates
    public $commission;

    // this property is visible by all (administrators, affiliates, users)
    public $price;
}

The definition of serialization can be specified using annotations, XML or YAML. In case of using annotations, define serialization groups as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
use Symfony\Component\Serializer\Annotation\Groups;

class Product
{
    /**
     * @Groups({"admins"})
     */
    public $itemsSold;

    /**
     * @Groups({"admins", "affiliates"})
     */
    public $commission;

    /**
     * @Groups({"admins", "affiliates", "users"})
     */
    public $price;
}

Now that serialization groups have been defined, you can serialize only the attributes that belong to the given groups:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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;
use Doctrine\Common\Annotations\AnnotationReader;

$product = new Product();
$product->itemsSold = 20;
$product->commission = 7.5;
$product->price = 19.99;

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new PropertyNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

$data = $serializer->normalize($product, null, ['groups' => ['admins']]);
// $data = ['itemsSold' => 20, 'commission' => 7.5, 'price' => 19.99];

$data = $serializer->normalize($product, null, ['groups' => ['affiliates']]);
// $data = ['comission' => 7.5, 'price' => 19.99];

$data = $serializer->normalize($product, null, ['groups' => ['users']]);
// $data = ['price' => 19.99];

$data = $serializer->normalize($product, null, ['groups' => ['affiliates', 'users']]);
// $data = ['commission' => 7.5, 'price' => 19.99];

Similarly, you can define the groups to user when deserializing contents:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
use Doctrine\Common\Annotations\AnnotationReader;

$product = new Product();
$product->itemsSold = 20;
$product->commission = 7.5;
$product->price = 19.99;

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

$product = $serializer->denormalize(
    ['itemsSold' => 20, 'price' => 19.99, 'commission' => 7.5],
    'Product',
    null,
    ['groups' => ['affiliates', 'users']]
);
// $product = Product(price: 19.99, commission: 7.5)

Comments

Awesome! Looks like JMSSerializer is not so necessary now, thanks Kévin.
There are a few issues in your code snippets:

- missing $ for the price property (in both class definitions)
- the instantiation of $classMetadataFactory is missing in all code snippets, while it is one of the changes in 2.7
One more issue : serializing attributes 'affiliates' and 'users' group will only produce this :
// $data = ['commission' => 7.5, 'price' => 19.99];
(This in the exemple of serializing. The exemple of deserialization is correct)
@Christophe @cgodot thanks for your review! All issues have been fixed now.
Another thing,the following use statement must be added to the Product class snippet:

use Symfony\Component\Serializer\Annotation\Groups;
Wonderful !
Good news !
This PR also introduce support for of the "ignoring attributes" feature for deserialization (for serialization, the feature was available since Symfony 2.3): http://symfony.com/doc/current/components/serializer.html#ignoring-attributes-when-serializing

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.