Денормализовать вложенную структуру в объектах с помощью сериализатора Symfony 2

Я работаю над проектом Symfony 2 с версией 2.8 и использую встроенный компонент Serializer -> http://symfony.com/doc/current/components/serializer.html

У меня есть структура JSON, предоставляемая веб-службой.
После десериализации я хочу денормализовать мой контент в объектах. Вот моя структура (модель / марка в контексте автомобильного приложения).

[{
"0": {
"id": 0,
"code": 1,
"model": "modelA",
"make": {
"id": 0,
"code": 1,
"name": "makeA"}
}
} , {
"1": {
"id": 1,
"code": 2,
"model": "modelB",
"make": {
"id": 0,
"code": 1,
"name": "makeA"}
}
}]

Моя идея состоит в том, чтобы заполнить VehicleModel объект, который содержит ссылку на VehicleMake объект.

class VehicleModel {
public $id;
public $code;
public $model;
public $make; // VehicleMake
}

Вот что я делаю:

// Retrieve data in JSON
$data = ...
$serializer = new Serializer([new ObjectNormalizer(), new ArrayDenormalizer()], [new JsonEncoder()]);
$models = $serializer->deserialize($data, '\Namespace\VehicleModel[]', 'json');

В результате мой объект VehicleModel правильно заселена, но $make логически массив ключ / значение. Здесь я хочу VehicleMake вместо.

Есть способ сделать это ?

Спасибо

13

Решение

ObjectNormalizer нужно больше конфигурации. Вам, по крайней мере, нужно будет указать четвертый параметр типа PropertyTypeExtractorInterface,

Вот (довольно хакерский) пример:

<?php
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$a = new VehicleModel();
$a->id = 0;
$a->code = 1;
$a->model = 'modalA';
$a->make = new VehicleMake();
$a->make->id = 0;
$a->make->code = 1;
$a->make->name = 'makeA';

$b = new VehicleModel();
$b->id = 1;
$b->code = 2;
$b->model = 'modelB';
$b->make = new VehicleMake();
$b->make->id = 0;
$b->make->code = 1;
$b->make->name = 'makeA';

$data = [$a, $b];

$serializer = new Serializer(
[new ObjectNormalizer(null, null, null, new class implements PropertyTypeExtractorInterface {
/**
* {@inheritdoc}
*/
public function getTypes($class, $property, array $context = array())
{
if (!is_a($class, VehicleModel::class, true)) {
return null;
}

if ('make' !== $property) {
return null;
}

return [
new Type(Type::BUILTIN_TYPE_OBJECT, true, VehicleMake::class)
];
}
}), new ArrayDenormalizer()],
[new JsonEncoder()]
);

$json = $serializer->serialize($data, 'json');
print_r($json);

$models = $serializer->deserialize($json, VehicleModel::class . '[]', 'json');
print_r($models);

Обратите внимание, что в вашем примере json первая запись имеет массив в качестве значения для make, Я принял это за опечатку, если это намеренно, пожалуйста, оставьте комментарий.

Чтобы сделать это более автоматический вы можете поэкспериментировать с PhpDocExtractor.

6

Другие решения

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

$serializer = new Serializer(
[
new ArrayNormalizer(),
new VehicleDenormalizer(),
new VehicleMakeDenormalizer()
], [
new JsonEncoder()
]
);
$models = $serializer->deserialize(
$data,
'\Namespace\VehicleModel[]',
'json'
);

Вот примерный код такого денормализатора

class VehicleDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface
{
public function denormalize($data, $class, $format, $context)
{
$vehicle = new VehicleModel();
...
$vehicleMake = $this->denormalizer->denormalize(
$data->make,
VehicleMake::class,
$format,
$context
);
$vehicle->setMake($vehicleMake);
...
}
}

У меня есть только сомнения, стоит ли нам полагаться на $this->denormalizer->denormalize (который работает правильно только потому, что мы используем Symfony\Component\Serializer\Serializer) или мы должны явно ввести VehicleMakeDenormalizer в VehicleDenormalizer

$vehicleDenormalizer = new VehicleDenormalizer();
$vehicleDenormalizer->setVehicleMakeDenormalizer(new VehicleMakeDenormalizer());
3

По вопросам рекламы [email protected]