Дата обновления перевода: 2021-05-13

Компонент Serializer

Компонент Serializer предназначается для того, чтобы превращать объекты в определённый формат (XML, JSON, YAML, …) и наоборот.

Для того, чтобы сделать это, компонент Serializer следует такой простой схеме.

Как вы можете увидеть на изображении выше, массив используются в качестве посредника между объектами и сериализованным содержанием. Таким образом, кодировщики (Encoders) будут работать только с превращением конкретных форматов в массивы и наоборот. Таким же образом, нормализаторы (Normalizers) будут работать с превращением определённых объектов в массивы и наоборот.

Сериализация - это сложная тема. Этот компонент может не охватить все ваши случаи применения, но может быть полезным для разработки инструментов для сериализации и десериализации ваших объектов.

Установка

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.

Для использования ObjectNormalizer, должен быть также установлен компонент PropertyAccess.

Применение

See also

Эта статья объясняет как использовать функции Serializer и знакомит вас с концепциями нормализаторв и шифровщиков. Примеры кода предполагают, что вы используете Serializer как независимый компонент. Если вы используете Serializer в приложении Symfony, прочтите How to Use the Serializer после того, как закончите эту статью.

Использовать компонент Сериализация очень просто. Вам просто нужно установить Serializer, указывая, какие кодировщики и нормализатор будут доступны:

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

Предпочитаемый нормализатор - ObjectNormalizer, но другие нормализаторы также доступны. Все примеры, показанные ниже, используют ObjectNormalizer.

Сериализация объекта

Ради этого примера, предположите, что следующий класс уже существует в AppModelпроекте:

namespace App\Model;

class Person
{
    private $age;
    private $name;
    private $sportsperson;
    private $createdAt;

    // Геттеры
    public function getName()
    {
        return $this->name;
    }

    public function getAge()
    {
        return $this->age;
    }

    // Иссеры
    public function isSportsperson()
    {
        return $this->sportsperson;
    }

    // Сеттеры
    public function setName($name)
    {
        $this->name = $name;
    }

    public function setAge($age)
    {
        $this->age = $age;
    }

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

    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;
    }
}

Теперь, если вы хотите сериализовать этот объект в JSON, вам просто нужно использовать сервис Serializer, созданный ранее:

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

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

// $jsonContent содержит {"name":"foo","age":99,"sportsperson":false,"createdAt":null}

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

Первый параметр serialize() - это объект, который должен быть сериализован, а второй - используются для выбора правильного кодировщика, в этом случае - JsonEncoder.

Десериализация объекта

Теперь вы узнаете, как делать с точностью до наоборот. В этот раз, информация класса Person будет зашифрована в формате XML:

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

В этом случае, deserialize() требует трёх параметров:

  1. Информацию, которую нужно расшифровать
  2. Имя класса, в который будет расшифрована эта информация
  3. Кодировщик, используемый для преобразования этой информации в массив

По умолчанию, дополнительные атрибуты, которые не связываются с денормализованным объектом, будут проигнорированы компонентом Сериализатор. Если вы предпочитаете получать исключение, когда это происходит, установите опцию контекста AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES как false и предоставьте объект, реализующий ClassMetadataFactoryInterface при создании нормализатора:

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,
]);

Десериализация в существующем объекте

Serializer также может быть использован для обновления существующего объекта:

// ...
$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)

Это распространённая необходимость, при работе с ORM.

AbstractNormalizer::OBJECT_TO_POPULATE используется только для объектов верхнего уровня. Если этот объект - корень иерархической структуры, все дочерние элементы, которые существуют в нормализованных данных, будут созданы повторно с новыми экземплярами.

Когда опация AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE установлена как true, cуществующие дочери корня OBJECT_TO_POPULATE обновляются из нормализованных данных, вместо того, чтобы денормализатор создавал их повторно. Заметьте, что DEEP_OBJECT_TO_POPULATE работает только для единичных дочерних объектов, а не для массивов. Они все равно будут заменяться, если будут обнаружены в нормализованных данных.

Группы атрибутов

Иногда вам захочется сериализовать разные наборы атрибутов из ваших сущностей. Группы являются удобным способом достижения этого.

