symfony/symfony — pull request #3562 by tvlooy (2012-03-11 16:36:11+00:00)
Title: prevent infinite loops when normalizing with GetSetMethodNormalizer

I would like to use the GetSetMethodNormalizer on an entity array. The problem is that the entities refer to each other. So, there is an infinite loop when normalising. To solve this, I created an annotation 'NoNormalizer', than I can add on my entity's get methods when I don't want them to be normalized. The GetSetNormalizer checks for this annotation.

My (stripped down) entity, to demonstrate the concept:
```
use Symfony\Component\Serializer\Normalizer as NormalizerStrategy;
class Author
{
/**
* Get books
* @NormalizerStrategy\NoNormalizer
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getBooks()
{
return $this->books;
}
}
```

This solves my problem. What do you thing of this solution?

In addition, I was thinking about changing 'NoNormalizer' into a 'NormalizerStrategy' that has a type property. For example 'none' (which skips the getter), 'lazy' (which does a getId() on the returned value). This is not in this pull request yet. But again, to show you an example of 'lazy':

use Symfony\Component\Serializer\Normalizer\NormalizerStrategy;
class Book
{
/**
* Get author
* @NormalizerStrategy(type="lazy")
*
* @return Author
*/
public function getAuthor()
{
return $this->author;
}
}
```
The GetSetMethodNormalizer would look something like this:
```
foreach ($reflectionMethods as $method) {
if ($this->isGetMethod($method)) {
$attributeName = strtolower(substr($method->getName(), 3));

$attributeValue = $method->invoke($object);
if (null !== $attributeValue) {
$annotation = $reader->getMethodAnnotation(
$method,
'Symfony\Component\Serializer\Normalizer\NoNormalizer'
);
if ($annotation !== NULL) {
switch ($annotation->type) {
case 'lazy':
$attributeValue = $attributeValue->getId();
break;
case 'none':
continue 2;
} else if (!is_scalar($attributeValue)) {
$attributeValue = $this->serializer->normalize($attributeValue, $format);
}
}

$attributes[$attributeName] = $attributeValue;
}
```