web-dev-qa-db-ja.com

symfony 2シリアライザーでオブジェクトの入れ子構造を非正規化する

私はバージョン2.8のSymfony 2プロジェクトに取り組んでおり、組み込みコンポーネントSerializer-> http://symfony.com/doc/current/components/serializer.html を使用しています。

Webサービスによって提供される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が必要です。

それを行う方法はありますか?

THX

13
kero_zen

ObjectNormalizerにはさらに設定が必要です。少なくとも、タイプPropertyTypeExtractorInterfaceの4番目のパラメーターを指定する必要があります。

これは(むしろハッキーな)例です:

<?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 を試してみるとよいでしょう。

7
Yoshi

非正規化により多くの柔軟性が必要な場合は、独自の非正規化子を作成することをお勧めします。

$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->denormalizeSymfony\Component\Serializer\Serializerを使用しているからといって正しく機能する)に依存しているか、VehicleMakeDenormalizerVehicleDenormalizerに明示的に注入する必要があるのか​​、疑問に思うだけです。

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