Предположите, что у вас есть следующий простой PHP объект:

namespace App\Model;

class MyObj
{
    public $foo;

    private $bar;

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

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

Определение сериализатора может быть указано используя аннотация, XML или YAML. ClassMetadataFactory, который будет использован нормализатором должен знать, какой формат использовать.

Следующий код показывает, как инициализировать ClassMetadataFactory для каждого формата:

  • Аннотации в PHP-файлах:

    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-файлах:

    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-файлах:

    use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
    use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
    
    $classMetadataFactory = new ClassMetadataFactory(new XmlFileLoader('/path/to/your/definition.xml'));
    

Далее, создайте ваше определение групп:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    namespace App\Model;
    
    use Symfony\Component\Serializer\Annotation\Groups;
    
    class MyObj
    {
        /**
         * @Groups({"group1", "group2"})
         */
        public $foo;
    
        /**
         * @Groups({"group3"})
         */
        public function getBar() // is* methods are also supported
        {
            return $this->bar;
        }
    
        // ...
    }
    
  • Attributes
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    namespace Acme;
    
    use Symfony\Component\Serializer\Annotation\Groups;
    
    class MyObj
    {
        #[Groups(['group1', 'group2'])]
        public $foo;
    
        #[Groups(['group3'])]
        public function getBar() // is* methods are also supported
        {
            return $this->bar;
        }
    
        // ...
    }
    
  • YAML
    1
    2
    3
    4
    5
    6
    Acme\MyObj:
        attributes:
            foo:
                groups: ['group1', 'group2']
            bar:
                groups: ['group3']
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    <?xml version="1.0" encoding="UTF-8" ?>
    <serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping
            https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
    >
        <class name="Acme\MyObj">
            <attribute name="foo">
                <group>group1</group>
                <group>group2</group>
            </attribute>
    
            <attribute name="bar">
                <group>group3</group>
            </attribute>
        </class>
    </serializer>
    

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

use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$obj = new MyObj();
$obj->foo = 'foo';
$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', 'bar' => 'bar'],
    'MyObj',
    null,
    ['groups' => ['group1', 'group3']]
);
// $obj2 = MyObj(foo: 'foo', bar: 'bar')

Выбор определённых атрибутов

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

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']];

Доступны только атрибуты, которые не игнорируются (см. ниже). Если установлены какие-то группы сериализации, то могут быть использованы только атрибуты, разрешённые этими группами.

Что касается групп, атрибуты могут быть выбраны как во время процесса сериализации, так и десериализации.

Игнорирование атрибутов

Все атрибуты по умолчанию включены при сериализации объектов. Существует два варианта игнорирования некоторых из этих атрибутов.

Вариант 1: Используя аннотацию @Ignore

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    namespace App\Model;
    
    use Symfony\Component\Serializer\Annotation\Ignore;
    
    class MyClass
    {
        public $foo;
    
        /**
         * @Ignore()
         */
        public $bar;
    }
    
  • Attributes
     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;
    }
    
  • YAML
    1
    2
    3
    4
    App\Model\MyClass:
        attributes:
            bar:
                ignore: true
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <?xml version="1.0" ?>
    <serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping
            https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
    >
        <class name="App\Model\MyClass">
            <attribute name="bar">
                <ignore>true</ignore>
            </attribute>
        </class>
    </serializer>
    

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

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'];

Вариант 2: Используя контекст

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

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"}

Конвертация имен свойств при сериализации и десериализации

Иногда сериализованные атрибуты должны называться по-другому, чем свойства или методы геттера/сеттера PHP-классов.

Компонент Сериализатор предоставляет удобный способ перевести или отобразить имена PHP-полей в сериализованные имена: Систему конвертации имен.

При условии, что у вас есть следующий объект:

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

А в сериализованной форме все атрибуты должны иметь префикс org_, как показано далее:

{"org_name": "Acme Inc.", "org_address": "123 Main Street, Big City"}

Пользовательский конвертер имен может работать с такими случаями:

