Сериализация графа сложного объекта в XML и обратно

проблема

У меня есть следующий объект графа:

AppBundle\Controller\Person Object
(
[name:AppBundle\Controller\Person:private] => Person Name
[age:AppBundle\Controller\Person:private] => 10
[phones:AppBundle\Controller\Person:private] => Array
(
[0] => AppBundle\Controller\Telephone Object
(
[phone:AppBundle\Controller\Telephone:private] => 221-16-78
)
[1] => AppBundle\Controller\Telephone Object
(
[phone:AppBundle\Controller\Telephone:private] => 221-16-78
)
)
)

и сериализация с использованием следующего кода из моего контроллера:

$s = $this->get("serializer")->serialize($person, 'xml');

и это дает мне следующий результат:

<response>
<name>Person Name</name>
<age>10</age>
<phones>
<phone>221-16-78</phone>
</phones>
<phones>
<phone>221-16-78</phone>
</phones>
</response>

Десериализация с использованием следующего кода:

$this->get("serializer")->deserialize($s, 'AppBundle\Controller\Person', 'xml');

возвращает следующее:

AppBundle\Controller\Person Object
(
[name:AppBundle\Controller\Person:private] => Person Name
[age:AppBundle\Controller\Person:private] => 10
[phones:AppBundle\Controller\Person:private] => Array
(
[0] => Array
(
[phone] => 221-16-78
)
[1] => Array
(
[phone] => 221-16-78
)
)
)

Вопрос

Во-первых, есть ли способ получить xml следующим образом:

<response>
<name>Person Name</name>
<age>10</age>
<phones>
<telephone>
<phone>221-16-78</phone>
</telephone>
<telephone>
<phone>221-16-78</phone>
</telephone>
</phones>
</response>

И, во-вторых, как я могу десериализовать его обратно в граф объектов (Персона и Телефон), однажды используя простую десериализацию, он возвращает объект персона с массивом телефонов, который содержит ассоциативный массив вместо Telephone объекты.

Модель / Контроллер

Вот мои классы модели / контроллера:

<?php

namespace AppBundle\Controller;

class Person {

private $name;
private $age;
private $phones;

public function getName() {
return $this->name;
}

public function getAge() {
return $this->age;
}

public function getPhones() {
return $this->phones;
}

public function setName($name) {
$this->name = $name;
}

public function setAge($age) {
$this->age = $age;
}

public function setPhones($phones) {
$this->phones = $phones;
}

}

<?php

namespace AppBundle\Controller;

class Telephone {

private $phone;

public function getPhone() {
return $this->phone;
}

public function setPhone($phone) {
$this->phone = $phone;
}

}

И мой метод контроллера:

/**
* @Route("/", name="homepage")
*/
public function indexAction(Request $request)
{

$phone1 = new Telephone();
$phone1->setPhone("221-16-78");

$phone2 = new Telephone();
$phone2->setPhone("221-16-78");

$person = new Person();
$person->setName("Person Name");
$person->setAge(10);
$person->setPhones(array($phone1, $phone2));

print_r($person);

$s = $this->get("serializer")->serialize($person, 'xml');
$p = $this->get("serializer")->deserialize($s, 'AppBundle\Controller\Person', 'xml');

print_r($p);

}

Решение с использованием JMS Serializer

Я смог решить эту проблему с помощью JMS Serializer, предоставив некоторые подсказки сериализатору с помощью аннотаций (в основном, типов и списков) следующим образом:

<?php

namespace AppBundle\Controller;

use JMS\Serializer\Annotation\Type;
use JMS\Serializer\Annotation\XmlList;

class Person {

/**
* @Type("string")
*/
private $name;
/**
* @Type("integer")
*/
private $age;
/**
* @Type("array<AppBundle\Controller\Telephone>")
* @XmlList(entry = "telephone")
*/
private $phones;

public function getName() {
return $this->name;
}

public function getAge() {
return $this->age;
}

public function getPhones() {
return $this->phones;
}

public function setName($name) {
$this->name = $name;
}

public function setAge($age) {
$this->age = $age;
}

public function setPhones($phones) {
$this->phones = $phones;
}

}

<?php

namespace AppBundle\Controller;

use JMS\Serializer\Annotation\Type;

class Telephone {

/**
* @Type("string")
*/
private $phone;

public function getPhone() {
return $this->phone;
}

public function setPhone($phone) {
$this->phone = $phone;
}

}

1

Решение

Как я понимаю, когда ты это делаешь $this->get('serializer') вы получаете Компонент Symfony Serialization. Я не совсем знаком с этим (вы поймете, почему в галочке), но их документация показывает, как обрабатывать свойства объекта хотя только для сериализации.

Для типа контроля над вашим сериализованным представлением, который вы, похоже, ищете, я настоятельно рекомендую JMS сериализатор (а также связанный комплект), который дает вам более точный контроль над выводом через аннотации или внешние конфиги. В вашем случае делаете:

use JMS\Serializer\Annotation as Serializer;

class Person
{
/**
* @Serializer\Type("array<Telephone>")
*/
private $phones;

Этого может быть достаточно, чтобы получить двухстороннюю сериализацию, которую вы ищете.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]