The Serializer Component

The Serializer component is meant to be used to turn objects into a specific format (XML, JSON, YAML, ...) and the other way around.

Serializer コンポーネントは、オブジェクトを特定の形式 (XML、JSON、YAML など) に変換したり、その逆を行うために使用することを意図しています。

In order to do so, the Serializer component follows the following schema.

そのために、Serializer コンポーネントは次のスキーマに従います。

As you can see in the picture above, an array is used as an intermediary between objects and serialized contents. This way, encoders will only deal with turning specific formats into arrays and vice versa. The same way, Normalizers will deal with turning specific objects into arrays and vice versa.

上の図からわかるように、配列はオブジェクトとシリアル化されたコンテンツの間の仲介として使用されます。このように、エンコーダーは特定の形式を配列に、またはその逆に変換することのみを処理します。同様に、ノーマライザーは特定のオブジェクトを配列に変換したり、その逆を処理したりします。

Serialization is a complex topic. This component may not cover all your use cases out of the box, but it can be useful for developing tools to serialize and deserialize your objects.

シリアル化は複雑なトピックです。このコンポーネントは、すぐに使用できるすべてのユースケースをカバーするわけではありませんが、オブジェクトをシリアライズおよびデシリアライズするツールを開発するのに役立ちます。

Installation

1
$ composer require symfony/serializer

Note

ノート

If you install this component outside of a Symfony application, you must require the vendor/autoload.php file in your code to enable the class autoloading mechanism provided by Composer. Read this article for more details.

このコンポーネントを Symfony アプリケーションの外部にインストールする場合は、Composer が提供するクラス自動ロード メカニズムを有効にするために、コード内に vendor/autoload.php ファイルを必要とする必要があります。詳細については、この記事をお読みください。

To use the ObjectNormalizer, the PropertyAccess component must also be installed.

ObjectNormalizer を使用するには、PropertyAccess コンポーネントもインストールする必要があります。

Usage

See also

こちらもご覧ください

This article explains the philosophy of the Serializer and gets you familiar with the concepts of normalizers and encoders. The code examples assume that you use the Serializer as an independent component. If you are using the Serializer in a Symfony application, read How to Use the Serializer after you finish this article.

この記事では、シリアライザーの原理を説明し、ノーマライザーとエンコーダーの概念に慣れてもらいます。コード例では、シリアライザーを独立したコンポーネントとして使用することを前提としています。 Symfony アプリケーションでシリアライザーを使用している場合は、この記事の終了後にシリアライザーの使用方法をお読みください。

To use the Serializer component, set up the Serializer specifying which encoders and normalizer are going to be available:

Serializer コンポーネントを使用するには、どのエンコーダーとノーマライザーを使用できるようにするかを指定して、Serializer をセットアップします。
1
2
3
4
5
6
7
8
9
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$encoders = [new XmlEncoder(), new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];

$serializer = new Serializer($normalizers, $encoders);

The preferred normalizer is the ObjectNormalizer, but other normalizers are available. All the examples shown below use the ObjectNormalizer.

推奨されるノーマライザーは ObjectNormalizer ですが、他のノーマライザーも使用できます。以下に示すすべての例では、ObjectNormalizer を使用しています。

Serializing an Object

For the sake of this example, assume the following class already exists in your project:

この例では、次のクラスがプロジェクトに既に存在すると仮定します。
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
namespace App\Model;

class Person
{
    private int $age;
    private string $name;
    private bool $sportsperson;
    private ?\DateTime $createdAt;

    // Getters
    public function getAge(): int
    {
        return $this->age;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    // Issers
    public function isSportsperson(): bool
    {
        return $this->sportsperson;
    }

    // Setters
    public function setAge(int $age): void
    {
        $this->age = $age;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }

    public function setSportsperson(bool $sportsperson): void
    {
        $this->sportsperson = $sportsperson;
    }

    public function setCreatedAt(\DateTime $createdAt = null): void
    {
        $this->createdAt = $createdAt;
    }
}

Now, if you want to serialize this object into JSON, you only need to use the Serializer service created before:

このオブジェクトを JSON にシリアル化する場合は、前に作成した Serializer サービスを使用するだけで済みます。
1
2
3
4
5
6
7
8
9
10
11
12
use App\Model\Person;

$person = new Person();
$person->setName('foo');
$person->setAge(99);
$person->setSportsperson(false);

$jsonContent = $serializer->serialize($person, 'json');

// $jsonContent contains {"name":"foo","age":99,"sportsperson":false,"createdAt":null}

echo $jsonContent; // or return it in a Response

The first parameter of the serialize() is the object to be serialized and the second is used to choose the proper encoder, in this case JsonEncoder.

serialize() の最初のパラメータはシリアル化されるオブジェクトで、2 番目のパラメータは適切なエンコーダ (この場合は JsonEncoder) を選択するために使用されます。

Deserializing an Object

You'll now learn how to do the exact opposite. This time, the information of the Person class would be encoded in XML format:

ここでは、正反対の方法を学習します。今回は、Person クラスの情報が XML 形式でエンコードされます。
1
2
3
4
5
6
7
8
9
10
11
use App\Model\Person;

$data = <<<EOF
<person>
    <name>foo</name>
    <age>99</age>
    <sportsperson>false</sportsperson>
</person>
EOF;

$person = $serializer->deserialize($data, Person::class, 'xml');

In this case, deserialize() needs three parameters:

この場合、deserialize() には 3 つのパラメーターが必要です。
  1. The information to be decoded
    デコードする情報
  2. The name of the class this information will be decoded to
    この情報がデコードされるクラスの名前
  3. The encoder used to convert that information into an array
    その情報を配列に変換するために使用されるエンコーダー

By default, additional attributes that are not mapped to the denormalized object will be ignored by the Serializer component. If you prefer to throw an exception when this happens, set the AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES context option to false and provide an object that implements ClassMetadataFactoryInterface when constructing the normalizer:

デフォルトでは、非正規化オブジェクトにマップされていない追加の属性は、シリアライザー コンポーネントによって無視されます。これが発生したときに例外をスローする場合は、AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES コンテキスト オプションを false に設定し、ノーマライザーの構築時に ClassMetadataFactoryInterface を実装するオブジェクトを提供します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use App\Model\Person;

$data = <<<EOF
<person>
    <name>foo</name>
    <age>99</age>
    <city>Paris</city>
</person>
EOF;

// $loader is any of the valid loaders explained later in this article
$classMetadataFactory = new ClassMetadataFactory($loader);
$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

// this will throw a Symfony\Component\Serializer\Exception\ExtraAttributesException
// because "city" is not an attribute of the Person class
$person = $serializer->deserialize($data, Person::class, 'xml', [
    AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
]);

Deserializing in an Existing Object

The serializer can also be used to update an existing object:

シリアライザーは、既存のオブジェクトを更新するためにも使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...
$person = new Person();
$person->setName('bar');
$person->setAge(99);
$person->setSportsperson(true);

$data = <<<EOF
<person>
    <name>foo</name>
    <age>69</age>
</person>
EOF;

$serializer->deserialize($data, Person::class, 'xml', [AbstractNormalizer::OBJECT_TO_POPULATE => $person]);
// $person = App\Model\Person(name: 'foo', age: '69', sportsperson: true)

This is a common need when working with an ORM.

これは、ORM を使用する場合によく必要になります。

The AbstractNormalizer::OBJECT_TO_POPULATE is only used for the top level object. If that object is the root of a tree structure, all child elements that exist in the normalized data will be re-created with new instances.

AbstractNormalizer::OBJECT_TO_POPULATE は、最上位オブジェクトにのみ使用されます。そのオブジェクトがツリー構造のルートである場合、正規化されたデータに存在するすべての子要素が新しいインスタンスで再作成されます。

When the AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE option is set to true, existing children of the root OBJECT_TO_POPULATE are updated from the normalized data, instead of the denormalizer re-creating them. Note that DEEP_OBJECT_TO_POPULATE only works for single child objects, but not for arrays of objects. Those will still be replaced when present in the normalized data.

AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE オプションが true に設定されている場合、ルート OBJECT_TO_POPULATE の既存の子は、デノーマライザーがそれらを再作成する代わりに、正規化されたデータから更新されます。 DEEP_OBJECT_TO_POPULATE は単一の子オブジェクトに対してのみ機能し、オブジェクトの配列に対しては機能しないことに注意してください。それらは、正規化されたデータに存在する場合でも置き換えられます。

Context

Many Serializer features can be configured using a context.

多くのシリアライザー機能は、コンテキストを使用して構成できます。

Attributes Groups

Sometimes, you want to serialize different sets of attributes from your entities. Groups are a handy way to achieve this need.

エンティティからさまざまな属性セットをシリアライズしたい場合があります。グループは、このニーズを実現する便利な方法です。

Assume you have the following plain-old-PHP object:

次のプレーン オールド PHP オブジェクトがあるとします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace Acme;

class MyObj
{
    public $foo;

