Symfony 4.1: Melhorias no Componente Serializer
Adicionado um ConstraintViolationListNormalizer
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