Symfony2.7新機能 - シリアライゼーショングループ


Symfony2.7 新機能シリーズ。ゆるい日本語翻訳。その2

http://symfony.com/blog/new-in-symfony-2-7-serialization-groups

Symfony Serializer Component への新機能として、Serialization Groups という機能が追加された。
そもそも、Serializaer Component は、PHPのデータを永続化など目的のため、他の形式 (XML, JSON, YAML...) に変換する機能を持っている。(http://symfony.com/doc/current/components/serializer.html)
場所によっては一部のフィールドのみ Serialize したいという場面において、Annotation を使い、Group を作ることができるようになった。

シリアライズの必要なオブジェクトを作り、`@Groups` アノーテーションで、グループ名を指定。属するグループを複数指定できる仕様のようだ。同じく、YAML、XMLでも同じようなことが可能。

```php:Product.php
use Symfony\Component\Serializer\Annotation\Groups;

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

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

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

```yaml:sample.yaml
Bucyou\Product:
    attributes:
        itemSold:
            groups: ["admins"]
        commission:
            groups: ["admins", "affiliates"]
        price:
            groups: ["admins", "affiliates", "users"]
```

`normalize()` で、`groups` を限定して取り出す。複数のグループを指定することが可能。該当するグループのデータのみを返すようだ。

```php:annotationSample.php
<?php

require_once __DIR__.'/vendor/autoload.php';

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 Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Bucyou\Product;

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

AnnotationRegistry::registerFile(__DIR__.'/vendor/symfony/serializer/Symfony/Component/Serializer/Annotation/Groups.php');
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new PropertyNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

var_dump($serializer->normalize($product, null, ['groups' => ['admins']]));
/*
array(3) {
  'itemSold' =>
  int(20)
  'commission' =>
  double(7.5)
  'price' =>
  double(19.99)
}
 */
var_dump($serializer->normalize($product, null, ['groups' => ['affiliates']]));
/*
array(2) {
  'commission' =>
  double(7.5)
  'price' =>
  double(19.99)
}
*/
var_dump($serializer->normalize($product, null, ['groups' => ['users']]));
/*
array(1) {
  'price' =>
  double(19.99)
}
*/
var_dump($serializer->normalize($product, null, ['groups' => ['affiliates', 'users']]));
/*
array(2) {
  'commission' =>
  double(7.5)
  'price' =>
  double(19.99)
}
*/
```

```php:yamlSample.php
<?php

require_once __DIR__.'/vendor/autoload.php';

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Bucyou\Product;

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

$classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader(__DIR__.'/sample.yml'));
$normalizer = new PropertyNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

var_dump($serializer->normalize($product, null, ['groups' => ['admins']]));
/*
array(3) {
  'itemSold' =>
  int(20)
  'commission' =>
  double(7.5)
  'price' =>
  double(19.99)
}
 */
var_dump($serializer->normalize($product, null, ['groups' => ['affiliates']]));
/*
array(2) {
  'commission' =>
  double(7.5)
  'price' =>
  double(19.99)
}
*/
var_dump($serializer->normalize($product, null, ['groups' => ['users']]));
/*
array(1) {
  'price' =>
  double(19.99)
}
*/
var_dump($serializer->normalize($product, null, ['groups' => ['affiliates', 'users']]));
/*
array(2) {
  'commission' =>
  double(7.5)
  'price' =>
  double(19.99)
}
*/
```

(XMLはなんかダルくなってまだ書いてないw)

ソースコードはこちら: https://github.com/kawahara/serializerSample

`denormalize()` 時も、同じようにグループを適用することが可能。


今のところ、Symfony 標準の Bundle でこの機能を使っているところは見つけられなかったが、設定値などを限定して安全に取り出したいと言う時に使えるだろう。