title: How do I add/update xml attributes with Symfony Serializer using my class/object?
body: <p>I have the following code example which defines a Contact class that can hold a name and a list of phone numbers. What I want to be able to do is set an attribute of "primary" on all the numbers, where the value for it is '1' for one of them arbitrarily, and '0' for the rest.</p>
  
  <p>I'd really like to do this using a class method but couldn't find a way to do this using a setter - is it possible somehow? </p>
  
  <p>Here's my code. In it I:</p>
  
  <ol>
  <li>Create my objects and set their properies</li>
  <li>print_r the Contact object to see how it is stored </li>
  <li>Deserialize the xml that I'd like to be able to generate into the
  same Contact object</li>
  <li>print_r the Contact object to see how it is stored </li>
  <li>Add another number using setter</li>
  <li>print_r the Contact object to see how it is stored </li>
  <li>Serialize to xml and see how the mixture of objects and arrays are treated</li>
  <li>print the xml</li>
  </ol>
  
  <hr>
  
  <pre><code>&lt;?php
  // Symfony Serializer experiment  
  
  require $_SERVER['DOCUMENT_ROOT'].'/libraries/symfony/vendor/autoload.php';
  
  use Symfony\Component\Serializer\Serializer;
  use Symfony\Component\Serializer\Encoder\XmlEncoder;
  use Symfony\Component\Serializer\Encoder\JsonEncoder;
  use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
  use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
  
  Class Number { 
      private $Number;
      private $Type;
      // Getters    
      public function getNumber()
      {
          return $this-&gt;Number;
      }
      public function getType()
      {
          return $this-&gt;Type;
      }     
      // Setters    
      public function setNumber($number)
      {
          $this-&gt;Number = $number;
  
          return $this;
      } 
      public function setType($type)
      {
          $this-&gt;Type = $type;
  
          return $this;
      }                 
  } 
  
  class Contact
  {
      private $Name;
      private $Numbers = array();
  
      function __construct() {
          ${@Primary} = 0;    
      }
  
      // Getters
      public function getName()
      {
          return $this-&gt;Name;
      }
      public function getNumbers()
      {
          return $this-&gt;Numbers;
      }  
      // Setters
      public function setName($name)
      {
          $this-&gt;Name = $name;
  
          return $this;        
      }
      public function setNumbers($numbers)
      {
          $this-&gt;Numbers = $numbers;
  
          return $this;        
      }
      public function addNumber($number) {
          $this-&gt;Numbers['Number'][] = $number;
      }    
  }
  
  // Serializer setup
  
  $xmlEncoder = new XmlEncoder();
  $xmlEncoder-&gt;setRootNodeName('Contact');                
  $encoders = array($xmlEncoder, new JsonEncoder());
  $normalizers = array(new ObjectNormalizer());
  $serializer = new Serializer($normalizers, $encoders);
  
  // Create my object
  
  $contact = new Contact();
  $contact-&gt;setName('baa');
  $number = new Number();
  $number-&gt;setNumber('07878386123')-&gt;setType('Mobile');
  $contact-&gt;addNumber($number);
  
  // take a look at how it's stored
  
  echo "&lt;pre lang=xml&gt;";
  print_r($contact);
  echo "&lt;/pre&gt;&lt;br&gt;&lt;br&gt;";
  
  // deserialize my desired xml into the same object
  
  $data = &lt;&lt;&lt;EOF
  &lt;Contact&gt;
      &lt;Name&gt;foo&lt;/Name&gt;
      &lt;Numbers&gt;
          &lt;Number primary='1'&gt;
              &lt;Number&gt;07878386459&lt;/Number&gt;
              &lt;Type&gt;Mobile&lt;/Type&gt;
          &lt;/Number&gt;    
          &lt;Number primary='0'&gt;
              &lt;Number&gt;02380860835&lt;/Number&gt;
              &lt;Type&gt;Landline&lt;/Type&gt;
          &lt;/Number&gt;            
      &lt;/Numbers&gt;        
  &lt;/Contact&gt;
  EOF;
  
  $contact = $serializer-&gt;deserialize($data, Contact::class, 'xml', array('object_to_populate' =&gt; $contact));
  
  // take a look at how it's stored
  
  echo "&lt;pre lang=xml&gt;";
  print_r($contact);
  echo "&lt;/pre&gt;&lt;br&gt;&lt;br&gt;";
  
  // Add another number
  
  $number = new Number();
  $number-&gt;setNumber('02387345123')-&gt;setType('Landline');
  $contact-&gt;addNumber($number);
  
  // take a look at how it's stored
  
  echo "&lt;pre lang=xml&gt;";
  print_r($contact);
  echo "&lt;/pre&gt;&lt;br&gt;&lt;br&gt;";
  
  // serialize  to xml and see how the mixture of objects and arrays are treated
  
  $xmlContent = $serializer-&gt;serialize($contact, 'xml');
  
  $dom = new domDocument( '1.0', 'utf-8' );
  $dom-&gt;preserveWhiteSpace = false;
  $dom-&gt;formatOutput = true;
  $result = $dom-&gt;loadXML($xmlContent);
  $xmlContentFormatted=htmlentities($dom-&gt;saveXML());
  ?&gt;
  &lt;pre lang=xml&gt;&lt;?= $xmlContentFormatted ?&gt;&lt;/pre&gt;
  </code></pre>
  
  <p>What I see in the output is:</p>
  
  <p>2)</p>
  
  <pre><code>Contact Object
  (
      [Name:Contact:private] =&gt; baa
      [Numbers:Contact:private] =&gt; Array
          (
              [Number] =&gt; Array
                  (
                      [0] =&gt; Number Object
                          (
                              [Number:Number:private] =&gt; 07878386123
                              [Type:Number:private] =&gt; Mobile
                          )   
                  )   
          )   
  )
  </code></pre>
  
  <p>4)  </p>
  
  <pre><code>Contact Object
  (
      [Name:Contact:private] =&gt; foo
      [Numbers:Contact:private] =&gt; Array
          (
              [Number] =&gt; Array
                  (
                      [0] =&gt; Array
                          (
                              [@primary] =&gt; 1
                              [Number] =&gt; 07878386459
                              [Type] =&gt; Mobile
                          )    
                      [1] =&gt; Array
                          (
                              [@primary] =&gt; 0
                              [Number] =&gt; 02380860835
                              [Type] =&gt; Landline
                          )   
                  )   
  
  )
  </code></pre>
  
  <p>6) Mixture of objects and arrays. Could I code my Number class so that it uses an array rather than properties and have another method for setting attribute? (eg </p>
  
  <pre><code>$number-&gt;setNumber('07878386123')-&gt;setType('Mobile')-&gt;addAttr(array('primary' =&gt; '1'));
  
  Contact Object
  (
      [Name:Contact:private] =&gt; foo
      [Numbers:Contact:private] =&gt; Array
          (
              [Number] =&gt; Array
                  (
                      [0] =&gt; Array
                          (
                              [@primary] =&gt; 1
                              [Number] =&gt; 07878386459
                              [Type] =&gt; Mobile
                          )    
                      [1] =&gt; Array
                          (
                              [@primary] =&gt; 0
                              [Number] =&gt; 02380860835
                              [Type] =&gt; Landline
                          )
  
                      [2] =&gt; Number Object
                          (
                              [Number:Number:private] =&gt; 02387345123
                              [Type:Number:private] =&gt; Landline
                          )    
                  )    
          )    
  )    
  </code></pre>
  
  <p>8)</p>
  
  <pre><code>&lt;?xml version="1.0"?&gt;
  &lt;Contact&gt;
    &lt;Name&gt;foo&lt;/Name&gt;
    &lt;Numbers&gt;
      &lt;Number primary="1"&gt;
        &lt;Number&gt;07878386459&lt;/Number&gt;
        &lt;Type&gt;Mobile&lt;/Type&gt;
      &lt;/Number&gt;
      &lt;Number primary="0"&gt;
        &lt;Number&gt;02380860835&lt;/Number&gt;
        &lt;Type&gt;Landline&lt;/Type&gt;
      &lt;/Number&gt;
      &lt;Number&gt;
        &lt;Number&gt;02387345123&lt;/Number&gt;
        &lt;Type&gt;Landline&lt;/Type&gt;
      &lt;/Number&gt;
    &lt;/Numbers&gt;
  &lt;/Contact&gt;
  </code></pre>
  
  <p>When deserializing from XML that has tags that use attributes, the php objects use arrays, so it would appear that if you want to start out with a php representation that can be given attributes you need to use arrays.</p>