如何使用 JMS Serializer 处理递归对象
How to handle recursive objects with JMS Serializer
我正在尝试序列化和反序列化 Doctrine 对象图。
结构相当复杂,但这个例子总结了我的问题:
有一个 Company
实体与 Employee
具有一对多关系。
Employee
实体与 Company
.
存在多对一关系
本文连载如下:
{
"company": {
"name": "MegaCorp",
"employees": [{
"name": "John Doe",
"company": null
}]
}
}
所以它 null
是对 Employee
的父 Company
的引用。对于序列化,这是可以的。
但是现在当我反序列化这个 json 时,我在 Employee
对象中得到了一个 null
Company
。我想要(和期望)的是获得对父 Company
.
的正确引用
是否可以使用 JMS 序列化程序,如果可以,如何实现?
如果不可能,什么是好的解决方法?记住是大图,我不想手动做。
不幸的是,在反序列化时,序列化程序无法知道对象是否相同或实际上是同一个对象。即使你可以递归地嵌套它们。
但是,将 @Accessor
注释与某些业务逻辑结合使用时,您可以获得所需的结果。所以离开你的例子:
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);
}
}
}
我认为这是一种比使用 @PostDeserialize
更自然的方法,因为您的代码中可能已经包含其中一些方法。此外,它以两种方式确保合同,因此如果您从 Employee
开始,您会得到相同的结果。
反序列化对象后手动设置引用有什么用?像这样:
class Company {
....
@PostDeserialize
public function setReferences()
{
foreach( $this->employees as $employee ){
$employee->setCompany( $this );
}
}
}
让您的 JSON 实体尽可能简单是一个很好的做法!如果您必须处理此类问题,是时候重新考虑您的数据模型了!
此外,您是否考虑过使用 HATEOAS(超媒体作为应用程序状态引擎)的原则,即应该使用超文本链接来创建更好的 API 导航。看起来像这样:
{
"id": 711,
"manufacturer": "bmw",
"model": "X5",
"seats": 5,
"drivers": [
{
"id": "23",
"name": "Stefan Jauker",
"links": [
{
"rel": "self",
"href": "/api/v1/drivers/23"
}
]
}
]
}
我正在尝试序列化和反序列化 Doctrine 对象图。
结构相当复杂,但这个例子总结了我的问题:
有一个 Company
实体与 Employee
具有一对多关系。
Employee
实体与 Company
.
本文连载如下:
{
"company": {
"name": "MegaCorp",
"employees": [{
"name": "John Doe",
"company": null
}]
}
}
所以它 null
是对 Employee
的父 Company
的引用。对于序列化,这是可以的。
但是现在当我反序列化这个 json 时,我在 Employee
对象中得到了一个 null
Company
。我想要(和期望)的是获得对父 Company
.
是否可以使用 JMS 序列化程序,如果可以,如何实现?
如果不可能,什么是好的解决方法?记住是大图,我不想手动做。
不幸的是,在反序列化时,序列化程序无法知道对象是否相同或实际上是同一个对象。即使你可以递归地嵌套它们。
但是,将 @Accessor
注释与某些业务逻辑结合使用时,您可以获得所需的结果。所以离开你的例子:
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);
}
}
}
我认为这是一种比使用 @PostDeserialize
更自然的方法,因为您的代码中可能已经包含其中一些方法。此外,它以两种方式确保合同,因此如果您从 Employee
开始,您会得到相同的结果。
反序列化对象后手动设置引用有什么用?像这样:
class Company {
....
@PostDeserialize
public function setReferences()
{
foreach( $this->employees as $employee ){
$employee->setCompany( $this );
}
}
}
让您的 JSON 实体尽可能简单是一个很好的做法!如果您必须处理此类问题,是时候重新考虑您的数据模型了!
此外,您是否考虑过使用 HATEOAS(超媒体作为应用程序状态引擎)的原则,即应该使用超文本链接来创建更好的 API 导航。看起来像这样:
{
"id": 711,
"manufacturer": "bmw",
"model": "X5",
"seats": 5,
"drivers": [
{
"id": "23",
"name": "Stefan Jauker",
"links": [
{
"rel": "self",
"href": "/api/v1/drivers/23"
}
]
}
]
}