    private $bar;

    public function getBar()
    {
        return $this->bar;
    }

    public function setBar($bar)
    {
        return $this->bar = $bar;
    }
}

The definition of serialization can be specified using annotations, XML or YAML. The ClassMetadataFactory that will be used by the normalizer must be aware of the format to use.

シリアライゼーションの定義は、注釈、XML または YAML を使用して指定できます。ノーマライザーによって使用される ClassMetadataFactory は、使用する形式を認識している必要があります。

The following code shows how to initialize the ClassMetadataFactory for each format:

次のコードは、各形式の ClassMetadataFactory を初期化する方法を示しています。
  • Annotations in PHP files:

    PHP ファイルの注釈:
    1
    2
    3
    4
    5
    use Doctrine\Common\Annotations\AnnotationReader;
    use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
    use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
    
    $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
  • YAML files:

    YAML ファイル:
    1
    2
    3
    4
    use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
    use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
    
    $classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader('/path/to/your/definition.yaml'));
  • XML files:

    XML ファイル:
    1
    2
    3
    4
    use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
    use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
    
    $classMetadataFactory = new ClassMetadataFactory(new XmlFileLoader('/path/to/your/definition.xml'));

Then, create your groups definition:

次に、グループ定義を作成します。
  • Attributes
    属性
  • YAML
    YAML
  • XML
    XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace Acme;

use Symfony\Component\Serializer\Annotation\Groups;

class MyObj
{
    #[Groups(['group1', 'group2'])]
    public $foo;

    #[Groups(['group4'])]
    public $anotherProperty;

    #[Groups(['group3'])]
    public function getBar() // is* methods are also supported
    {
        return $this->bar;
    }

    // ...
}

You are now able to serialize only attributes in the groups you want:

必要なグループの属性のみをシリアル化できるようになりました。
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
27
28
29
30
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

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

$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

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

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

// To get all groups, use the special value `*` in `groups`
$obj3 = $serializer->denormalize(
    ['foo' => 'foo', 'anotherProperty' => 'anotherProperty', 'bar' => 'bar'],
    'MyObj',
    null,
    ['groups' => ['*']]
);
// $obj2 = MyObj(foo: 'foo', anotherProperty: 'anotherProperty', bar: 'bar')

Selecting Specific Attributes

It is also possible to serialize only a set of specific attributes:

特定の属性のセットのみをシリアル化することもできます。
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
27
28
29
30
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

class User
{
    public $familyName;
    public $givenName;
    public $company;
}

class Company
{
    public $name;
    public $address;
}

$company = new Company();
$company->name = 'Les-Tilleuls.coop';
$company->address = 'Lille, France';

$user = new User();
$user->familyName = 'Dunglas';
$user->givenName = 'Kévin';
$user->company = $company;

$serializer = new Serializer([new ObjectNormalizer()]);

$data = $serializer->normalize($user, null, [AbstractNormalizer::ATTRIBUTES => ['familyName', 'company' => ['name']]]);
// $data = ['familyName' => 'Dunglas', 'company' => ['name' => 'Les-Tilleuls.coop']];

Only attributes that are not ignored (see below) are available. If some serialization groups are set, only attributes allowed by those groups can be used.

無視されない属性 (以下を参照) のみが使用可能です。いくつかのシリアライゼーション グループが設定されている場合、それらのグループで許可されている属性のみを使用できます。

As for groups, attributes can be selected during both the serialization and deserialization process.

グループに関しては、シリアライゼーション プロセスとデシリアライゼーション プロセスの両方で属性を選択できます。

Ignoring Attributes

All attributes are included by default when serializing objects. There are two options to ignore some of those attributes.

オブジェクトをシリアライズするとき、デフォルトですべての属性が含まれます。これらの属性の一部を無視するには、2 つのオプションがあります。

Option 1: Using @Ignore Annotation

  • Attributes
    属性
  • YAML
    YAML
  • XML
    XML
1
2
3
4
5
6
7
8
9
10
11
namespace App\Model;

use Symfony\Component\Serializer\Annotation\Ignore;

class MyClass
{
    public $foo;

    #[Ignore]
    public $bar;
}

You can now ignore specific attributes during serialization:

シリアル化中に特定の属性を無視できるようになりました。
1
2
3
4
5
6
7
8
9
10
11
12
13
use App\Model\MyClass;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

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

$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

$data = $serializer->normalize($obj);
// $data = ['foo' => 'foo'];

Option 2: Using the Context

Pass an array with the names of the attributes to ignore using the AbstractNormalizer::IGNORED_ATTRIBUTES key in the context of the serializer method:

シリアライザー メソッドのコンテキストで AbstractNormalizer::IGNORED_ATTRIBUTES キーを使用して、無視する属性の名前の配列を渡します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Acme\Person;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$person = new Person();
$person->setName('foo');
$person->setAge(99);

$normalizer = new ObjectNormalizer();
$encoder = new JsonEncoder();

$serializer = new Serializer([$normalizer], [$encoder]);
$serializer->serialize($person, 'json', [AbstractNormalizer::IGNORED_ATTRIBUTES => ['age']]); // Output: {"name":"foo"}

Converting Property Names when Serializing and Deserializing

Sometimes serialized attributes must be named differently than properties or getter/setter methods of PHP classes.

シリアル化された属性は、PHP クラスのプロパティまたは getter/setter メソッドとは異なる名前を付ける必要がある場合があります。

The Serializer component provides a handy way to translate or map PHP field names to serialized names: The Name Converter System.

Serializer コンポーネントは、PHP フィールド名をシリアル化された名前に変換またはマップするための便利な方法を提供します: The Name Converter System。

Given you have the following object:

次のオブジェクトがあるとします。
1
2
3
4
5
class Company
{
    public $name;
    public $address;
}

And in the serialized form, all attributes must be prefixed by org_ like the following:

また、シリアル化された形式では、次のようにすべての属性に org_ をプレフィックスとして付ける必要があります。
1
{"org_name": "Acme Inc.", "org_address": "123 Main Street, Big City"}

A custom name converter can handle such cases:

カスタム名コンバーターは、そのようなケースを処理できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;

class OrgPrefixNameConverter implements NameConverterInterface
{
    public function normalize(string $propertyName): string
    {
        return 'org_'.$propertyName;
    }

    public function denormalize(string $propertyName): string
    {
        // removes 'org_' prefix
        return 'org_' === substr($propertyName, 0, 4) ? substr($propertyName, 4) : $propertyName;
    }
}

