简体   繁体   English

如何使用JMS Serializer处理递归对象

[英]How to handle recursive objects with JMS Serializer

I am trying to serialize and deserialize a Doctrine object graph. 我正在尝试序列化和反序列化Doctrine对象图。

The structure is pretty complex, but this example sums up my problem: 结构非常复杂,但这个例子总结了我的问题:

There is a Company entity with a OneToMany relationship to Employee . 有一个与Employee具有OneToMany关系的Company实体。
The Employee entity has a ManyToOne relationship with the Company . Employee实体与Company具有ManyToOne关系。

This is serialized as follows: 这序列化如下:

{
    "company": {
        "name": "MegaCorp",
        "employees": [{
            "name": "John Doe",
            "company": null
        }]
    }
}

So it null s the reference to the Employee 's parent Company . 因此, null S中的参考Employee的父Company For serialization this is ok. 对于序列化,这没关系。 But now when I deserialize this json, I get a null Company in the Employee object. 但是现在当我反序列化这个json时,我在Employee对象中得到一个null Company What I want (and expect) is to get a correct reference to the parent Company . 我想(和期望)是获得正确的引用,父Company

Is this possible using JMS serializer and if so, how can it be done? 这是否可以使用JMS序列化器,如果是这样,它怎么做?
If it is not possible, what could be a good workaround? 如果不可能,那么什么是一个好的解决方法? Remember that it is a large graph, I don't want to do it manually. 请记住,它是一个大图,我不想手动执行。

Unfortunately, when deserializing, there is no way for the serializer to know whether the objects are identical or actually the same object. 不幸的是,在反序列化时,序列化程序无法知道对象是相同的还是实际上是同一个对象。 Even if you could nest them recursively. 即使你可以递归地嵌套它们。

But, you can get the desired result when combining the @Accessor annotation with some business logic. 但是,在将@Accessor注释与某些业务逻辑相结合时,您可以获得所需的结果。 So going off of your example: 所以离开你的榜样:

class Company {
    /**
     * @Accessor(setter="addEmployees")
     */
    private $employees;

    public function addEmployee(Employee $employee)
    {
        if (!$this->employees->contains($employee)) {
            $this->employees[] = $employee;
            $employee->setCompany($this);
        }
    }

    public function addEmployees($employees)
    {
        foreach ($employees as $employee) {
            $this->addEmployee($employee);
        }
    }
}

class Employee {
    /**
     * @Accessor(setter="setCompany")
     */
    private $company;

    public setCompany(Company $company = null)
    {
        $this->company = $company;

        if ($company) {
            $company->addEmployee($this);
        }
    }
}

I think this is a more natural approach than using @PostDeserialize as you probably already have some of these methods in your code. 我认为这比使用@PostDeserialize更自然,因为您的代码中可能已经有了一些这样的方法。 Also, it ensures the contract in both ways, so if you were to start from Employee you'd get the same result. 此外,它以两种方式确保合同,因此如果您从Employee开始,您将获得相同的结果。

What's about set the reference manually when you have deserialize the object? 在反序列化对象时手动设置引用是什么? Something like this: 像这样的东西:

class Company { 

    ....

    @PostDeserialize
    public function setReferences()
    {
        foreach( $this->employees as $employee ){
            $employee->setCompany( $this );
        }
    }
}

Is a good practice to keep as simple as possible your JSON entities! 保持JSON实体尽可能简单是一种很好的做法! If you have to deal with this kind of issues, is the moment to rethink your data model! 如果您必须处理这类问题,那么重新考虑您的数据模型的时刻到了!

In addition, did you think about use HATEOAS (Hypermedia as the Engine of Application State) is a principle that hypertext links should be used to create a better navigation through the API. 另外,您是否考虑过使用HATEOAS(超媒体作为应用程序状态的引擎)是一个原则,应该使用超文本链接来创建更好的API导航。 Looks like this: 看起来像这样:

{
  "id": 711,
  "manufacturer": "bmw",
  "model": "X5",
  "seats": 5,
  "drivers": [
   {
    "id": "23",
    "name": "Stefan Jauker",
    "links": [
     {
     "rel": "self",
     "href": "/api/v1/drivers/23"
    }
   ]
  }
 ]
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM