schmittjoh/serializer — pull request #306 by tmilos (2014-07-21 21:06:07+00:00)
Title: setter ignored in XmlDeserializationVisitor for xmlAttribute and xmlValue

If you mark a property with XmlAttribute and Accessor getter/setter, during serialization the getter method will be called, but during deserialization setter method is not called. Setter is also not called in case property has XmlValue annotation.

Example:

``` php
class Assertion
{
/**
* @var int
* @JMS\Type("string")
* @JMS\Accessor(getter="getIssueInstantString", setter="setIssueInstant")
* @JMS\SerializedName("IssueInstant")
* @JMS\XmlAttribute
*/
protected $issueInstant;

/**
* @return string
*/
public function getIssueInstantString()
{
return Helper::time2string($this->issueInstant);
}

/**
* @return string
*/
public function getIssueInstantTimestamp()
{
return $this->issueInstant;
}

/**
* @param string|int|\DateTime $issueInstant
* @throws \InvalidArgumentException
* @return $this|Assertion
*/
public function setIssueInstant($issueInstant)
{
if (is_string($issueInstant)) {
$this->issueInstant = Helper::parseSAMLTime($issueInstant);
} else if ($issueInstant instanceof \DateTime) {
$this->issueInstant = $issueInstant->getTimestamp();
} else if (is_int($issueInstant)) {
$this->issueInstant = $issueInstant;
} else {
throw new \InvalidArgumentException();
}
return $this;
}

}
```

XML for deserialization
``` xml

```

Test
``` php
class AssertionTest extends \PHPUnit_Framework_TestCase
{
public function testDeserialization()
{
$xml = <<

EOT;
AnnotationRegistry::registerLoader('class_exists');
$serializer = \JMS\Serializer\SerializerBuilder::create()->build();
$assertion = $serializer ->deserialize($xml, 'Assertion', 'xml');

// actual value is "2014-07-21T14:37:28Z" directly set by reflection, rather then setter method called
$this->assertEquals(1405953448, $assertion->getIssueInstantTimestamp());
}
```

Suggested fix:
Class ```JMS\Serializer\XmlDeserializationVisitor```
Method: ```visitProperty(...)```
When value ```$v``` is obtained do
``` php
if (null === $metadata->setter) {
$metadata->reflection->setValue($this->currentObject, $v);
return;
}
$this->currentObject->{$metadata->setter}($v);
```
instead of just
``` php
$metadata->reflection->setValue($this->currentObject, $v);
```
like it's done in the fallback on the end of that method.

Eventually, extract those few lines into separate method and prevent duplication of code.