Как использовать Serializer

Дата обновления перевода 2024-08-01

Как использовать Serializer

Symfony предоставляет Serializer для сериализации/десериализации в и из объектов и разных форматов (например, JSON или XML). До его использования, прочтите документы компонента Serializer, который предоставляет вам некоторые инструменты, которые вы можете использовать для решения ваших задач.

Установка

В приложениях, использующих Symfony Flex , выполните эту команду, чтобы установить пакет Symfony serializer перед его использованием:

1
$ composer require symfony/serializer-pack

Использование сервиса Serializer

После подключения, сервис сериализатора может быть внедрен в любой сервис, где вам это нужно, или он может быть использован в контроллере:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Controller/DefaultController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\SerializerInterface;

class DefaultController extends AbstractController
{
    public function index(SerializerInterface $serializer): Response
    {
        // продолжайте читать для примеров использования
    }
}

Или вы можете использовать фильтр Twig serialize в шаблоне:

1
{{ object|serialize(format = 'json') }}

См. справочник twig, чтобы узнать больше информации.

Добавление нормализаторов и кодировшиков

После подключения, сервис serializer будет доступен в контейнере. Он поставляется с набором полезных кодировщиков и нормализаторов .

Включены кодировщики, поддерживающие следующие форматы:

А также следующие нормализаторы:

Другие встроенные нормализаторы и пользовательские нормализаторы и/или кодировщики также могут быть загружены, путем тегирования их как serializer.normalizer и serializer.encoder . Также возможно установить приоритет тега, чтобы опрределить порядок сопоставления.

Danger

Не забывайте загружать DateTimeNormalizer при сериализации классов DateTime или DateTimeImmutable для избежания излишнего использования памяти и оголения внутренних деталей.

Контекст сериализатора

Сериализатор может определять контекст для контроля (де)сериализацию источников. Этот контекст передается всем нормализаторам. К примеру:

  • DateTimeNormalizer использует ключ datetime_format в формате даты и времени;
  • AbstractObjectNormalizer использует empty_iterable_as_object, чтобы представлять пустые объекты как {} вместо [] в JSON.
  • Serializer использует empty_array_as_object для представления пустых массивов как {} вместо [] в JSON.

Вы можете передать контекст следующим образом:

1
2
3
4
5
6
7
$serializer->serialize($something, 'json', [
    DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i:s',
]);

$serializer->deserialize($someJson, Something::class, 'json', [
    DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i:s',
]);

Вы также можете сконфигурироовать контекст по умолчанию через конфигурацию фреймворка:

1
2
3
4
5
6
7
# config/packages/framework.yaml
framework:
    # ...
    serializer:
        default_context:
            enable_max_depth: true
            yaml_indentation: 2

Вы также можете указать контекст в зависимости от свойства:

1
2
3
4
5
6
7
8
9
10
11
12
namespace App\Model;

use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

class Person
{
    #[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
    public \DateTimeInterface $createdAt;

    // ...
}

Use the options to specify context specific to normalization or denormalization:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace App\Model;

use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

class Person
{
    #[Context(
        normalizationContext: [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'],
        denormalizationContext: [DateTimeNormalizer::FORMAT_KEY => '!Y-m-d'], // To prevent to have the time from the moment of denormalization
    )]
    public \DateTimeInterface $createdAt;

    // ...
}

Вы также можете ограничить использование контекста по каким-то группам:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace App\Model;

use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

class Person
{
    #[Groups(['extended'])]
    #[Context([DateTimeNormalizer::FORMAT_KEY => \DateTime::RFC3339])]
    #[Context(
        context: [DateTimeNormalizer::FORMAT_KEY => \DateTime::RFC3339_EXTENDED],
        groups: ['extended'],
    )]
    public \DateTimeInterface $createdAt;

    // ...
}

Атрибут может повторяться необходимое количество раз в одном свойстве. Контекст без группы всегда применяется первым. Затем, контекст для совпадающих групп слияется в предоставленном порядке.

Если вы повторяете один и тот же контекст в нескольких свойствах, подумайте об использовании атрибута #[Context] в вашем классе, чтобы применить конфигурацию контекста ко всем свойствам класса:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace App\Model;

use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

#[Context([DateTimeNormalizer::FORMAT_KEY => \DateTime::RFC3339])]
#[Context(
    context: [DateTimeNormalizer::FORMAT_KEY => \DateTime::RFC3339_EXTENDED],
    groups: ['extended'],
)]
class Person
{
    // ...
}

Использование конструкторов контекста

Чтобы определить контекст (де)сериализации, вы можете использовать "конструкторы контекста", которые являются объектами, помогающими вам создавать этот контекст, предоставляя автозаполнение, валидацию и документацию:

1
2
3
4
use Symfony\Component\Serializer\Context\Normalizer\DateTimeNormalizerContextBuilder;

$contextBuilder = (new DateTimeNormalizerContextBuilder())->withFormat('Y-m-d H:i:s');
$serializer->serialize($something, 'json', $contextBuilder->toArray());

Каждый нормализатор/кодировщик имеет связанный с ним конструктор контекста . Чтобы создать более сложный контекст (де)сериализации, вы можете цепочку, используя метод withContext():

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());

Вы также можете создавать собственные конструкторы контекста, чтобы иметь автозаполнение, валидацию и документацию для ваших пользовательских значений контекста.

Использование атрибутов групповой сериализации

Вы можете добавить атрибуты #[Groups] к вашему классу:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/Entity/Product.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