use Symfony\Component\Serializer\NameConverter\NameConverterInterface;

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

    public function denormalize(string $propertyName)
    {
        // удаляет префикс 'org_'
        return 'org_' === substr($propertyName, 0, 4) ? substr($propertyName, 4) : $propertyName;
    }
}

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

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

Вы также можете реализовать AdvancedNameConverterInterface, чтобы получить доступ к текущему имени, формату и контексту класса.

Из CamelCase в snake_case

Во многих форматах распространено использование нижних подчёркиваний для разделения слов (также известно, как snake_case). Однако, в приложениях Symfony часто используется CamelCase для именования свойств (несмотря на то, что стандарт PSR-1 не рекомендует никакой определённый стиль для имён свойств).

Symfony предоставляет встроенный преобразователь имён, созданный для преобразований между стилями snake_case и CamelCased во время процессов сериализации и десериализации:

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 с firstName: 'Anne'

Конфигурация конверсии имен с использованием метаданных

Если этот компонент используется внутри приложения Symfony и фабрика класса метаданных включена, как объясняется в Attributes Groups section, все уже настроено и вам нужно только предоставить конфигурацию. В других случаях:

// ...
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()]
);

Теперь сконфигурируйте отображение вашей конверсии имен. Рассмотрите приложение, которое определяет сущность Person со свойством firstName:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    namespace App\Entity;
    
    use Symfony\Component\Serializer\Annotation\SerializedName;
    
    class Person
    {
        /**
         * @SerializedName("customer_name")
         */
        private $firstName;
    
        public function __construct($firstName)
        {
            $this->firstName = $firstName;
        }
    
        // ...
    }
    
  • Attributes
     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;
        }
    
        // ...
    }
    
  • YAML
    1
    2
    3
    4
    App\Entity\Person:
        attributes:
            firstName:
                serialized_name: customer_name
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <?xml version="1.0" encoding="UTF-8" ?>
    <serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping
            https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
    >
        <class name="App\Entity\Person">
            <attribute name="firstName" serialized-name="customer_name"/>
        </class>
    </serializer>
    

Это пользовательское отображение используется для преобразования имен свойств во время сериализации и десериализации объектов:

$serialized = $serializer->serialize(new Person('Kévin'), 'json');
// {"customer_name": "Kévin"}

Сериализация булевых атрибутов

Если вы используете методы иссеров (методы, с префиксом is, вроде Acme\Person::isSportsperson()), компонент Serializer автоматически определит его и использует для сериализации связанных атрибутов.

ObjectNormalizer также заботится о методах, начинающихся на has, add и remove.

Использование обратных вызовов для сериализации свойств с экземплярами объектов

При сериализации вы можете устаналивать обратный вызов для форматирования определённого свойства объекта:

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');
// Вывод: {"name":"cordoval", "age": 34, "createdAt": "2014-03-22T09:43:12-0500"}

Нормализаторы

Нормализаторы превращают объект в массив и наоборот. Они реализуют :NormalizableInterface для нормализации (объекта в массив) и DenormalizableInterface для денормализации (массива в объект).

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

use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

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

Встроенные нормализаторы

Компонент Serializer предоставляет несколько встроенных нормализаторов:

ObjectNormalizer

Этот нормализатор использует PropertyAccess Component чтобы считывать и делать записи в объекте. Это означает, что он имеет доступ к свойства напрямую и через геттеры, сеттеры, хассеры, иссеры, аддеры и ремуверы. Он поддерживает вызов конструктора во время процесса денормализации.

Объекты нормализуются в карту имен свойств и значений (имена генерируются путем удаления префикса get, set, has, is, add или remove из имени метода и трансформации первой буквы в нижний регистр; например, getFirstName() -> firstName).

ObjectNormalizer - это самый мощный нормализатор. Он конфигурируется по умолчанию в приложениях Symfony с включенным компонентом Serializer.

GetSetMethodNormalizer

Этот нормализатор читает содержание класса путем вызова “геттеров” (публичных методов, начинающихся на “get”). Он денормализует данные, вызывая конструктор и “сеттеры” (публичные методы, начинающиеся на “set”).