The custom name converter can be used by passing it as second parameter of any class extending AbstractNormalizer, including GetSetMethodNormalizer and PropertyNormalizer:

カスタム名コンバーターは、GetSetMethodNormalizer および PropertyNormalizer を含む、AbstractNormalizer を拡張する任意のクラスの 2 番目のパラメーターとして渡すことによって使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$nameConverter = new OrgPrefixNameConverter();
$normalizer = new ObjectNormalizer(null, $nameConverter);

$serializer = new Serializer([$normalizer], [new JsonEncoder()]);

$company = new Company();
$company->name = 'Acme Inc.';
$company->address = '123 Main Street, Big City';

$json = $serializer->serialize($company, 'json');
// {"org_name": "Acme Inc.", "org_address": "123 Main Street, Big City"}
$companyCopy = $serializer->deserialize($json, Company::class, 'json');
// Same data as $company

Note

ノート

You can also implement AdvancedNameConverterInterface to access the current class name, format and context.

AdvancedNameConverterInterface を実装して、現在のクラス名、形式、およびコンテキストにアクセスすることもできます。

CamelCase to snake_case

In many formats, it's common to use underscores to separate words (also known as snake_case). However, in Symfony applications is common to use CamelCase to name properties (even though the PSR-1 standard doesn't recommend any specific case for property names).

多くの形式では、単語を区切るためにアンダースコアを使用するのが一般的です (snake_case とも呼ばれます)。ただし、Symfony アプリケーションでは、プロパティ名に CamelCase を使用するのが一般的です (PSR-1 標準では、プロパティ名に特定のケースを推奨していませんが)。

Symfony provides a built-in name converter designed to transform between snake_case and CamelCased styles during serialization and deserialization processes:

Symfony は、シリアライゼーションおよびデシリアライゼーションのプロセス中に、snake_case スタイルと CamelCased スタイルの間で変換するように設計された組み込みの名前コンバーターを提供します。
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\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

$normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter());

class Person
{
    private $firstName;

    public function __construct($firstName)
    {
        $this->firstName = $firstName;
    }

    public function getFirstName()
    {
        return $this->firstName;
    }
}

$kevin = new Person('Kévin');
$normalizer->normalize($kevin);
// ['first_name' => 'Kévin'];

$anne = $normalizer->denormalize(['first_name' => 'Anne'], 'Person');
// Person object with firstName: 'Anne'

Configure name conversion using metadata

When using this component inside a Symfony application and the class metadata factory is enabled as explained in the Attributes Groups section, this is already set up and you only need to provide the configuration. Otherwise:

このコンポーネントを Symfony アプリケーション内で使用し、属性グループ セクションで説明されているようにクラス metadatafactory が有効になっている場合、これは既に設定されており、構成を提供するだけで済みます。さもないと:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

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

$metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);

$serializer = new Serializer(
    [new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter)],
    ['json' => new JsonEncoder()]
);

Now configure your name conversion mapping. Consider an application that defines a Person entity with a firstName property:

次に、名前変換マッピングを構成します。 firstName プロパティを使用して Person エンティティを定義するアプリケーションを考えてみましょう。
  • Attributes
    属性
  • YAML
    YAML
  • XML
    XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace App\Entity;

use Symfony\Component\Serializer\Annotation\SerializedName;

class Person
{
    #[SerializedName('customer_name')]
    private $firstName;

    public function __construct($firstName)
    {
        $this->firstName = $firstName;
    }

    // ...
}

This custom mapping is used to convert property names when serializing and deserializing objects:

このカスタム マッピングは、オブジェクトをシリアル化および逆シリアル化するときにプロパティ名を変換するために使用されます。
1
2
$serialized = $serializer->serialize(new Person('Kévin'), 'json');
// {"customer_name": "Kévin"}

Serializing Boolean Attributes

If you are using isser methods (methods prefixed by is, like App\Model\Person::isSportsperson()), the Serializer component will automatically detect and use it to serialize related attributes.

isser メソッド (App\Model\Person::isSportsperson() など、is で始まるメソッド) を使用している場合、Serializer コンポーネントはそれを自動的に検出し、関連する属性をシリアル化するために使用します。

The ObjectNormalizer also takes care of methods starting with has, get, and can.

ObjectNormalizer は、has、get、および can で始まるメソッドも処理します。

6.1

6.1

The support of canners (methods prefixed by can) was introduced in Symfony 6.1.

canners (can で始まるメソッド) のサポートは、Symfony 6.1 で導入されました。

Using Callbacks to Serialize Properties with Object Instances

When serializing, you can set a callback to format a specific object property:

シリアル化するとき、コールバックを設定して特定のオブジェクト プロパティをフォーマットできます。
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
27
28
29
use App\Model\Person;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Serializer;

$encoder = new JsonEncoder();

// all callback parameters are optional (you can omit the ones you don't use)
$dateCallback = function ($innerObject, $outerObject, string $attributeName, string $format = null, array $context = []) {
    return $innerObject instanceof \DateTime ? $innerObject->format(\DateTime::ISO8601) : '';
};

$defaultContext = [
    AbstractNormalizer::CALLBACKS => [
        'createdAt' => $dateCallback,
    ],
];

$normalizer = new GetSetMethodNormalizer(null, null, null, null, null, $defaultContext);

$serializer = new Serializer([$normalizer], [$encoder]);

$person = new Person();
$person->setName('cordoval');
$person->setAge(34);
$person->setCreatedAt(new \DateTime('now'));

$serializer->serialize($person, 'json');
// Output: {"name":"cordoval", "age": 34, "createdAt": "2014-03-22T09:43:12-0500"}

Normalizers

Normalizers turn objects into arrays and vice versa. They implement NormalizerInterface for normalizing (object to array) and DenormalizerInterface for denormalizing (array to object).

ノーマライザーは、オブジェクトを配列に、またはその逆に変換します。これらは、正規化 (オブジェクトから配列) のための NormalizerInterface と、非正規化 (配列からオブジェクトへ) のための DenormalizerInterface を実装します。

Normalizers are enabled in the serializer passing them as its first argument:

ノーマライザーは、それらを最初の引数として渡すシリアライザーで有効になります。
1
2
3
4
5
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, []);

Built-in Normalizers

The Serializer component provides several built-in normalizers:

Serializer コンポーネントには、いくつかの組み込みノーマライザーが用意されています。
ObjectNormalizer

This normalizer leverages the PropertyAccess Component to read and write in the object. It means that it can access to properties directly and through getters, setters, hassers, issers, canners, adders and removers. It supports calling the constructor during the denormalization process.

このノーマライザーは、PropertyAccess コンポーネントを利用して、オブジェクトの読み取りと書き込みを行います。これは、プロパティに直接、および getter、setter、hasser、isser、canner、adder、および remover を介してアクセスできることを意味します。非正規化プロセス中のコンストラクターの呼び出しをサポートします。

Objects are normalized to a map of property names and values (names are generated by removing the get, set, has, is, can, add or remove prefix from the method name and transforming the first letter to lowercase; e.g. getFirstName() -> firstName).

オブジェクトは、プロパティ名と値のマップに正規化されます (名前は、メソッド名から get、set、has、is、can、add、または removeprefix を削除し、最初の文字を小文字に変換することによって生成されます。例: getFirstName() -> firstName) .

The ObjectNormalizer is the most powerful normalizer. It is configured by default in Symfony applications with the Serializer component enabled.

ObjectNormalizer は、最も強力なノーマライザーです。 Serializer コンポーネントが有効になっている Symfony アプリケーションでは、デフォルトで設定されています。
GetSetMethodNormalizer

