Symfony 4.1: Melhorias no Componente Serializer

Adicionado um ConstraintViolationListNormalizer

Andréia Bohner
3 min readApr 21, 2018

Ao trabalhar em APIs com o Symfony, é comum usar código como este:

/**
* @Route("/blog/new", name="api_blog_new")
* @Method("POST")
* @Security("is_granted('ROLE_ADMIN')")
*/
public function new(Request $request, SerializerInterface $serializer, ValidatorInterface $validator)
{
$data = $request->getContent();
$post = $serializer->deserialize($data, Post::class, 'json', ['groups' => ['post_write']]);
$post->setAuthor($this->getUser());

$violations = $validator->validate($post);
if (count($violations) > 0) {
$repr = $serializer->serialize($violations, 'json');

return JsonResponse::fromJsonString($repr, 400);
}

// ...
}

A variável $violations contém um objeto ConstraintViolationList e é comum transformá-lo em uma lista de erros e serializar a lista para incluí-la em uma resposta JSON. É por isso que no Symfony 4.1 foi adicionado um ConstraintViolationListNormalizer que faz isso para você automaticamente. O normalizador segue a especificação RFC 7807 para gerar a lista de erros.

Obtendo resultados XML e CSV como uma coleção

O CsvEncoder e XmlEncoder agora definem uma nova opção de configuração chamada as_collection. Se você passar essa opção como parte do argumento de contexto e configurá-la como true, os resultados serão uma coleção.

Argumentos default do construtor para desnormalização

Se o construtor de uma classe define argumentos, como geralmente acontece ao usar Value Objects, o serializador não poderá criar o objeto. No Symfony 4.1, foi introduzida uma nova opção de contexto default_constructor_arguments para resolver esse problema.

No exemplo a seguir, foo e bar são argumentos de construtor necessários, mas apenas foo é fornecido. O valor de bar é obtido da opção default_constructor_arguments:

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

class MyObj
{
private $foo;
private $bar;

public function __construct($foo, $bar)
{
$this->foo = $foo;
$this->bar = $bar;
}
}

$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer(array($normalizer));

// this is equivalent to $data = new MyObj('Hello', '');
$data = $serializer->denormalize(['foo' => 'Hello'], 'MyObj', [
'default_constructor_arguments' => [
'MyObj' => ['foo' => '', 'bar' => ''],
]
]);

Adicionado um handler MaxDepth

Às vezes, em vez de apenas parar o processo de serialização quando max depth configurada é atingida, é melhor deixar o desenvolvedor lidar com essa situação para retornar algo (por exemplo, o identificador da entidade).

No Symfony 4.1 você pode resolver esse problema definindo um handler personalizado com o novo método setMaxDepthHandler():

use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Annotation\MaxDepth;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

class Foo
{
public $id;

/** @MaxDepth(1) */
public $child;
}

$level1 = new Foo();
$level1->id = 1;

$level2 = new Foo();
$level2->id = 2;
$level1->child = $level2;

$level3 = new Foo();
$level3->id = 3;
$level2->child = $level3;

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new ObjectNormalizer($classMetadataFactory);
$normalizer->setMaxDepthHandler(function ($foo) {
return '/foos/'.$foo->id;
});

$serializer = new Serializer(array($normalizer));
$result = $serializer->normalize($level1, null, array(ObjectNormalizer::ENABLE_MAX_DEPTH => true));
/*
$result = array[
'id' => 1,
'child' => [
'id' => 2,
'child' => '/foos/3',
]
];
*/

Ignore comentários ao decodificar XML

Nas versões anteriores do Symfony, os comentários XML eram processados ​​ao decodificar o conteúdo. Além disso, se a primeira linha do conteúdo XML fosse um comentário, ele seria usado como o nó raiz do XML decodificado.

No Symfony 4.1, os comentários XML são removidos por padrão, mas você pode controlar esse comportamento com o terceiro novo argumento opcional do construtor:

class XmlEncoder
{
public function __construct(
string $rootNodeName = 'response',
int $loadOptions = null,
array $ignoredNodeTypes = array(XML_PI_NODE, XML_COMMENT_NODE)
) {
// ...
}
}

Tradução de: New in Symfony 4.1: Serializer improvements

--

--