Desnormalizar la estructura anidada en objetos con el serializador Symfony 2

Estoy trabajando en el proyecto Symfony 2 con la versión 2.8 y estoy usando el componente integrado Serializer -> http://symfony.com/doc/current/components/serializer.html

Tengo una estructura JSON proporcionada por un servicio web. Después de la deserialización, quiero desnormalizar mi contenido en objetos. Aquí está mi estructura (modelo / marca en un contexto de aplicación de automóvil).

[{ "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" } } }] 

Mi idea es llenar un objeto VehicleModel que contiene una referencia a un objeto VehicleMake .

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

Esto es lo que hago:

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

Como resultado, mi objeto VehicleModel está correctamente rellenado, pero $make es lógicamente una matriz clave / valor. Aquí quiero un VehicleMake lugar.

Hay una manera de hacer eso ?

Gracias

ObjectNormalizer necesita más configuración. Al menos deberá proporcionar el cuarto parámetro de tipo PropertyTypeExtractorInterface .

Aquí hay un ejemplo (algo hacky):

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

Tenga en cuenta que en su ejemplo json, la primera entrada tiene una matriz como valor para make . Tomé esto como un error tipográfico, si es deliberado, por favor deje un comentario.

Para que esto sea más automático, es posible que desee experimentar con PhpDocExtractor .

En los casos en que necesitas más flexibilidad en la desnormalización, es bueno crear tus propios denormalizadores.

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

Aquí el código aproximado de tal denormalizador

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

Solo tengo dudas sobre si debemos confiar en $this->denormalizer->denormalize (que funciona correctamente solo porque usamos Symfony\Component\Serializer\Serializer ) o debemos inyectar de forma explícita VehicleMakeDenormalizer en VehicleDenormalizer

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