This normalizer reads the content of the class by calling the "getters" (public methods starting with "get"). It will denormalize data by calling the constructor and the "setters" (public methods starting with "set").

このノーマライザーは、「getter」(「get」で始まるパブリック メソッド) を呼び出して、クラスの内容を読み取ります。コンストラクターと「セッター」(「set」で始まるパブリック メソッド) を呼び出すことにより、データを非正規化します。

Objects are normalized to a map of property names and values (names are generated by removing the get prefix from the method name and transforming the first letter to lowercase; e.g. getFirstName() -> firstName).

オブジェクトは、プロパティ名と値のマップに正規化されます (名前は、メソッド名から get プレフィックスを削除し、最初の文字を小文字に変換することによって生成されます。たとえば、getFirstName() -> firstName)。
PropertyNormalizer

This normalizer directly reads and writes public properties as well as private and protected properties (from both the class and all of its parent classes) by using PHP reflection. It supports calling the constructor during the denormalization process.

このノーマライザーは、PHP リフレクションを使用して、(クラスとそのすべての親クラスの両方から) パブリック プロパティとプライベート プロパティおよび保護されたプロパティを直接読み書きします。非正規化プロセス中のコンストラクターの呼び出しをサポートします。

Objects are normalized to a map of property names to property values.

オブジェクトは、プロパティ名からプロパティ値へのマップに正規化されます。

If you prefer to only normalize certain properties (e.g. only public properties) set the PropertyNormalizer::NORMALIZE_VISIBILITY context option and combine the following values: PropertyNormalizer::NORMALIZE_PUBLIC, PropertyNormalizer::NORMALIZE_PROTECTED or PropertyNormalizer::NORMALIZE_PRIVATE.

特定のプロパティのみを正規化する場合 (たとえば、パブリック プロパティのみ)、PropertyNormalizer::NORMALIZE_VISIBILITY コンテキスト オプションを設定し、次の値を組み合わせます: PropertyNormalizer::NORMALIZE_PUBLIC、PropertyNormalizer::NORMALIZE_PROTECTED または PropertyNormalizer::NORMALIZE_PRIVATE。

6.2

6.2

The PropertyNormalizer::NORMALIZE_VISIBILITY context option and its values were introduced in Symfony 6.2.

PropertyNormalizer::NORMALIZE_VISIBILITY コンテキスト オプションとその値は、Symfony 6.2 で導入されました。
JsonSerializableNormalizer

This normalizer works with classes that implement JsonSerializable.

このノーマライザーは、JsonSerializable を実装するクラスで動作します。

It will call the JsonSerializable::jsonSerialize() method and then further normalize the result. This means that nested JsonSerializable classes will also be normalized.

JsonSerializable::jsonSerialize() メソッドを呼び出し、結果をさらに正規化します。これは、ネストされた JsonSerializable クラスも正規化されることを意味します。

This normalizer is particularly helpful when you want to gradually migrate from an existing codebase using simple json_encode to the Symfony Serializer by allowing you to mix which normalizers are used for which classes.

このノーマライザーは、単純な json_encode を使用する既存のコードベースから SymfonySerializer に徐々に移行したい場合に特に役立ちます。これにより、どのノーマライザーをどのクラスに使用するかを混在させることができます。

Unlike with json_encode circular references can be handled.

json_encode とは異なり、循環参照を処理できます。
DateTimeNormalizer
This normalizer converts DateTimeInterface objects (e.g. DateTime and DateTimeImmutable) into strings. By default, it uses the RFC3339 format.
このノーマライザーは、DateTimeInterface オブジェクト (DateTime や DateTimeImmutable など) を文字列に変換します。デフォルトでは、RFC3339 形式を使用します。
DateTimeZoneNormalizer
This normalizer converts DateTimeZone objects into strings that represent the name of the timezone according to the list of PHP timezones.
このノーマライザーは、DateTimeZone オブジェクトを、PHP タイムゾーンのリストに従ってタイムゾーンの名前を表す文字列に変換します。
DataUriNormalizer
This normalizer converts SplFileInfo objects into a data URI string (data:...) such that files can be embedded into serialized data.
このノーマライザーは、ファイルをシリアル化されたデータに埋め込むことができるように、SplFileInfo オブジェクトをデータ URIstring (data:...) に変換します。
DateIntervalNormalizer
This normalizer converts DateInterval objects into strings. By default, it uses the P%yY%mM%dDT%hH%iM%sS format.
このノーマライザーは、DateInterval オブジェクトを文字列に変換します。既定では、P%yY%mM%dDT%hH%iM%sS 形式を使用します。
BackedEnumNormalizer
This normalizer converts a BackedEnum objects into strings or integers.
このノーマライザーは、BackedEnum オブジェクトを文字列または整数に変換します。
FormErrorNormalizer

This normalizer works with classes that implement FormInterface.

このノーマライザーは、FormInterface を実装するクラスで機能します。

It will get errors from the form and normalize them into a normalized array.

フォームからエラーを取得し、それらを正規化された配列に正規化します。
ConstraintViolationListNormalizer
This normalizer converts objects that implement ConstraintViolationListInterface into a list of errors according to the RFC 7807 standard.
このノーマライザーは、RFC 7807 標準に従って、ConstraintViolationListInterface を実装するオブジェクトをエラーのリストに変換します。
ProblemNormalizer
Normalizes errors according to the API Problem spec RFC 7807.
API 問題の仕様 RFC 7807 に従ってエラーを正規化します。
CustomNormalizer
Normalizes a PHP object using an object that implements NormalizableInterface.
NormalizableInterface を実装するオブジェクトを使用して、PHP オブジェクトを正規化します。
UidNormalizer

This normalizer converts objects that implement AbstractUid into strings. The default normalization format for objects that implement Uuid is the RFC 4122 format (example: d9e7a184-5d5b-11ea-a62a-3499710062d0). The default normalization format for objects that implement Ulid is the Base 32 format (example: 01E439TP9XJZ9RPFH3T1PYBCR8). You can change the string format by setting the serializer context option UidNormalizer::NORMALIZATION_FORMAT_KEY to UidNormalizer::NORMALIZATION_FORMAT_BASE_58, UidNormalizer::NORMALIZATION_FORMAT_BASE_32 or UidNormalizer::NORMALIZATION_FORMAT_RFC_4122.

このノーマライザーは、AbstractUid を実装するオブジェクトを文字列に変換します。Uuid を実装するオブジェクトの既定の正規化形式は、RFC 4122 形式です (例: d9e7a184-5d5b-11ea-a62a-3499710062d0)。Ulid を実装するオブジェクトの既定の正規化形式は、Base 32 形式です (例: 01E439TP9XJZ9RPFH3T1PYBCR8)シリアライザーコンテキストオプションUidNormalizer::NORMALIZATION_FORMAT_KEYをUidNormalizer::NORMALIZATION_FORMAT_BASE_58、UidNormalizer::NORMALIZATION_FORMAT_BASE_32またはUidNormalizer::NORMALIZATION_FORMAT2.RFC4に設定することで、文字列形式を変更できます。

Also it can denormalize uuid or ulid strings to Uuid or Ulid. The format does not matter.

また、uuid または ulid 文字列を Uuidor Ulid に非正規化することもできます。形式は問いません。

Note

ノート

You can also create your own Normalizer to use another structure. Read more at How to Create your Custom Normalizer.

独自のノーマライザーを作成して、別の構造を使用することもできます。詳しくは、カスタム ノーマライザーの作成方法をご覧ください。

Certain normalizers are enabled by default when using the Serializer component in a Symfony application, additional ones can be enabled by tagging them with serializer.normalizer.

Symfony アプリケーションで Serializer コンポーネントを使用すると、特定のノーマライザーがデフォルトで有効になります。追加のノーマライザーは、serializer.normalizer でタグ付けすることで有効にできます。

