2016-10-14 99 views
9

我工作的Symfony 2項目2.8版本,我使用的是內置的組件串行 - >http://symfony.com/doc/current/components/serializer.html與symfony的2串對象非規範化嵌套結構

我已經通過網絡提供的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

回答

5

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

+0

你是對的我在我的json有一個錯字。我更新了我的問題。 –

+0

ObjectNormaliser在構造函數中只需要3個參數,而第三個實現PropertyAccessorInterface,對吧? –

+0

哦,我只在sf3上測試過。所以api可能會有變化。如果在v2.8中沒有辦法添加類型提取器,那麼這個答案可能不適合你。 – Yoshi

3

在需要非規範化更靈活的情況下,創建自己的denormalizers是很好的選擇。

$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)或我們必須明確地注入VehicleMakeDenormalizerVehicleDenormalizer

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