1

Problem

I have the following object graph:

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
                )
        )
)

and the serialization using the following code from my controller:

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

and this gives me the following result:

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

The deserialization using the following code:

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

is giving the following back:

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
                )
        )
)

Question

First, is there a way to receive an xml as follows:

<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>

And second, how can I deserialize it back to an object graph (Person and Telephone), once using simple deserialize it returns an object person with an array of phones that holds an associative array instead of Telephone objects.

Model / Controller

Here my model / controller classes:

<?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;
    }

}

And my controller method:

/**
 * @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);

}

Solution using JMS Serializer

I was able to solve this issue with JMS Serializer by providing some hints to serializer using annotations (basically type and list details) as follows:

<?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 Answer 1

2

As I understand it, when you do $this->get('serializer') you're getting the Symfony Serialization component. I'm not entirely familiar with it (you'll see why in a tick) but their documentation does highlight how to handle object properties though only for serialization.

For the type of control over your serialized view that you seem to be looking for, I would strongly suggest JMS serializer (and associated bundle) which gives you finer grained control over the output via annotations or external configs. In your case, doing:

use JMS\Serializer\Annotation as Serializer;

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

Might be enough to get the two way serialization you're looking for.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks for your answer, and in fact it worked using JMS Serialization, but was curious about symfony2 serializer, if it couldn't be used to solve this problem.
For a lot of situations the Symfony serializer is perfectly serviceable, especially if you're only serializing (rather than deserializing) objects - i.e. sending JSON via an API. But as far as I know there's no way of doing complex transforms with it in the way that the JMS serializer allows and which you would need to make your example work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.