#[ORM\Entity]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    #[Groups(['show_product', 'list_product'])]
    private int $id;

    #[ORM\Column(type: 'string', length: 255)]
    #[Groups(['show_product', 'list_product'])]
    private string $name;

    #[ORM\Column(type: 'text')]
    #[Groups(['show_product'])]
    private string $description;
}

You can also use the #[Groups] attribute on class level:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#[ORM\Entity]
#[Groups(['show_product'])]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    #[Groups(['list_product'])]
    private int $id;

    #[ORM\Column(type: 'string', length: 255)]
    #[Groups(['list_product'])]
    private string $name;

    #[ORM\Column(type: 'text')]
    private string $description;
}

В этом примере свойства id и name принадлежат к группам show_product и list_product. Свойство description принадлежит только к группе show_product.

Теперь, когда группы определены, вы можете выбрать, какие группы использовать при сериализации:

1
2
3
4
5
6
7
use Symfony\Component\Serializer\Context\Normalizer\ObjectNormalizerContextBuilder;

$context = (new ObjectNormalizerContextBuilder())
    ->withGroups('show_product')
    ->toArray();

$json = $serializer->serialize($product, 'json', $context);

Tip

Значение ключа groups может быть одной строкой или их массивом.

В дополенение к атрибуту #[Groups], компонент Serializer также поддерживает файлы YAML или XML. Эти файлы автоматически загружаются при сохранении в одной из следующих локаций:

  • Все файлы *.yaml и *.xml в каталоге config/serializer/.
  • Файл serialization.yaml или serialization.xml в каталоге пакета Resources/config/;
  • Все файлы *.yaml и *.xml в каталоге пакета Resources/config/serialization/.

Note

По умолчанию при нормализации и денормализации объектов используются группы
Default и группа, соответствующая имени класса. Например, если вы нормализуете объект App\Entity\Product, то будут использоваться группы Default и Product.

7.1

Использование имени класса и группы Default по умолчанию при нормализации
и денормализации объектов было представлено в Symfony 7.1.

Использование вложенных атрибутов

Чтобы отобразить вложенные свойства, используйте конфигурацию SerializedPath, чтобы определить их пути, используя валидный синтаксис PropertyAccess:

1
2
3
4
5
6
7
8
9
10
11
namespace App\Model;

use Symfony\Component\Serializer\Annotation\SerializedPath;

class Person
{
    #[SerializedPath('[profile][information][birthday]')]
    private string $birthday;

    // ...
}

Используя конфигурацию выше, денормализация с нормализатором, знающим о метаданных, впишет поле birthday из $data в объект Person:

1
2
3
4
5
6
7
8
9
$data = [
    'profile' => [
        'information' => [
            'birthday' => '01-01-1970',
        ],
    ],
];
$person = $normalizer->denormalize($data, Person::class, 'any');
$person->getBirthday(); // 01-01-1970

При использовании аннотаций или атрибутов, SerializedPath может либо быть установлен в свойстве, либо в ассоциированном методе _getter_. SerializedPath не может быть использован в комбинации с SerializedName для одного свойства.

Конфигурация кеша метаданных

Метаданные для сериализатора автоматически кешируются для улучшения работы приложения. По умолчанию, сериализатор использует пул кеша cache.system, который конфигурируется с использованием опции cache.system .

Подключения конвертера имен

Использование сервиса конвертера имен может быть определено в конфигурации с использованием опции name_converter .

Встроенный конвертер имен CamelCase в snake_case может быть подключен, используя значение serializer.name_converter.camel_case_to_snake_case:

1
2
3
4
5
# config/packages/framework.yaml
framework:
    # ...
    serializer:
        name_converter: 'serializer.name_converter.camel_case_to_snake_case'

Отладка Serializer

Используйте команду debug:serializer, чтобы сбросить метаданные сериализатора
заданного класса:

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
$ php bin/console debug:serializer 'App\Entity\Book'

    App\Entity\Book
    ---------------

    +----------+------------------------------------------------------------+
    | Свойство | Опции                                                    |
    +----------+------------------------------------------------------------+
    | name     | [                                                          |
    |          |   "groups" => [                                            |
    |          |       "book:read",                                         |
    |          |       "book:write",                                        |
    |          |   ],                                                       |
    |          |   "maxDepth" => 1,                                         |
    |          |   "serializedName" => "book_name",                         |
    |          |   "serializedPath" => null,                                |
    |          |   "ignore" => false,                                       |
    |          |   "normalizationContexts" => [],                           |
    |          |   "denormalizationContexts" => []                          |
    |          | ]                                                          |
    | isbn     | [                                                          |
    |          |   "groups" => [                                            |
    |          |       "book:read",                                         |
    |          |   ],                                                       |
    |          |   "maxDepth" => null,                                      |
    |          |   "serializedName" => null,                                |
    |          |   "serializedPath" => [data][isbn],                        |
    |          |   "ignore" => false,                                       |
    |          |   "normalizationContexts" => [],                           |
    |          |   "denormalizationContexts" => []                          |
    |          | ]                                                          |
    +----------+------------------------------------------------------------+

Углублённое использование Serializer

Платформа API предоставляет API-систему, поддерживающую следующие форматы:

Она встроена над фреймворком Symfony и ее компонентом Serializer. Она предоставляет пользовательские нормализаторы и кодировщики, пользовательсские метаданные и систему кеширования.

Если вы хотите воспользоваться преимуществами полной мощи компонента Symfony Serializer, посмотрите на то, как работает этот пакет.