将嵌套的Doctrine实体的JSON表示序列化回Doctrine

时间:2019-05-30 10:13:53

标签: symfony doctrine serializer

我在多个项目中都有一整套共享的教义实体。

第一个项目从外部API提取数据,将数据序列化为我的Doctrine实体,然后序列为JSON。将此JSON推送到队列中,以供另一个项目读取。

一个示例JSON有效负载为

{
  "addressLine1": "Address1",
  "addressLine2": "Address2",
  "townCity": "",
  "county": "Somewhere",
  "postCode": "XX17 XPJ",
  "meters": [
    {
      "reference": "1234442123",
      "profileClass": null,
      "source": "Futura",
      "sourceId": 132
    }
  ],
  "source": "Futura",
  "sourceId": "00000002|97"
}

这对于我的初始同步很好,因为该实体在数据库中不存在,但是如果我收到一个已经存在的实体,我最终会得到

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1234442123' for key 'reference'

我是否可以将JSON序列化到我的Doctrine对象中,但可以通过sourcesource_id查询以获取现有实体并进行更新?

值得一提的是,第一个生成JSON的项目无权访问数据库。我必须在接收端执行此操作。

class SupplyPoint
{

    /**
     * @var int
     */
    private $id;

    /**
     * @var string|null
     */
    private $addressLine1;

    /**
     * @var string|null
     */
    private $addressLine2;

    /**
     * @var string|null
     */
    private $townCity;

    /**
     * @var string|null
     */
    private $county;

    /**
     * @var string|null
     */
    private $postCode;

    /**
     * @var Meter[]|array
     */
    private $meters;
class Meter
{
    /**
     * @var int|string
     */
    private $id;

    /**
     * @var SupplyPoint
     */
    private $supplyPoint;

    /**
     * @var string|null
     */
    private $reference;

    /**
     * @var int|null
     */
    private $profileClass;

我目前在序列化之后得到这个,但是我想在那里的某个步骤将我的数据链接到数据库中存在的现有实体。因此,填充ID字段,并让Doctrine知道它们是要更新的现有实体

Uttily\Entities\SupplyPoint {#964
  -id: null
  -addressLine1: "Address1"
  -addressLine2: "Address2"
  -townCity: ""
  -county: "Somewhere"
  -postCode: "XX17 XPJ"
  -meters: Doctrine\Common\Collections\ArrayCollection {#980
    -elements: array:1 [
      0 => Uttily\Entities\Meter {#1088
        -id: null
        -supplyPoint: Uttily\Entities\SupplyPoint {#964}
        -reference: "1234442123"
        -profileClass: null
        -source: "Futura"
        -sourceId: 132
        #createdAt: null
        #updatedAt: null
      }
    ]
  }
  -source: "Futura"
  -sourceId: "00000002|97"
  #createdAt: null
  #updatedAt: null
}

我不希望手动进行此操作,因为会向Meters添加更多的关系,因此自动过程将是理想的选择,这样我就可以向Doctrine中添加关系并且它“可以正常工作”

我的序列化器:

        $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));

        $encoders = [new JsonEncoder()];
        $normalizers = [new EntityNormalizer($em), new ArrayDenormalizer(), new ObjectNormalizer($classMetadataFactory, null, null, new PhpDocExtractor())];

        $this->serializer = new Serializer($normalizers, $encoders);

EntityNormalizer通过其来源和source_id找到SupplyPoint

        if (isset($data['source'], $data['sourceId']) && $data['source'] !== null && $data['sourceId'] !== null) {
            $source = [
                'source'   => $data['source'],
                'sourceId' => $data['sourceId'],
            ];
        }

        return $this->em->getRepository($class)->findOneBy($source);

并使用现有的SupplyPoint返回我的Meters,但是当我将JSON有效负载与该实体合并时,例如:

        // Merge JSON data into a new or existing supply point object
        $uttilySupplyPoint = $serializer->deserializeIntoObject(
            $this->payload,
            SupplyPoint::class,
            $uttilySupplyPoint
        );

SupplyPoint的ID仍然存在,但Meter的ID已删除

    #collection: Doctrine\Common\Collections\ArrayCollection {#999
      -elements: array:1 [
        1 => Uttily\Entities\Meter {#1018
          -id: null
          -supplyPoint: Uttily\Entities\SupplyPoint {#983}
          -reference: "123456"
          -profileClass: null
          -source: "Futura"
          -sourceId: null
          #createdAt: null
          #updatedAt: null
        }
      ]
    }

0 个答案:

没有答案