Объекты нормализуются в карту имен свойств и значений (имена генерируются путем удаления префикса get из имени метода и тренформации первой буквы в нижний регистр; например, getFirstName() -> firstName).

PropertyNormalizer

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

Объекты нормализуются в капту имен и значений свойств.

JsonSerializableNormalizer

Этот нормализатор работает с классами, реализующими JsonSerializable.

Он будет вызывать метод JsonSerializable::jsonSerialize(), а затем далее нормализовать результат. Это означает, что вложенные классы JsonSerializable также будут нормализованы.

Этот нормализатор особенно полезен, когда вы хотите постепенно мигрировать с существующей базы исходного кода, используя простую json_encode на Сериализатор Symfony, позволяя вам смешивать то, какие нормализаторы для каких классов используются.

В отличие от json_encode циклические ссылки могут быть обработаны.

DateTimeNormalizer
Этот нормализатор конвертирует объекты DateTimeInterface (например, DateTime и DateTimeImmutable) в строки. По умолчанию, он использует формат RFC3339.
DateTimeZoneNormalizer
Этот нормализатор конвертирует объекты DateTimeZone в строки, которые представляют название временной зоны в соответствии со `Списком PHP временных зон`_.
DataUriNormalizer
Этот нормализатор конвертирует объекты SplFileInfo в данные URI строки (data:...) так, что файлы могут быть встроены в сериализованные данные.
DateIntervalNormalizer
Этот нормализатор конвертирует объекты DateInterval в строки. По умолчанию, он использует формат P%yY%mM%dDT%hH%iM%sS.
FormErrorNormalizer

Этот нормализатор работает с классами, реализующими FormInterface.

Он будет получать ошибки из формы и нормализовать их в нормализованный массив.

ConstraintViolationListNormalizer
Этот нормализатор конвертирует объекты, реализующие ConstraintViolationListInterface в список ошибок в соответствии со стандартом RFC 7807.
ProblemNormalizer
Нормализирует ошибки в соотстветствии со спецификацией проблем API RFC 7807.

CustomNormalizer

Нормализует PHP-объект используя объект, реализующий NormalizableInterface.
UidNormalizer

Этот нормализатор конвертирует объекты, реализующие 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_FORMAT_RFC_4122.

Также он может денормализовать строки uuid или ulid в Uuid или Ulid. Формат не имеет значения.

New in version 5.2: UidNormalizer был представлен в Symfony 5.2.

New in version 5.3: Форматы нормализации UidNormalizer были представлены в Symfony 5.3.

Кодировщики

Кодировщики превращают массивы в форматы и наоборот. Они реализуют EncoderInterface для кодирования (массив в формат) и DecoderInterface для декодирования (формат в массив).

Вы можете добавить новые кодировщики в экземпляр Serializer используя второй аргумент конструктора:

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;

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

Встроенные кодировщики

Компонент Serializer предоставляет несколько встроенных кодировщиков:

JsonEncoder
Этот класс зашифровывает и расшифровывает данные в JSON.
XmlEncoder
Этот класс зашифровывает и расшифровывает данные в XML.
YamlEncoder
Этот кодировщик зашифровывает и расшифровывает данные в YAML. Кодировщик требует компонент Yaml.
CsvEncoder
Этот кодировщик зашифровывает и расшифровывает данные в CSV.

Note

Вы такоже можете создать собственый кодировщик, чтобы использовать другую структуру. Прочтите больше в How to Create your Custom Encoder.

Все эти кодировщики включены по умолчанию при использовании стандартной версии Symfony с включенным сериализатором.

Кодировщик JsonEncoder

JsonEncoder шифрует и дешифрует из JSON-строк, основываясь на PHP-функциях json_encode и json_decode. Он может быть полезен для модификации того, как это функции работают в определенных экземплярах, предоставляя опции вроде JSON_PRESERVE_ZERO_FRACTION. Вы можете использовать контекст сериализации, чтобы передать эти опции, используя ключ json_encode_options или json_decode_options, соответственно:

$this->serializer->serialize($data, 'json', ['json_encode_options' => \JSON_PRESERVE_ZERO_FRACTION]);

