Intereting Posts

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

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

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

[{ "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 в 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 .

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

Спасибо

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 .

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

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