Nuevo en Symfony 2.7: Mejoras en el componente Serializer

El componente Serializer de Symfony es probablemente el que menos ha evolucionado desde que se presentó. El motivo es que sus autores querían que limitar sus funcionalidades para que fuera sencillo de usar. Además, el JMS Serializer usado por muchos programadores Symfony era la mejor alternativa cuando el componente Serializer se te quedaba corto.

Sin embargo, en Symfony 2.7 todo lo anterior ha cambiado. Debido a una incompatibilidad de licencias, ya no se conseja usar el JMS Serializer en las aplicaciones Symfony. Por ese motivo, han empezado a actualizar el componente Serializer para añadirle todas las funcionalidades que le faltan en comparación con el otro.

Soporte para definir grupos de serialización

Imagina que dispones de la siguiente clase PHP:

class Product
{
    public $itemsSold;
    public $commission;
    public $price;
}

Si serializas objetos de esta clase, se incluirán todas sus propiedades. Esto puede ser un problema cuando alguna de las propiedades sólo debe ser vista por los administradores o por las empresas afiliadas.

Así que ahora puedes definir grupos de serialización de manera que sólo se incluyan cada vez las propiedades adecuadas:

use Symfony\Component\Serializer\Annotation\Groups;
 
class Product
{
    /**
     * @Groups({"admins"})
     */
    public $itemsSold;
 
    /**
     * @Groups({"admins", "affiliates"})
     */
    public $commission;
 
    /**
     * @Groups({"admins", "affiliates", "users"})
     */
    public $price;
}

Si pruebas a serializar la información indicando un grupo específico, el resultado será diferente cada vez:

$data = $serializer->normalize($product, null, ['groups' => ['admins']]);
// $data = ['itemsSold' => 20, 'commission' => 7.5, 'price' => 19.99];
 
$data = $serializer->normalize($product, null, ['groups' => ['affiliates']]);
// $data = ['comission' => 7.5, 'price' => 19.99];
 
$data = $serializer->normalize($product, null, ['groups' => ['users']]);
// $data = ['price' => 19.99];

Para definir los grupos mediante anotaciones, activa primero esta opción de configuración:

# app/config/services.yml
framework:
    # ...
    serializer: { enable_annotations: true }

Si no quieres usar anotaciones, la misma configuración se puede definir en archivos YAML y XML.

El nuevo ObjectNormalizer

Symfony 2.6 incluye dos tipos de normalizadores: GetSetMethodNormalizer y PropertyNormalizer. Symfony 2.7 añade un nuevo normalizador llamado ObjectNormalizer. Su principal ventaja sobre los anteriores es que puede trabajar con propiedades protegidas/privadas y también con propiedades que sólo definen getters o issers:

class MyObject
{
    public $foo = 'foo';
 
    public getBar()
    {
       return 'bar';
    }
 
    public isBaz()
    {
        return true;
    }
}

Las propiedades bar y baz no está definidas como propiedades, pero el nuevo normalizador entiende tu código correctamente:

use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
 
$normalizer = new ObjectNormalizer();
$result = $normalizer->normalize(new MyObject());
// $result = ['foo' => 'foo', 'bar' => 'bar', 'baz' => true]

Posibilidad de cambiar el nombre de las propiedades

Si tus propiedades utilizan la sintaxis snake case (ejemplo: $first_name) en vez del camel case (ejemplo: $firstName) es posible que te encuentres con errores al serializar la información. Por ejemplo, el getter de la propiedad $first_name se llama getFirstName() y el serializador busca un getter llamado getFirst_name().

Para evitar estos problemas, en Symfony 2.7 se ha introducido un conversor general que permite realizar cualquier transformación entre nombre de propiedad y nombre de getter. El único conversor incluído por defecto convierte snake case en camel case y viceversa:

use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
 
// ...
$nameConverter = new CamelCaseToSnakeCaseNameConverter(array('first_name'));
$normalizer = new GetSetMethodNormalizer(null, $nameConverter);
$serializer = new Serializer(array($normalizer), array($encoder));

Deserializar en un objeto existente

Cuando deserializas información lo habitual es crear un nuevo objeto en el que guardar esa información. En Symfony 2.7 también puedes deserializarla en un objeto existente. Esto puede ser útil por ejemplo para obtener un objeto con Doctrine y después actualizarlo con la información deserializada:

$existingProduct = $this->getDoctrine()->...
 
$product = $this->normalizer->denormalize(
    array('bar' => 'bar'),
    'AppBundle\\Entity\\Product',
    null,
    array('object_to_populate' => $existingProduct)
);
 
// $product y $existingProduct son referencia al mismo objeto

DunglasJsonLdApiBundle

Para ver en acción todas estas nuevas funcionalidades del componente Serializer, Kévin Dunglas ha creado un bundle llamado DunglasJsonLdApiBundle que permite desarrollar APIs con soporte de JSON-LD e Hydra utilizando el componente Serializer. component.

Todas estas nuevas funcionalidades han sido desarrolladas por Kévin Dunglas y puedes ver los detalles en los siguientes pull requests de Symfony: #12092, #13257, #13120 y #13252.

Comentarios

Este artículo ya no permite añadir más comentarios.
¿Por qué? Los artículos cierran sus comentarios automáticamente unos meses después de su publicación para asegurar que estos sigan siendo relevantes.

Publicada el

14 de abril de 2015

Etiquetas

Proyectos Symfony destacados

La plataforma de eCommerce 100% Symfony que rivaliza con Magento y PrestaShop. Ver más

Síguenos en @symfony_es para acceder a las últimas noticias.