Кодировщик CsvEncoder

CsvEncoder кодирует и декодирует в и из CSV.

Опции контекста CsvEncoder

Метод encode() определяет третий необязательный параметр, под названием context, которые определяет опции конфигурации для ассоциативного массива CsvEncoder:

$csvEncoder->encode($array, 'csv', $context);

Вот доступные опции:

Опция Описание Значение по умолчанию
csv_delimiter Устанавливает разделитель поля, отделяющий значения (только один символ) ,
csv_enclosure Устанавливает закрытие поля (только один символ) "
csv_end_of_line Устаналивает символ(ы), используемые для отметки окончание каждой строчки в CSV-файле \n
csv_escape_char Устанавливает символ перехода (макс. один символ) пустая строка
csv_key_separator Устанавливает разделитель для ключей массива во время его обработки .
csv_headers Устанавливает порядок столбцов заголовков и данных Пример: если $data = ['c' => 3, 'a' => 1, 'b' => 2] и $options = ['csv_headers' => ['a', 'b', 'c']] то serialize($data, 'csv', $options) возвращает a,b,c\n1,2,3 [], выврдится из ключей данных ввода
csv_escape_formulas Избегает полей, содержащих формулы, добавляя в начале символ``t`` false
as_collection Всегда возвращает результат в виде коллекции, даже если зашифрована только одна строчка true
no_headers Отключает заголовок в зашифрованном CSV false
output_utf8_bom Выводит специальный UTF-8 BOM вместе с защифрованными данными false

New in version 5.3: Опция csv_end_of_line была добавлена в Symfony 5.3.

Кодировщик XmlEncoder

Этот кодировщик преобразует массивы в XML и наоборот.

Например, возьмём объект нормализированный следующим образом:

['foo' => [1, 2], 'bar' => true];

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>

Специальный ключ # может быть использован для определения данных узла:

['foo' => ['@bar' => 'value', '#' => 'baz']];

// зашифрован следующим образом:
// <?xml version="1.0"?>
// <response>
//     <foo bar="value">
//        baz
//     </foo>
// </response>

Более того, ключи, начинающиеся с @, будут счтаться атрибутами, а ключ #comment может быть использован для зашифровки XML-комментариев:

$encoder = new XmlEncoder();
$encoder->encode([
    'foo' => ['@bar' => 'value'],
    'qux' => ['#comment' => 'A comment'],
], 'xml');
// вернет:
// <?xml version="1.0"?>
// <response>
//     <foo bar="value"/>
//     <qux><!-- A comment --!><qux>
// </response>

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

Tip

XML-комментарии игнорируются по умолчанию при дешифровке содержания, но это поведение можно изменить с помощью необязательного ключа XmlEncoder::DECODER_IGNORED_NODE_TYPES.

Данные с ключами #comment зашифровываются в XML-комментарии по умолчанию. Это можно изменить с помощью необязательного аргумента $encoderIgnoredNodeTypes класса конструктора XmlEncoder.

Опции контекста XmlEncoder

Метод encode() определяет третий необязательный параметр под названием context, который определяет опции конфигурации для ассоциативного массива XmlEncoder

$xmlEncoder->encode($array, 'xml', $context);

Доступны следующие опции:

Опция Описание Значение по умолчанию
xml_format_output Если установлен как true, форматирует сгенерированный XML разрывами строки и отступами  
xml_version Устанавливает XML-версию атрибута 1.1
xml_encoding Устанавливает атрибут, зашифровывающий XML utf-8
xml_standalone Добавляет отдельный атрибут в сгенерированный XML true
xml_type_cast_attributes Предоставляет возможность опустить построение типа атрибута true
xml_root_node_name Устанавливает имя узла корня (по умолчанию: response).  
as_collection Всегда возвращает результат в виде коллекции, даже если зашифрована только одна строчка  
decoder_ignored_node_types Указывает игнорировать узлы в дешифровке [\XML_PI_NODE, \XML_COMMENT_NODE]
encoder_ignored_node_types Указывает игнорировать узлы в шифровании []
load_options XML, загружающий опции с libxml \LIBXML_NONET | \LIBXML_NOBLANKS
remove_empty_tags Если установлен как true, удаляет все пустые теги в сгенерированном XML false