Here is an example of how to enable the built-in GetSetMethodNormalizer, a faster alternative to the ObjectNormalizer:

以下は、組み込みの GetSetMethodNormalizer を有効にする方法の例で、ObjectNormalizer のより高速な代替手段です。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
# config/services.yaml
services:
    # ...

    get_set_method_normalizer:
        class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
        tags: [serializer.normalizer]

Encoders

Encoders turn arrays into formats and vice versa. They implement EncoderInterface for encoding (array to format) and DecoderInterface for decoding (format to array).

エンコーダーは配列をフォーマットに変換し、その逆も同様です。これらは、エンコード (配列からフォーマット) 用の EncoderInterface と、デコード (フォーマットから配列) 用の DecoderInterface を実装します。

You can add new encoders to a Serializer instance by using its second constructor argument:

2 番目のコンストラクター引数を使用して、Serializer インスタンスに新しいエンコーダーを追加できます。
1
2
3
4
5
6
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Serializer;

$encoders = [new XmlEncoder(), new JsonEncoder()];
$serializer = new Serializer([], $encoders);

Built-in Encoders

The Serializer component provides several built-in encoders:

Serializer コンポーネントには、いくつかの組み込みエンコーダーが用意されています。
JsonEncoder
This class encodes and decodes data in JSON.
このクラスは、JSON でデータをエンコードおよびデコードします。
XmlEncoder
This class encodes and decodes data in XML.
このクラスは、XML のデータをエンコードおよびデコードします。
YamlEncoder
This encoder encodes and decodes data in YAML. This encoder requires the Yaml Component.
このエンコーダーは、YAML でデータをエンコードおよびデコードします。このエンコーダーには、Yaml コンポーネントが必要です。
CsvEncoder
This encoder encodes and decodes data in CSV.
このエンコーダーは、CSV のデータをエンコードおよびデコードします。

Note

ノート

You can also create your own Encoder to use another structure. Read more at How to Create your Custom Encoder.

独自の Encoder を作成して、別の構造を使用することもできます。詳しくはカスタム エンコーダーの作成方法をご覧ください。

All these encoders are enabled by default when using the Serializer component in a Symfony application.

Symfony アプリケーションで Serializer コンポーネントを使用すると、これらのエンコーダーはすべてデフォルトで有効になります。

The JsonEncoder

The JsonEncoder encodes to and decodes from JSON strings, based on the PHP json_encode and json_decode functions. It can be useful to modify how these functions operate in certain instances by providing options such as JSON_PRESERVE_ZERO_FRACTION. You can use the serialization context to pass in these options using the key json_encode_options or json_decode_options respectively:

JsonEncoder は、PHPjson_encode および json_decode 関数に基づいて、JSON 文字列をエンコードおよびデコードします。 JSON_PRESERVE_ZERO_FRACTION などのオプションを指定して、これらの関数が特定のインスタンスでどのように動作するかを変更すると便利です。 serializationcontext を使用して、それぞれキー json_encode_options または json_decode_options を使用してこれらのオプションを渡すことができます。
1
$this->serializer->serialize($data, 'json', ['json_encode_options' => \JSON_PRESERVE_ZERO_FRACTION]);

The CsvEncoder

The CsvEncoder encodes to and decodes from CSV.

CsvEncoder は、CSV へのエンコードと CSV からのデコードを行います。

The CsvEncoder Context Options

The encode() method defines a third optional parameter called context which defines the configuration options for the CsvEncoder an associative array:

encode() メソッドは、連想配列である CsvEncoder の構成オプションを定義する context と呼ばれる 3 番目のオプション パラメータを定義します。
1
$csvEncoder->encode($array, 'csv', $context);

These are the options available:

利用可能なオプションは次のとおりです。
Option Description Default
csv_delimiter Sets the field delimiter separating values (one character only) ,
csv_enclosure Sets the field enclosure (one character only) "
csv_end_of_line Sets the character(s) used to mark the end of each line in the CSV file \n
csv_escape_char Sets the escape character (at most one character) empty string
csv_key_separator Sets the separator for array's keys during its flattening .
csv_headers Sets the order of the header and data columns E.g.: if $data = ['c' => 3, 'a' => 1, 'b' => 2] and $options = ['csv_headers' => ['a', 'b', 'c']] then serialize($data, 'csv', $options) returns a,b,c\n1,2,3 [], inferred from input data's keys
csv_escape_formulas Escapes fields containing formulas by prepending them with a \t character false
as_collection Always returns results as a collection, even if only one line is decoded. true
no_headers Disables header in the encoded CSV false
output_utf8_bom Outputs special UTF-8 BOM along with encoded data false

The XmlEncoder

This encoder transforms arrays into XML and vice versa.

このエンコーダーは、配列を XML に、またはその逆に変換します。

For example, take an object normalized as following:

たとえば、次のように正規化されたオブジェクトを使用します。
1
['foo' => [1, 2], 'bar' => true];

The XmlEncoder will encode this object like that:

XmlEncoder は、このオブジェクトを次のようにエンコードします。
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" ?>
<response>
    <foo>1</foo>
    <foo>2</foo>
    <bar>1</bar>
</response>

The special # key can be used to define the data of a node:

特殊な # キーを使用して、ノードのデータを定義できます。
1
2
3
4
5
6
7
8
9
['foo' => ['@bar' => 'value', '#' => 'baz']];

// is encoded as follows:
// <?xml version="1.0"?>
// <response>
//     <foo bar="value">
//        baz
//     </foo>
// </response>

Furthermore, keys beginning with @ will be considered attributes, and the key #comment can be used for encoding XML comments:

さらに、@ で始まるキーは属性と見なされ、key#comment を使用して XML コメントをエンコードできます。
1
2
3
4
5
6
7
8
9
10
11
$encoder = new XmlEncoder();
$encoder->encode([
    'foo' => ['@bar' => 'value'],
    'qux' => ['#comment' => 'A comment'],
], 'xml');
// will return:
// <?xml version="1.0"?>
// <response>
//     <foo bar="value"/>
//     <qux><!-- A comment --!><qux>
// </response>

You can pass the context key as_collection in order to have the results always as a collection.

結果を常にコレクションとして保持するために、コンテキスト キー as_collection を渡すことができます。

Tip

ヒント

XML comments are ignored by default when decoding contents, but this behavior can be changed with the optional context key XmlEncoder::DECODER_IGNORED_NODE_TYPES.

XML コメントはコンテンツのデコード時にデフォルトで無視されますが、この動作はオプションのコンテキスト キー XmlEncoder::DECODER_IGNORED_NODE_TYPES で変更できます。

Data with #comment keys are encoded to XML comments by default. This can be changed by adding the \XML_COMMENT_NODE option to the XmlEncoder::ENCODER_IGNORED_NODE_TYPES key of the $defaultContext of the XmlEncoder constructor or directly to the $context argument of the encode() method:

#comment キーを持つデータは、デフォルトで XML コメントにエンコードされます。これは、XmlEncoder コンストラクターの $defaultContext の XmlEncoder::ENCODER_IGNORED_NODE_TYPESkey に \XML_COMMENT_NODE オプションを追加するか、encode() メソッドの $context 引数に直接追加することで変更できます。
1
$xmlEncoder->encode($array, 'xml', [XmlEncoder::ENCODER_IGNORED_NODE_TYPES => [\XML_COMMENT_NODE]]);

The XmlEncoder Context Options

The encode() method defines a third optional parameter called context which defines the configuration options for the XmlEncoder an associative array:

encode() メソッドは、 XmlEncoder 連想配列の構成オプションを定義する context と呼ばれる 3 番目のオプション パラメータを定義します。
1
$xmlEncoder->encode($array, 'xml', $context);

