Kévin Dunglas
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)
Published in #Living on the edge