Кодировщик YamlEncoder

Этот кодировщик требует Компонент Yaml и преобразует в и из Yaml.

Опции контекста YamlEncoder

Метод encode(), как и другой кодировщик, использует context, чтобы установить опции конфигурации для ассоциативного массива YamlEncoder:

$yamlEncoder->encode($array, 'yaml', $context);

Вот доступные отзывы:

Опция Описание Значение по умолчанию
yaml_inline Уровень, на котором вы переключаетесь на встраиваемый YAML 0
yaml_indent Размер отступов (используемых внутренне) 0
yaml_flags Константы бит-поля Yaml::DUMP_* / PARSE_* для настройки (де)шифровки YAML-строки 0

Пропуск значений null

По умолчанию, Сериализатор будет сохранять свойства, содержащие значение null. Вы можете изменить это поведение, установив опцию контекста AbstractObjectNormalizer::SKIP_NULL_VALUES как true:

$dummy = new class {
    public $foo;
    public $bar = 'notNull';
};

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

Работа с циклическими ссылками

Циклические ссылки распространены при работе с отношениями сущности:

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;
    }
}

Чтобы избежать бесконечных циклов, GetSetMethodNormalizer или ObjectNormalizer, вызоваите CircularReferenceException, когда столкнётесь с таким случаем:

$member = new Member();
$member->setName('Kévin');

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

$member->setOrganization($organization);

echo $serializer->serialize($organization, 'json'); // Вызывает CircularReferenceException

Ключ circular_reference_limit в контексте по умолчанию устанавливает количество раз, которое он будет сериализовать один и тот же объект, до признания его цикличной ссылкой. Его значение по умолчанию - 1.

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

$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"}]}

Работа с глубиной сериализации

Компонент Сериализация может определять и ограничивать глубину сериализации. Это особенно полезно при сериализации больших древ. Представьте следующую структуру данных:

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;

Serializer может быть сконфигурирован, чтобы установить максимальную глубину данного свойства. Здесь мы установили его, как 2 для свойства $child:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    namespace Acme;
    
    use Symfony\Component\Serializer\Annotation\MaxDepth;
    
    class MyObj
    {
        /**
         * @MaxDepth(2)
         */
        public $child;
    
        // ...
    }
    
  • Attributes
     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;
    
        // ...
    }
    
  • YAML
    1
    2
    3
    4
    Acme\MyObj:
        attributes:
            child:
                max_depth: 2
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <?xml version="1.0" encoding="UTF-8" ?>
    <serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping
            https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
    >
        <class name="Acme\MyObj">
            <attribute name="child" max-depth="2"/>
        </class>
    </serializer>
    

Загрузчик меаданных, соответствующий выбранному формату, должен быть сконфигурирован для того, чтобы использовать эту функцию. Это делается автоматически при использовании стандартной версии Symfony. При использовани компонента отдельно, см. документацию групп, чтобы узнать, как это сделать.

Проверка производится только если ключ AbstractObjectNormalizer::ENABLE_MAX_DEPTH контекста сериализатора установлен, как true. В следующем примере, третий уровень не сериализуется, так как он глубже, чем максимальная сконфигурированная глубина (2):

$result = $serializer->normalize($level1, null, [AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true]);
/*
$result = [
    'foo' => 'level1',
    'child' => [
        'foo' => 'level2',
        'child' => [
            'child' => null,
        ],
    ],
];
*/

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

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

// все параметры обратных вызовов не обязательны (вы можете пропустить те, которые не используете)
$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',
    ],
];
*/

Раббота с массивами

Компонент Serializer способен также работать с массивами объектов. Сериализация массивов работает так же, как и сериализация одного объекта:

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 содержит [{"name":"foo","age":99,"sportsperson":false},{"name":"bar","age":33,"sportsperson":true}]

Если вы хотите десериализовать такую структуру, то вам нужно добавить ArrayDenormalizer к набору нормализаторов. Добавив [] к типу параметра метода deserialize(), вы обозначите, что вы ожидаете массив вместо одного объекта:

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