These are the options available:

利用可能なオプションは次のとおりです。
Option Description Default
xml_format_output If set to true, formats the generated XML with line breaks and indentation false
xml_version Sets the XML version attribute 1.1
xml_encoding Sets the XML encoding attribute utf-8
xml_standalone Adds standalone attribute in the generated XML true
xml_type_cast_attributes This provides the ability to forget the attribute type casting true
xml_root_node_name Sets the root node name response
as_collection Always returns results as a collection, even if only one line is decoded false
decoder_ignored_node_types Array of node types (DOM XML_* constants) to be ignored while decoding [\XML_PI_NODE, \XML_COMMENT_NODE]
encoder_ignored_node_types Array of node types (DOM XML_* constants) to be ignored while encoding []
load_options XML loading options with libxml \LIBXML_NONET | \LIBXML_NOBLANKS
remove_empty_tags If set to true, removes all empty tags in the generated XML false

Example with custom context:

カスタム コンテキストの例:
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
27
28
29
30
31
use Symfony\Component\Serializer\Encoder\XmlEncoder;

// create encoder with specified options as new default settings
$xmlEncoder = new XmlEncoder(['xml_format_output' => true]);

$data = [
    'id' => 'IDHNQIItNyQ',
    'date' => '2019-10-24',
];

// encode with default context
$xmlEncoder->encode($data, 'xml');
// outputs:
// <?xml version="1.0"?>
// <response>
//   <id>IDHNQIItNyQ</id>
//   <date>2019-10-24</date>
// </response>

// encode with modified context
$xmlEncoder->encode($data, 'xml', [
    'xml_root_node_name' => 'track',
    'encoder_ignored_node_types' => [
        \XML_PI_NODE, // removes XML declaration (the leading xml tag)
    ],
]);
// outputs:
// <track>
//   <id>IDHNQIItNyQ</id>
//   <date>2019-10-24</date>
// </track>

The YamlEncoder

This encoder requires the Yaml Component and transforms from and to Yaml.

このエンコーダーには、Yaml コンポーネントが必要であり、Yaml との間で変換されます。

The YamlEncoder Context Options

The encode() method, like other encoder, uses context to set configuration options for the YamlEncoder an associative array:

encode() メソッドは、他のエンコーダーと同様に、コンテキストを使用して YamlEncoder の構成オプションを連想配列に設定します。
1
$yamlEncoder->encode($array, 'yaml', $context);

These are the options available:

利用可能なオプションは次のとおりです。
Option Description Default
yaml_inline The level where you switch to inline YAML 0
yaml_indent The level of indentation (used internally) 0
yaml_flags A bit field of Yaml::DUMP_* / PARSE_* constants to customize the encoding / decoding YAML string 0

Context Builders

Instead of passing plain PHP arrays to the serialization context, you can use "context builders" to define the context using a fluent interface:

単純な PHP 配列をシリアライゼーション コンテキストに渡す代わりに、「コンテキスト ビルダー」を使用して流暢なインターフェイスを使用してコンテキストを定義できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder;
use Symfony\Component\Serializer\Context\Normalizer\ObjectNormalizerContextBuilder;

$initialContext = [
    'custom_key' => 'custom_value',
];

$contextBuilder = (new ObjectNormalizerContextBuilder())
    ->withContext($initialContext)
    ->withGroups(['group1', 'group2']);

$contextBuilder = (new CsvEncoderContextBuilder())
    ->withContext($contextBuilder)
    ->withDelimiter(';');

$serializer->serialize($something, 'csv', $contextBuilder->toArray());

6.1

6.1

Context builders were introduced in Symfony 6.1.

コンテキストビルダーは Symfony 6.1 で導入されました。

Note

ノート

The Serializer component provides a context builder for each normalizer and encoder.

Serializer コンポーネントは、各ノーマライザーとエンコーダーのコンテキスト ビルダーを提供します。

You can also create custom context builders to deal with your context values.

コンテキスト値を処理するカスタム コンテキスト ビルダーを作成することもできます。

Skipping null Values

By default, the Serializer will preserve properties containing a null value. You can change this behavior by setting the AbstractObjectNormalizer::SKIP_NULL_VALUES context option to true:

デフォルトでは、Serializer は null 値を含むプロパティを保持します。AbstractObjectNormalizer::SKIP_NULL_VALUES コンテキスト オプションを true に設定することで、この動作を変更できます。
1
2
3
4
5
6
7
8
$dummy = new class {
    public $foo;
    public $bar = 'notNull';
};

$normalizer = new ObjectNormalizer();
$result = $normalizer->normalize($dummy, 'json', [AbstractObjectNormalizer::SKIP_NULL_VALUES => true]);
// ['bar' => 'notNull']

Skipping Uninitialized Properties

In PHP, typed properties have an uninitialized state which is different from the default null of untyped properties. When you try to access a typed property before giving it an explicit value, you get an error.

PHP では、型指定されたプロパティには、型指定されていないプロパティのデフォルトの null とは異なる初期化されていない状態があります。明示的な値を与える前に typedproperty にアクセスしようとすると、エラーが発生します。

To avoid the Serializer throwing an error when serializing or normalizing an object with uninitialized properties, by default the object normalizer catches these errors and ignores such properties.

初期化されていないプロパティを持つオブジェクトをシリアル化または正規化するときにシリアライザーがエラーをスローするのを避けるために、既定では、オブジェクト ノーマライザーはこれらのエラーをキャッチし、そのようなプロパティを無視します。

You can disable this behavior by setting the AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES context option to false:

この動作を無効にするには、AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUEScontext オプションを false に設定します。
1
2
3
4
5
6
7
8
class Dummy {
    public string $foo = 'initialized';
    public string $bar; // uninitialized
}

$normalizer = new ObjectNormalizer();
$result = $normalizer->normalize(new Dummy(), 'json', [AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES => false]);
// throws Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException as normalizer cannot read uninitialized properties

Note

ノート

Calling PropertyNormalizer::normalize or GetSetMethodNormalizer::normalize with AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES context option set to false will throw an \Error instance if the given object has uninitialized properties as the normalizer cannot read them (directly or via getter/isser methods).

PropertyNormalizer::normalize または GetSetMethodNormalizer::normalize with AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES コンテキスト オプションを false に設定して呼び出すと、指定されたオブジェクトに初期化されていないプロパティがある場合、ノーマライザーが (直接または getter/isser メソッドを介して) 読み取ることができないため、\Error インスタンスがスローされます。

Collecting Type Errors While Denormalizing

When denormalizing a payload to an object with typed properties, you'll get an exception if the payload contains properties that don't have the same type as the object.

ペイロードを型指定されたプロパティを持つオブジェクトに非正規化する場合、オブジェクトと同じ型を持たないプロパティがペイロードに含まれていると、例外が発生します。

In those situations, use the COLLECT_DENORMALIZATION_ERRORS option to collect all exceptions at once, and to get the object partially denormalized:

このような状況では、COLLECT_DENORMALIZATION_ERRORS オプションを使用してすべての例外を一度に収集し、オブジェクトを部分的に非正規化します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
try {
    $dto = $serializer->deserialize($request->getContent(), MyDto::class, 'json', [
        DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
    ]);
} catch (PartialDenormalizationException $e) {
    $violations = new ConstraintViolationList();
    /** @var NotNormalizableValueException $exception */
    foreach ($e->getErrors() as $exception) {
        $message = sprintf('The type must be one of "%s" ("%s" given).', implode(', ', $exception->getExpectedTypes()), $exception->getCurrentType());
        $parameters = [];
        if ($exception->canUseMessageForUser()) {
            $parameters['hint'] = $exception->getMessage();
        }
        $violations->add(new ConstraintViolation($message, '', $parameters, null, $exception->getPath(), null));
    }

    return $this->json($violations, 400);
}

Handling Circular References

Circular references are common when dealing with entity relations:

エンティティ関係を扱う場合、循環参照は一般的です。
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Organization
{
    private $name;
    private $members;

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setMembers(array $members)
    {
        $this->members = $members;
    }

    public function getMembers()
    {
        return $this->members;
    }
}

class Member
{
    private $name;
    private $organization;

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setOrganization(Organization $organization)
    {
        $this->organization = $organization;
    }

    public function getOrganization()
    {
        return $this->organization;
    }
}

To avoid infinite loops, GetSetMethodNormalizer or ObjectNormalizer throw a CircularReferenceException when such a case is encountered:

無限ループを回避するために、GetSetMethodNormalizer または ObjectNormalizer は、次のような場合に CircularReferenceException をスローします。
1
2
3
4
5
6
7
8
9
10
$member = new Member();
$member->setName('Kévin');

$organization = new Organization();
$organization->setName('Les-Tilleuls.coop');
$organization->setMembers([$member]);

$member->setOrganization($organization);

echo $serializer->serialize($organization, 'json'); // Throws a CircularReferenceException

The key circular_reference_limit in the default context sets the number of times it will serialize the same object before considering it a circular reference. The default value is 1.

デフォルト コンテキストのキー circle_reference_limit は、同じオブジェクトを循環参照と見なす前にシリアル化する回数を設定します。デフォルト値は 1 です。

Instead of throwing an exception, circular references can also be handled by custom callables. This is especially useful when serializing entities having unique identifiers:

例外をスローする代わりに、カスタム callable で循環参照を処理することもできます。これは、一意の識別子を持つエンティティをシリアル化するときに特に役立ちます。
1
2
3
4
5
6
7
8
9
10
11
$encoder = new JsonEncoder();
$defaultContext = [
    AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object, $format, $context) {
        return $object->getName();
    },
];
$normalizer = new ObjectNormalizer(null, null, null, null, null, null, $defaultContext);

$serializer = new Serializer([$normalizer], [$encoder]);
var_dump($serializer->serialize($org, 'json'));
// {"name":"Les-Tilleuls.coop","members":[{"name":"K\u00e9vin", organization: "Les-Tilleuls.coop"}]}

Handling Serialization Depth

The Serializer component is able to detect and limit the serialization depth. It is especially useful when serializing large trees. Assume the following data structure:

Serializer コンポーネントは、シリアライゼーションの深さを検出して制限することができます。これは、大きなツリーをシリアライズする場合に特に役立ちます。次のデータ構造を想定します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace Acme;

class MyObj
{
    public $foo;

    /**
     * @var self
     */
    public $child;
}

$level1 = new MyObj();
$level1->foo = 'level1';

$level2 = new MyObj();
$level2->foo = 'level2';
$level1->child = $level2;

$level3 = new MyObj();
$level3->foo = 'level3';
$level2->child = $level3;

The serializer can be configured to set a maximum depth for a given property. Here, we set it to 2 for the $child property:

シリアライザーは、特定のプロパティの最大深度を設定するように構成できます。ここでは、$child プロパティの最大深度を 2 に設定します。
  • Attributes
    属性
  • YAML
    YAML
  • XML
    XML
1
2
3
4
5
6
7
8
9
10
11
namespace Acme;

use Symfony\Component\Serializer\Annotation\MaxDepth;

class MyObj
{
    #[MaxDepth(2)]
    public $child;

    // ...
}

The metadata loader corresponding to the chosen format must be configured in order to use this feature. It is done automatically when using the Serializer component in a Symfony application. When using the standalone component, refer to the groups documentation to learn how to do that.

この機能を使用するには、選択した形式に対応するメタデータ ローダーを構成する必要があります。 Symfony アプリケーションで Serializer コンポーネントを使用すると、自動的に行われます。スタンドアロン コンポーネントを使用する場合は、その方法についてグループのドキュメントを参照してください。

The check is only done if the AbstractObjectNormalizer::ENABLE_MAX_DEPTH key of the serializer context is set to true. In the following example, the third level is not serialized because it is deeper than the configured maximum depth of 2:

このチェックは、シリアライザー コンテキストの AbstractObjectNormalizer::ENABLE_MAX_DEPTH キーが true に設定されている場合にのみ行われます。次の例では、3 番目のレベルは構成された最大深度 2 よりも深いため、シリアライズされません。
1
2
3
4
5
6
7
8
9
10
11
12
$result = $serializer->normalize($level1, null, [AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true]);
/*
$result = [
    'foo' => 'level1',
    'child' => [
        'foo' => 'level2',
        'child' => [
            'child' => null,
        ],
    ],
];
*/

Instead of throwing an exception, a custom callable can be executed when the maximum depth is reached. This is especially useful when serializing entities having unique identifiers:

例外をスローする代わりに、最大深度に達したときにカスタム呼び出し可能オブジェクトを実行できます。これは、一意の識別子を持つエンティティをシリアル化するときに特に役立ちます。
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Serializer\Annotation\MaxDepth;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

class Foo
{
    public $id;

    #[MaxDepth(1)]
    public $child;
}

$level1 = new Foo();
$level1->id = 1;

$level2 = new Foo();
$level2->id = 2;
$level1->child = $level2;

$level3 = new Foo();
$level3->id = 3;
$level2->child = $level3;

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

// all callback parameters are optional (you can omit the ones you don't use)
$maxDepthHandler = function ($innerObject, $outerObject, string $attributeName, string $format = null, array $context = []) {
    return '/foos/'.$innerObject->id;
};

$defaultContext = [
    AbstractObjectNormalizer::MAX_DEPTH_HANDLER => $maxDepthHandler,
];
$normalizer = new ObjectNormalizer($classMetadataFactory, null, null, null, null, null, $defaultContext);

$serializer = new Serializer([$normalizer]);

$result = $serializer->normalize($level1, null, [AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true]);
/*
$result = [
    'id' => 1,
    'child' => [
        'id' => 2,
        'child' => '/foos/3',
    ],
];
*/

Handling Arrays

The Serializer component is capable of handling arrays of objects as well. Serializing arrays works just like serializing a single object:

Serializer コンポーネントは、オブジェクトの配列も処理できます。配列のシリアル化は、単一のオブジェクトのシリアル化と同じように機能します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Acme\Person;

$person1 = new Person();
$person1->setName('foo');
$person1->setAge(99);
$person1->setSportsman(false);

$person2 = new Person();
$person2->setName('bar');
$person2->setAge(33);
$person2->setSportsman(true);

$persons = [$person1, $person2];
$data = $serializer->serialize($persons, 'json');

// $data contains [{"name":"foo","age":99,"sportsman":false},{"name":"bar","age":33,"sportsman":true}]

If you want to deserialize such a structure, you need to add the ArrayDenormalizer to the set of normalizers. By appending [] to the type parameter of the deserialize() method, you indicate that you're expecting an array instead of a single object:

このような構造をデシリアライズする場合は、ArrayDenormalizer をノーマライザーのセットに追加する必要があります。 [] を deserialize() メソッドの型パラメーターに追加することで、単一のオブジェクトではなく配列を期待していることを示します。
1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Serializer;

$serializer = new Serializer(
    [new GetSetMethodNormalizer(), new ArrayDenormalizer()],
    [new JsonEncoder()]
);

$data = ...; // The serialized data from the previous example
$persons = $serializer->deserialize($data, 'Acme\Person[]', 'json');

Handling Constructor Arguments