Обработка аргументов конструктора

Если у конструктора класса есть аргументы, что обычно случается в Value Objects, сериализатор не сможет создать объект, если пропущены какие-то аргументы. В данных случаях используйте контекстную опцию default_constructor_arguments:

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', '');

Рекурсивная денормализация и безопасность типа

Компонент Serializer может использовать PropertyInfo Component, чтобы денормализовать сложные типы (объекты). Тип свойства класса будет предположен, используя предоставленный извлекатель и использован для рекурсивной денормализации внутренних данных.

При использовании стандартной версии Symfony, все нормализаторы автоматически конфигурируются, чтобы использовать зарегистрированные извлекатели. При использовании копомнента самостоятельно, реализация PropertyTypeExtractorInterface (обычно экземпляр PropertyInfoExtractor) должна быть передана в качестве 4го параметра ObjectNormalizer:

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'

Если доступен PropertyTypeExtractor, то нормализатор также проверит, чтобы данные для денормализации соответствовали типу свойства (даже для примитивных типов). Например, если предоставлена string, но тип свойства - int, будет вызвано UnexpectedValueException. Принуждение типа свойства можно отключить, установив опцию контекста сериализатора ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT, как true.

Сериализация интерфейсов и абстрактных классов

При работе с объектами, которые достаточно похожи или имеют общие свойства, вы можете использовать интерфейсы или абстрактные классы. Компонент Serializer позволяет вам сериализовать и десериализовать эти объекты, используя “отображение класса дискриминатора”

Дискриминатор - это поле (в сериализованной строке), используемое для дифференциации между возможными объектами. На практике, при использвании компонента Serializer, передайте реализацию ClassDiscriminatorResolverInterface ObjectNormalizer.

Компонент Serializer предоставляет реализацию ClassDiscriminatorResolverInterface под названием ClassDiscriminatorFromClassMetadata, который использует фабрику класса метаданных и конфигурацию отображения для сериализации и десерализации объектов правильного класса.

При использовании этого компонента внутри приложения Symfony и использовании фабрики класса метаданных, как объясняется в разделе группы атрибутов, это уже настроено и вам нужно только предоставить конфигурацию. В других случаях:

// ...
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()]
);

Теперь сконфигурируйте ваше отображение класса дискриминатора. Рассмотрите приложение, которое определяет абстрактный класс CodeRepository, расширенный классами GitHubCodeRepository и BitBucketCodeRepository:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    namespace App;
    
    use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
    
    /**
     * @DiscriminatorMap(typeProperty="type", mapping={
     *    "github"="App\GitHubCodeRepository",
     *    "bitbucket"="App\BitBucketCodeRepository"
     * })
     */
    abstract class CodeRepository
    {
        // ...
    }
    
  • Attributes
     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
    {
        // ...
    }
    
  • YAML
    1
    2
    3
    4
    5
    6
    App\CodeRepository:
        discriminator_map:
            type_property: type
            mapping:
                github: 'App\GitHubCodeRepository'
                bitbucket: 'App\BitBucketCodeRepository'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <?xml version="1.0" encoding="UTF-8" ?>
    <serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping
            https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
    >
        <class name="App\CodeRepository">
            <discriminator-map type-property="type">
                <mapping type="github" class="App\GitHubCodeRepository"/>
                <mapping type="bitbucket" class="App\BitBucketCodeRepository"/>
            </discriminator-map>
        </class>
    </serializer>
    

После конфигурации, cериализатор использует отображение для выбора правильного класса:

$serialized = $serializer->serialize(new GitHubCodeRepository(), 'json');
// {"type": "github"}

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

Узнать больше

See also

Нормализаторы для компонента Symfony Сериализатор, поддерживающие популярные API-форматы (JSON-LD, GraphQL, OpenAPI, HAL, JSON:API) доступны как часть проекта API Platform.

See also

Популярной альтернативой компоненту Serializer Symfony является сторонняя библиотека - JMS сериализатор (версии до v1.12.0 были выпущены под лицензией Apache, поэтому несовместимэ с проектами GPLv2).

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.