If the class constructor defines arguments, as usually happens with Value Objects, the serializer won't be able to create the object if some arguments are missing. In those cases, use the default_constructor_arguments context option:

値オブジェクトで通常発生するように、クラス コンストラクターが引数を定義する場合、いくつかの引数が欠落していると、シリアライザーはオブジェクトを作成できません。そのような場合は、default_constructor_argumentscontext オプションを使用します。
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
27
28
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

class MyObj
{
    private $foo;
    private $bar;

    public function __construct($foo, $bar)
    {
        $this->foo = $foo;
        $this->bar = $bar;
    }
}

$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

$data = $serializer->denormalize(
    ['foo' => 'Hello'],
    'MyObj',
    null,
    [AbstractNormalizer::DEFAULT_CONSTRUCTOR_ARGUMENTS => [
        'MyObj' => ['foo' => '', 'bar' => ''],
    ]]
);
// $data = new MyObj('Hello', '');

Recursive Denormalization and Type Safety

The Serializer component can use the PropertyInfo Component to denormalize complex types (objects). The type of the class' property will be guessed using the provided extractor and used to recursively denormalize the inner data.

Serializer コンポーネントは、PropertyInfo コンポーネントを使用して、複合型 (オブジェクト) を非正規化できます。クラスのプロパティの型は、提供されたextractorを使用して推測され、内部データを再帰的に非正規化するために使用されます。

When using this component in a Symfony application, all normalizers are automatically configured to use the registered extractors. When using the component standalone, an implementation of PropertyTypeExtractorInterface, (usually an instance of PropertyInfoExtractor) must be passed as the 4th parameter of the ObjectNormalizer:

このコンポーネントを Symfony アプリケーションで使用する場合、すべてのノーマライザーは登録済みのエクストラクタを使用するように自動的に構成されます。コンポーネントをスタンドアロンで使用する場合、PropertyTypeExtractorInterface の実装 (通常は PropertyInfoExtractor のインスタンス) を ObjectNormalizer の 4 番目のパラメータとして渡す必要があります。
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
namespace Acme;

use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

class ObjectOuter
{
    private $inner;
    private $date;

    public function getInner()
    {
        return $this->inner;
    }

    public function setInner(ObjectInner $inner)
    {
        $this->inner = $inner;
    }

    public function setDate(\DateTimeInterface $date)
    {
        $this->date = $date;
    }

    public function getDate()
    {
        return $this->date;
    }
}

class ObjectInner
{
    public $foo;
    public $bar;
}

$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());
$serializer = new Serializer([new DateTimeNormalizer(), $normalizer]);

$obj = $serializer->denormalize(
    ['inner' => ['foo' => 'foo', 'bar' => 'bar'], 'date' => '1988/01/21'],
    'Acme\ObjectOuter'
);

dump($obj->getInner()->foo); // 'foo'
dump($obj->getInner()->bar); // 'bar'
dump($obj->getDate()->format('Y-m-d')); // '1988-01-21'

When a PropertyTypeExtractor is available, the normalizer will also check that the data to denormalize matches the type of the property (even for primitive types). For instance, if a string is provided, but the type of the property is int, an UnexpectedValueException will be thrown. The type enforcement of the properties can be disabled by setting the serializer context option ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT to true.

PropertyTypeExtractor が使用可能な場合、ノーマライザーは、非正規化するデータがプロパティの型と一致することも確認します (プリミティブ型であっても)。たとえば、文字列が指定されているが、プロパティの型が int の場合、UnexpectedValueException がスローされます。プロパティの型強制は、シリアライザー コンテキスト オプション ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT を true に設定することで無効にできます。

Serializing Interfaces and Abstract Classes

When dealing with objects that are fairly similar or share properties, you may use interfaces or abstract classes. The Serializer component allows you to serialize and deserialize these objects using a "discriminator class mapping".

よく似たオブジェクトやプロパティを共有するオブジェクトを扱う場合は、インターフェイスまたは抽象クラスを使用できます。 Serializer コンポーネントを使用すると、「ディスクリミネーター クラス マッピング」を使用してこれらのオブジェクトをシリアル化および逆シリアル化できます。

The discriminator is the field (in the serialized string) used to differentiate between the possible objects. In practice, when using the Serializer component, pass a ClassDiscriminatorResolverInterface implementation to the ObjectNormalizer.

ディスクリミネーターは、可能なオブジェクトを区別するために使用される (シリアル化された文字列内の) フィールドです。実際には、Serializer コンポーネントを使用する場合、ClassDiscriminatorResolverInterface 実装を ObjectNormalizer に渡します。

The Serializer component provides an implementation of ClassDiscriminatorResolverInterface called ClassDiscriminatorFromClassMetadata which uses the class metadata factory and a mapping configuration to serialize and deserialize objects of the correct class.

Serializer コンポーネントは、ClassDiscriminatorFromClassMetadata と呼ばれる ClassDiscriminatorResolverInterface の実装を提供します。これは、クラス メタデータ ファクトリとマッピング構成を使用して、正しいクラスのオブジェクトをシリアル化および逆シリアル化します。

When using this component inside a Symfony application and the class metadata factory is enabled as explained in the Attributes Groups section, this is already set up and you only need to provide the configuration. Otherwise:

このコンポーネントを Symfony アプリケーション内で使用し、属性グループ セクションで説明されているようにクラス メタデータ ファクトリが有効になっている場合、これは既に設定されており、構成を提供するだけで済みます。さもないと:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

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

$discriminator = new ClassDiscriminatorFromClassMetadata($classMetadataFactory);

$serializer = new Serializer(
    [new ObjectNormalizer($classMetadataFactory, null, null, null, $discriminator)],
    ['json' => new JsonEncoder()]
);

Now configure your discriminator class mapping. Consider an application that defines an abstract CodeRepository class extended by GitHubCodeRepository and BitBucketCodeRepository classes:

ここで、識別子クラス マッピングを構成します。 GitHubCodeRepository および BitBucketCodeRepository クラスによって拡張された抽象 CodeRepository クラスを定義するアプリケーションを考えてみましょう。
  • Attributes
    属性
  • YAML
    YAML
  • XML
    XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace App;

use App\BitBucketCodeRepository;
use App\GitHubCodeRepository;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;

#[DiscriminatorMap(typeProperty: 'type', mapping: [
    'github' => GitHubCodeRepository::class,
    'bitbucket' => BitBucketCodeRepository::class,
])]
abstract class CodeRepository
{
    // ...
}

Once configured, the serializer uses the mapping to pick the correct class:

構成が完了すると、シリアライザーはマッピングを使用して正しいクラスを選択します。
1
2
3
4
5
$serialized = $serializer->serialize(new GitHubCodeRepository(), 'json');
// {"type": "github"}

$repository = $serializer->deserialize($serialized, CodeRepository::class, 'json');
// instanceof GitHubCodeRepository

Learn more

See also

こちらもご覧ください

Normalizers for the Symfony Serializer Component supporting popular web API formats (JSON-LD, GraphQL, OpenAPI, HAL, JSON:API) are available as part of the API Platform project.

一般的な Web API 形式 (JSON-LD、GraphQL、OpenAPI、HAL、JSON:API) をサポートする Symfony シリアライザー コンポーネントのノーマライザーは、API プラットフォーム プロジェクトの一部として利用できます。

See also

こちらもご覧ください

A popular alternative to the Symfony Serializer component is the third-party library, JMS serializer (versions before v1.12.0 were released under the Apache license, so incompatible with GPLv2 projects).

Symfony シリアライザー コンポーネントに代わる一般的なものは、サードパーティ製ライブラリである JMS シリアライザーです (v1.12.0 より前のバージョンは Apache ライセンスの下でリリースされたため、GPLv2 プロジェクトとは互換性がありません)。