Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Trabajo en Limenius Ofrecemos formación, consultoría y desarrollo a empresas Trabajamos con Symfony y React No hay proyecto que no tenga una API El serializador es uno de tus mejores amigos al implementar una API Victoria Quirante @vicqr [email protected]

Slide 4

Slide 4 text

INTRODUCCIÓN De qué va todo esto http://www.flickr.com/photos/lilianasaeb/16463233379

Slide 5

Slide 5 text

¿Qué es serializar?

Slide 6

Slide 6 text

@vicqr Serialización Es el proceso de codificación de un objeto en otro formato que puede ser almacenado, transmitido y posteriormente descodificado

Slide 7

Slide 7 text

@vicqr Serialización Es el proceso de codificación de un objeto en otro formato que puede ser almacenado, transmitido y posteriormente descodificado OBJETOS REPRESENTACIONES (JSON, XML..)

Slide 8

Slide 8 text

@vicqr Serialización Es el proceso de codificación de un objeto en otro formato que puede ser almacenado, transmitido y posteriormente descodificado OBJETOS REPRESENTACIONES (JSON, XML..) Serialización

Slide 9

Slide 9 text

@vicqr Serialización Es el proceso de codificación de un objeto en otro formato que puede ser almacenado, transmitido y posteriormente descodificado OBJETOS REPRESENTACIONES (JSON, XML..) Serialización Deserialización

Slide 10

Slide 10 text

@vicqr Ejemplo de serialización $responseData = [ 'id' => $spaceship->getId(), 'name' => $spaceship->getName(), 'color' => $spaceship->getColor(), 'maxSpeed' => $spaceship->getMaxSpeed(), ]; $response = new JsonResponse($responseData, 201); Nuestro objeto -> La response (serialización manual)

Slide 11

Slide 11 text

@vicqr Ejemplo de serialización $responseData = [ 'id' => $spaceship->getId(), 'name' => $spaceship->getName(), 'color' => $spaceship->getColor(), 'maxSpeed' => $spaceship->getMaxSpeed(), ]; $response = new JsonResponse($responseData, 201); ... ... $spaceship = new Spaceship(); $spaceship->setName($content['name']); $spaceship->setColor($content['color']); $spaceship->setMaxSpeed($content['maxSpeed']); Nuestro objeto -> La response (serialización manual) La request -> Nuestro objeto (deserialización manual)

Slide 12

Slide 12 text

@vicqr Ejemplo de serialización $responseData = [ 'id' => $spaceship->getId(), 'name' => $spaceship->getName(), 'color' => $spaceship->getColor(), 'maxSpeed' => $spaceship->getMaxSpeed(), ]; $response = new JsonResponse($responseData, 201); ... ... $spaceship = new Spaceship(); $spaceship->setName($content['name']); $spaceship->setColor($content['color']); $spaceship->setMaxSpeed($content['maxSpeed']); Apasionante :_( Nuestro objeto -> La response (serialización manual) La request -> Nuestro objeto (deserialización manual)

Slide 13

Slide 13 text

@vicqr Serialización con serializador $responseData = [ 'id' => $spaceship->getId(), 'name' => $spaceship->getName(), 'color' => $spaceship->getColor(), 'maxSpeed' => $spaceship->getMaxSpeed(), ]; $response = new JsonResponse($responseData, 201); Convirtiendo nuestro objeto en una Response en JSON

Slide 14

Slide 14 text

@vicqr Serialización con serializador $responseData = [ 'id' => $spaceship->getId(), 'name' => $spaceship->getName(), 'color' => $spaceship->getColor(), 'maxSpeed' => $spaceship->getMaxSpeed(), ]; $response = new JsonResponse($responseData, 201); -------------- $response = new Response($serializer->serialize($spaceship, 'json'), 201); Convirtiendo nuestro objeto en una Response en JSON

Slide 15

Slide 15 text

@vicqr Deserialización con serializador $spaceship = new Spaceship(); $spaceship->setName($content['name']); $spaceship->setColor($content['color']); $spaceship->setMaxSpeed($content['maxSpeed']); Convirtiendo el contenido de la Request (JSON) en un objeto

Slide 16

Slide 16 text

@vicqr Deserialización con serializador $spaceship = new Spaceship(); $spaceship->setName($content['name']); $spaceship->setColor($content['color']); $spaceship->setMaxSpeed($content['maxSpeed']); ------------------ $spaceship = $serializer->deserialize($content, Spaceship::class, 'json'); Convirtiendo el contenido de la Request (JSON) en un objeto

Slide 17

Slide 17 text

¿A qué llamamos serializador?

Slide 18

Slide 18 text

@vicqr El serializador Es un código que es muy bueno serializando por nosotros

Slide 19

Slide 19 text

@vicqr El serializador Es un código que es muy bueno serializando por nosotros

Slide 20

Slide 20 text

El verdadero problema que nos ayuda a resolver

Slide 21

Slide 21 text

Los objetos y las representaciones que queremos pueden ser muy distintos

Slide 22

Slide 22 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } }

Slide 23

Slide 23 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission”

Slide 24

Slide 24 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission” No quiero mostrarlo

Slide 25

Slide 25 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission” No quiero mostrarlo No quiero mostrarlo en el list

Slide 26

Slide 26 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission” No quiero mostrarlo No quiero mostrarlo en el list Quiero añadir “thumb_”

Slide 27

Slide 27 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission” No quiero mostrarlo No quiero mostrarlo en el list Quiero añadir “thumb_” Solo en la versión 2 de la API

Slide 28

Slide 28 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission” No quiero mostrarlo No quiero mostrarlo en el list Quiero añadir “thumb_” Solo en la versión 2 de la API Quiero que sea un campo más

Slide 29

Slide 29 text

@vicqr Representaciones != lo que hay en la BD { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission” No quiero mostrarlo No quiero mostrarlo en el list Quiero añadir “thumb_” Solo en la versión 2 de la API Quiero que sea un campo más Con este tipo de cosas es con lo que va a ayudarnos un serializador

Slide 30

Slide 30 text

VISTAZO GENERAL A ambas soluciones

Slide 31

Slide 31 text

@vicqr Datos básicos JMSSERIALIZERBUNDLE SYMFONY SERIALIZER

Slide 32

Slide 32 text

@vicqr Datos básicos JMSSERIALIZERBUNDLE - Es un bundle (y librería, claro) - Creado por @schmittjoh - Se comenzó en abril de 2011 - Pasó época de poco mantenimiento - Desde hace un año mejor (@goetas_asmir) - Licencia Apache SYMFONY SERIALIZER

Slide 33

Slide 33 text

@vicqr Datos básicos JMSSERIALIZERBUNDLE SYMFONY SERIALIZER - Es un bundle (y librería, claro) - Creado por @schmittjoh - Se comenzó en abril de 2011 - Pasó época de poco mantenimiento - Desde hace un año mejor (@goetas_asmir) - Licencia Apache - Es un Symfony Component - Desarrollado por los core - Se comenzó en enero de 2011 - Se le criticaba que “le faltan muchas cosas” - En continua evolución y mejora - Licencia MIT

Slide 34

Slide 34 text

@vicqr Inciso: componentes y bundles - Componente -> librería desacoplada y reutilizable - Bundle -> atado al Symfony Framework

Slide 35

Slide 35 text

@vicqr Inciso: componentes y bundles - Componente -> librería desacoplada y reutilizable - Bundle -> atado al Symfony Framework A menudo tenemos: Funcionalidad Librería Integración con SF Configuración Inyección de dependencias Bundle +

Slide 36

Slide 36 text

@vicqr Inciso: componentes y bundles - Componente -> librería desacoplada y reutilizable - Bundle -> atado al Symfony Framework A menudo tenemos: Por ejemplo, en el caso del JMSSerializerBundle Funcionalidad Librería Integración con SF Configuración Inyección de dependencias Bundle +

Slide 37

Slide 37 text

@vicqr JMSSerialiazerBundle - Características - Muchas anotaciones útiles que cubren casos de uso muy frecuentes - Muy sencillo empezar a utilizarlo

Slide 38

Slide 38 text

@vicqr JMSSerialiazer - Instalación y setup - Instalación: - composer require - Registrar el bundle http://jmsyst.com/bundles/JMSSerializerBundle

Slide 39

Slide 39 text

@vicqr JMSSerialiazer - Instalación y setup - Instalación: - composer require - Registrar el bundle - Setup: no hay que hacer nada para empezar a usarlo http://jmsyst.com/bundles/JMSSerializerBundle

Slide 40

Slide 40 text

@vicqr Componente Serializer - Características - No aspira a resolver casos de uso concretos sino a proporcionar una arquitectura que te permita hacerlo - Menos “ya hecho”, más flexible Aproximación diferente

Slide 41

Slide 41 text

@vicqr Componente Serializer - Características

Slide 42

Slide 42 text

@vicqr Componente Serializer - Características El trabajo más complejo se lleva a cabo en los normalizadores

Slide 43

Slide 43 text

@vicqr SF Serializer - Instalación y setup - Instalación: - composer require - Si quieres usar ObjectNormalizer instalas también PropertyAccess

Slide 44

Slide 44 text

@vicqr SF Serializer - Instalación y setup - Instalación: - composer require - Si quieres usar ObjectNormalizer instalas también PropertyAccess - Setup: hay que hacer algunas cosas

Slide 45

Slide 45 text

@vicqr Componente Serializer - Setup use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; $encoders = array(new XmlEncoder(), new JsonEncoder()); $normalizers = array(new ObjectNormalizer()); serializer = new Serializer($normalizers, $encoders);

Slide 46

Slide 46 text

@vicqr Componente Serializer - Setup use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; $encoders = array(new XmlEncoder(), new JsonEncoder()); $normalizers = array(new ObjectNormalizer()); serializer = new Serializer($normalizers, $encoders); El ObjectNormalizer es muy potente, pero no idóneo para todos los casos

Slide 47

Slide 47 text

TRABAJANDO CON AMBOS Serialicemos algo fácil

Slide 48

Slide 48 text

http://github.com/VictoriaQ/sf-serialization-talk

Slide 49

Slide 49 text

@vicqr JMSSerialiazerBundle - Deserialización # AppBundle/Controller/Api/SpaceshipController.php /** * @Route("/api/spaceships") * @Method("POST") */ public function newAction(Request $request) { $serializer = $this->container->get('jms_serializer'); $spaceship = $serializer->deserialize($request->getContent(), Spaceship::class, 'json'); $em = $this->getDoctrine()->getManager(); $em->persist($spaceship); $em->flush(); return new Response("Spaceship created!"); }

Slide 50

Slide 50 text

@vicqr JMSSerialiazerBundle - Deserialización # AppBundle/Controller/Api/SpaceshipController.php /** * @Route("/api/spaceships") * @Method("POST") */ public function newAction(Request $request) { $serializer = $this->container->get('jms_serializer'); $spaceship = $serializer->deserialize($request->getContent(), Spaceship::class, 'json'); $em = $this->getDoctrine()->getManager(); $em->persist($spaceship); $em->flush(); return new Response("Spaceship created!"); }

Slide 51

Slide 51 text

@vicqr JMSSerialiazerBundle - Serialización # AppBundle/Controller/Api/SpaceshipController.php /** * @Route("/api/spaceships/{name}") * @Method("GET") */ public function showAction($name) { $spaceship = $this->getDoctrine() ->getRepository('AppBundle:Spaceship') ->findOneByName($name); $serializer = $this->container->get('jms_serializer'); return new Response($serializer->serialize($spaceship, 'json'), 200); }

Slide 52

Slide 52 text

@vicqr JMSSerialiazerBundle - Serialización # AppBundle/Controller/Api/SpaceshipController.php /** * @Route("/api/spaceships/{name}") * @Method("GET") */ public function showAction($name) { $spaceship = $this->getDoctrine() ->getRepository('AppBundle:Spaceship') ->findOneByName($name); $serializer = $this->container->get('jms_serializer'); return new Response($serializer->serialize($spaceship, 'json'), 200); }

Slide 53

Slide 53 text

@vicqr JMSSerialiazerBundle - Serialización HTTP/1.1 200 OK Host: localhost:8000 Connection: close X-Powered-By: PHP/7.1.0-0ubuntu0.16.04.4 Cache-Control: no-cache, private Date: Sat, 24 Jun 2017 17:45:32 GMT Content-Type: application/json X-Debug-Token: 127f2b X-Debug-Token-Link: http://localhost:8000/_profiler/127f2b {"id":1,"name":"Orion","color":"Razzmic Berry","maxSpeed":8900}

Slide 54

Slide 54 text

@vicqr Componente Serializer - Deserialización # AppBundle/Controller/Api/SpaceshipController.php /** * @Route("/api/spaceships") * @Method("POST") */ public function newAction(Request $request) { $encoders = array(new JsonEncoder()); $normalizers = array(new ObjectNormalizer()); $serializer = new Serializer($normalizers, $encoders); $spaceship = $serializer->deserialize($request->getContent(), Spaceship::class, 'json'); $em = $this->getDoctrine()->getManager(); $em->persist($spaceship); $em->flush(); return new Response("Spaceship created!"); }

Slide 55

Slide 55 text

@vicqr Componente Serializer - Deserialización # AppBundle/Controller/Api/SpaceshipController.php /** * @Route("/api/spaceships") * @Method("POST") */ public function newAction(Request $request) { $encoders = array(new JsonEncoder()); $normalizers = array(new ObjectNormalizer()); $serializer = new Serializer($normalizers, $encoders); $spaceship = $serializer->deserialize($request->getContent(), Spaceship::class, 'json'); $em = $this->getDoctrine()->getManager(); $em->persist($spaceship); $em->flush(); return new Response("Spaceship created!"); }

Slide 56

Slide 56 text

@vicqr Deserializar un objeto ya existente # AppBundle/Controller/Api/SpaceshipController.php $serializer->deserialize($request->getContent(), Spaceship::class, 'json', array('object_to_populate' => $spaceship));

Slide 57

Slide 57 text

@vicqr Componente Serializer - Serialización # AppBundle/Controller/Api/SpaceshipController.php /** * @Route("/api/spaceships/{name}") * @Method("GET") */ public function showAction($name) { $encoders = array(new JsonEncoder()); $normalizers = array(new ObjectNormalizer()); $serializer = new Serializer($normalizers, $encoders); $spaceship = $this->getDoctrine() ->getRepository('AppBundle:Spaceship') ->findOneByName($name); return new Response($serializer->serialize($spaceship, 'json'), 200); }

Slide 58

Slide 58 text

@vicqr Comparación inicial Algo de instalación -mínimo- el bundle Algo más de configuración el componente En general, para este tipo de ejemplo, idéntico uso

Slide 59

Slide 59 text

@vicqr Comparación inicial Algo de instalación -mínimo- el bundle Algo más de configuración el componente En general, para este tipo de ejemplo, idéntico uso Pero este tipo de ejemplo no existe

Slide 60

Slide 60 text

JMSSERIALIZERBUNDLE EN DETALLE http://www.flickr.com/photos/florianric/7263382550

Slide 61

Slide 61 text

@vicqr JMSSerializerBundle Tres estrategias de exclusión (Exclude, Groups, Versions) Propiedades configurables (Virtual Props., Accessors) Eventos para más flexibilidad XML muy configurable Muchas funcionalidades que necesitas siempre listas para usar

Slide 62

Slide 62 text

@vicqr Estrategias de exclusión - Estrategias generales: @ExclusionPolicy (all, none), @Exclude, @Expose

Slide 63

Slide 63 text

@vicqr Estrategias de exclusión - Estrategias generales: @ExclusionPolicy (all, none), @Exclude, @Expose - Versiones: @Until, @Since

Slide 64

Slide 64 text

@vicqr Estrategias de exclusión - Estrategias generales: @ExclusionPolicy (all, none), @Exclude, @Expose - Versiones: @Until, @Since - Diferentes vistas de un objeto: @Groups

Slide 65

Slide 65 text

@vicqr Estrategias de exclusión - Estrategias generales: @ExclusionPolicy (all, none), @Exclude, @Expose - Versiones: @Until, @Since - Diferentes vistas de un objeto: @Groups - Limitar nivel de serialización en el grafo: @MaxDepth

Slide 66

Slide 66 text

@vicqr Estrategias de exclusión - Estrategias generales: @ExclusionPolicy (all, none), @Exclude, @Expose - Versiones: @Until, @Since - Diferentes vistas de un objeto: @Groups - Limitar nivel de serialización en el grafo: @MaxDepth - Exclusión dinámica: @Exclude(if=”...”)

Slide 67

Slide 67 text

@vicqr Estrategias de exclusión - Estrategias generales: @ExclusionPolicy (all, none), @Exclude, @Expose - Versiones: @Until, @Since - Diferentes vistas de un objeto: @Groups - Limitar nivel de serialización en el grafo: @MaxDepth - Exclusión dinámica: @Exclude(if=”...”) Muchas formas de indicar qué propiedades muestras y cuáles no

Slide 68

Slide 68 text

@vicqr Propiedades configurables - Cambiar nombre de una propiedad: @SerializedName - Crear propiedades virtuales: @VirtualProperty

Slide 69

Slide 69 text

@vicqr Propiedades configurables - Cambiar nombre de una propiedad: @SerializedName - Crear propiedades virtuales: @VirtualProperty Sencillo cambiar lo que tengo por defecto en las propiedades

Slide 70

Slide 70 text

@vicqr Accessors - De qué modo hay que acceder las propiedades: @AccessorType - Qué método hay que utilizar para acceder una propiedad: @Accessor - En qué orden hay que acceder las propiedades: @AccessorOrder

Slide 71

Slide 71 text

@vicqr Accessors - De qué modo hay que acceder las propiedades: @AccessorType - Qué método hay que utilizar para acceder una propiedad: @Accessor - En qué orden hay que acceder las propiedades: @AccessorOrder Sencillo configurar el acceso a las propiedades

Slide 72

Slide 72 text

@vicqr XML muy configurable - @XmlRoot - @XmlAttribute - @XmlDiscriminator - @XmlValue - @XmlList - @XmlMap - @XmlKeyValuePairs - @XmlAttributeMap - @XmlElement - @XmlNamespace

Slide 73

Slide 73 text

@vicqr XML muy configurable - @XmlRoot - @XmlAttribute - @XmlDiscriminator - @XmlValue - @XmlList - @XmlMap - @XmlKeyValuePairs - @XmlAttributeMap - @XmlElement - @XmlNamespace Hay consenso en que para trabajar con XML es estupendo

Slide 74

Slide 74 text

@vicqr Eventos para mayor customización - serializer.pre_serialize - serializer.post_serialize - serializer.pre_deserialize - serializer.post_deserialize

Slide 75

Slide 75 text

@vicqr Eventos para mayor customización - serializer.pre_serialize - serializer.post_serialize - serializer.pre_deserialize - serializer.post_deserialize Por ej., para utilizar un servicio (al que no puedes llamar desde la Entidad) http://knpuniversity.com/screencast/symfony-rest3/serialization-event-subscriber

Slide 76

Slide 76 text

@vicqr Suscribers Los eventos tienen un getVisitor() El visitor es el encargado del proceso de serialización Utilizando $visitor->addData() podemos añadir los campos que queramos

Slide 77

Slide 77 text

@vicqr Suscribers Los eventos tienen un getVisitor() El visitor es el encargado del proceso de serialización Utilizando $visitor->addData() podemos añadir los campos que queramos Esta forma de trabajar no encaja mucho con la filosofía del componente Serializer

Slide 78

Slide 78 text

@vicqr Deserializando objetos complejos Utilizamos la anotación @Type para que el serializer sepa qué objeto es cada uno

Slide 79

Slide 79 text

@vicqr Algún detalle que viene bien saber - Hay que solucionar el problema del underscore # app/config/config.yml parameters: jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy

Slide 80

Slide 80 text

@vicqr Algún detalle que viene bien saber - Hay que solucionar el problema del underscore # app/config/config.yml parameters: jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy https://knpuniversity.com/screencast/symfony-rest

Slide 81

Slide 81 text

@vicqr Algún detalle que viene bien saber - Hay que solucionar el problema del underscore # app/config/config.yml parameters: jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy - Los campos null por defecto no se serializan # src/AppBundle/Controller/Api/SpaceshipController.php $context = new SerializationContext(); $context->setSerializeNull(true); return $this->container->get('jms_serializer')->serialize($data, $format, $context); https://knpuniversity.com/screencast/symfony-rest

Slide 82

Slide 82 text

@vicqr Críticas y elogios frecuentes - Problema licencia - Mantenimiento regular - Modelo “caja de herramientas”

Slide 83

Slide 83 text

@vicqr Críticas y elogios frecuentes - Problema licencia - Mantenimiento regular - Modelo “caja de herramientas” - Fácil de usar - Permite resolver problemas muy habituales muy cómodamente

Slide 84

Slide 84 text

COMPONENTE SERIALIZER EN DETALLE

Slide 85

Slide 85 text

@vicqr Componente Serializer No pretende darte soluciones ya hechas para todo Solo dos anotaciones (MaxDepth y Groups) Te proporciona algunos normalizadores muy útiles Va mucho de crear tus propios normalizadores Arquitectura potente y flexible que te permite exportar tus estructuras PHP

Slide 86

Slide 86 text

@vicqr Anotaciones MaxDepth - Detecta y limita el nivel de serialización - Especialmente útil serializando árboles grandes

Slide 87

Slide 87 text

@vicqr Anotaciones MaxDepth - Detecta y limita el nivel de serialización - Especialmente útil serializando árboles grandes Groups - Para serializar distintos grupos de atributos de tus entidades - De hecho sirve para implementar cualquiera de los métodos de exclusión

Slide 88

Slide 88 text

@vicqr Anotaciones - Groups class Spaceship { /** * @Groups({"show", "list"}) */ public $name; /** * @Groups({"show"}) */ public $color; /** * @Groups({"show", "list"}) */ public $maxSpeed; }

Slide 89

Slide 89 text

@vicqr Anotaciones - Groups class Spaceship { /** * @Groups({"show", "list"}) */ public $name; /** * @Groups({"show"}) */ public $color; /** * @Groups({"show", "list"}) */ public $maxSpeed; }

Slide 90

Slide 90 text

@vicqr Anotaciones - Groups $groups = ['groups' => ['list']]; $response = new Response($serializer->serialize($spaceship, 'json', $groups), 201); $response->headers->set('Content-Type', 'application/json'); return $response; Así indicamos que queremos serializar el grupo show

Slide 91

Slide 91 text

@vicqr Setup anotaciones use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $normalizer = new ObjectNormalizer($classMetadataFactory); Hay que inicializar classMetadataFactory y pasárselo al normalizador

Slide 92

Slide 92 text

@vicqr Habilitar cache de Doctrine # app/config/config_prod.yml framework: serializer: cache: serializer.mapping.cache.apc El sistema de extracción de metadatos es lento, conviene mucho habilitar la cache cuando se utilizan anotaciones (como Groups)

Slide 93

Slide 93 text

@vicqr Los principales normalizers disponibles ObjectNormalizer: - El más completo - Utiliza el PropertyAccess Component para leer y escribir en el objeto - Normaliza a partir de los métodos get/set/has/remove del objeto

Slide 94

Slide 94 text

@vicqr Los principales normalizers disponibles ObjectNormalizer: - El más completo - Utiliza el PropertyAccess Component para leer y escribir en el objeto - Normaliza a partir de los métodos get/set/has/remove del objeto GetSetMethodNormalizer: - Más sencillo que el anterior - Normaliza llamando a los getters y setters del objeto

Slide 95

Slide 95 text

@vicqr Los principales normalizers disponibles ObjectNormalizer: - El más completo - Utiliza el PropertyAccess Component para leer y escribir en el objeto - Normaliza a partir de los métodos get/set/has/remove del objeto GetSetMethodNormalizer: - Más sencillo que el anterior - Normaliza llamando a los getters y setters del objeto PropertyNormalizer: - Normaliza leyendo directamente las propiedades del objeto

Slide 96

Slide 96 text

@vicqr Los principales normalizers disponibles ObjectNormalizer: - El más completo - Utiliza el PropertyAccess Component para leer y escribir en el objeto - Normaliza a partir de los métodos get/set/has/remove del objeto GetSetMethodNormalizer: - Más sencillo que el anterior - Normaliza llamando a los getters y setters del objeto PropertyNormalizer: - Normaliza leyendo directamente las propiedades del objeto Todos devuelven un mapeo entre valores y nombres de propiedades, la diferencia es cómo lo obtienen

Slide 97

Slide 97 text

@vicqr Los principales normalizers disponibles ObjectNormalizer: - El más completo - Utiliza el PropertyAccess Component para leer y escribir en el objeto - Normaliza a partir de los métodos get/set/has/remove del objeto GetSetMethodNormalizer: - Más sencillo que el anterior - Normaliza llamando a los getters y setters del objeto PropertyNormalizer: - Normaliza leyendo directamente las propiedades del objeto https://symfony.com/doc/current/components/serializer.html#normalizers Todos devuelven un mapeo entre valores y nombres de propiedades, la diferencia es cómo lo obtienen

Slide 98

Slide 98 text

@vicqr ObjectNormalizer Es muy útil, pero también tiene un coste Se apoya en el PropertyAccess Component Ha sido bastante optimizado y siguen optimizándolo

Slide 99

Slide 99 text

@vicqr ObjectNormalizer Es muy útil, pero también tiene un coste Se apoya en el PropertyAccess Component Ha sido bastante optimizado y siguen optimizándolo Si la performance importa, mejor utilizar GetSetMethodNormalizer, PropertyNormalizer o el tuyo propio

Slide 100

Slide 100 text

@vicqr PropertyAccess Component http://symfony.com/doc/current/components/property_access.html Permite leer de y escribir en un objeto de forma cómoda Bien mediante propiedades públicas, setters/getters, hassers/issers Es esto concretamente lo que están intentando optimizar más

Slide 101

Slide 101 text

Utilizar el Symfony Serializer va mucho de crear tus propios normalizadores

Slide 102

Slide 102 text

@vicqr Creando tus normalizadores use Symfony\Component\Serializer\NameConverter\NameConverterInterface; class OrgPrefixNameConverter implements NameConverterInterface { public function normalize($propertyName) { return 'apolo18_'.$propertyName; } public function denormalize($propertyName) { // remove prefix_ prefix return 'apolo18_' === substr($propertyName, 0, 8) ? substr($propertyName, 8) : $propertyName; } } Por ejemplo, para serializar atributos con un nombre distinto

Slide 103

Slide 103 text

@vicqr Algunas funcionalidades secundarias - setIgnoredAttributes - Boolean functions (is, has) - Callbacks Para no serializar algunas propiedades Métodos cuyo resultado booleano se serializa Forma posible de formatear una propiedad

Slide 104

Slide 104 text

@vicqr Algunas funcionalidades secundarias - setIgnoredAttributes - Boolean functions (is, has) - Callbacks Para no serializar algunas propiedades Métodos cuyo resultado booleano se serializa Forma posible de formatear una propiedad Están bien, pero no son imprescindibles

Slide 105

Slide 105 text

@vicqr Callbacks $callback = function ($logoPath) { return 'thumb_'.$logoPath; }; $normalizer->setCallbacks(array('logo' => $callback)); Para formatear una propiedad del objeto (por ejemplo, fechas)

Slide 106

Slide 106 text

@vicqr Referencias circulares Si no haces nada verás un error como este: A circular reference has been detected (configured limit: 1). (500 Internal Server Error)

Slide 107

Slide 107 text

@vicqr Referencias circulares Si no haces nada verás un error como este: $normalizer->setCircularReferenceLimit(1); Número de veces que tiene que serializar un objeto antes de considerarlo referencia circular A circular reference has been detected (configured limit: 1). (500 Internal Server Error)

Slide 108

Slide 108 text

@vicqr Referencias circulares Si no haces nada verás un error como este: $normalizer->setCircularReferenceLimit(1); $normalizer->setCircularReferenceHandler(function ($object) { return $object->getName(); }); Número de veces que tiene que serializar un objeto antes de considerarlo referencia circular En lugar de lanzar excepción, la referencia circular es gestionada por este callable A circular reference has been detected (configured limit: 1). (500 Internal Server Error)

Slide 109

Slide 109 text

@vicqr Deserializando objetos complejos El Serializer utiliza el componente PropertyInfo para esto

Slide 110

Slide 110 text

@vicqr PropertyInfo Component Extrae información de las propiedades de una clase PHP por a partir de metadatos (de Doctrine, PHP Reflection, PHP doc., etc.)

Slide 111

Slide 111 text

@vicqr Deserializando objetos complejos El Serializer utiliza el componente PropertyInfo para esto Hay que pasarle un Extractor al normalizador

Slide 112

Slide 112 text

@vicqr Deserializando objetos complejos El Serializer utiliza el componente PropertyInfo para esto Hay que pasarle un Extractor al normalizador use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());

Slide 113

Slide 113 text

@vicqr Deserializando objetos complejos El Serializer utiliza el componente PropertyInfo para esto Hay que pasarle un Extractor al normalizador use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor()); El Extractor indica de qué modo hay que extraer la información, el PropertyInfo permite al normalizador conocer el tipo de lo que tiene que desnormalizar

Slide 114

Slide 114 text

@vicqr Críticas y elogios frecuentes - Ciertas cosas muy comunes son menos directas que en JMS - XML mal (pobre)

Slide 115

Slide 115 text

¿Y por qué lo del XML no está “bien hecho” en el Serializer?

Slide 116

Slide 116 text

@vicqr ¿Por qué es pobre el XML? El XML puede ser bastante más rico que el JSON (namespaces, xincludes, instrucciones de procesado)…

Slide 117

Slide 117 text

@vicqr ¿Por qué es pobre el XML? El XML puede ser bastante más rico que el JSON (namespaces, xincludes, instrucciones de procesado)… Añadir información de un formato a otro no encaja con la filosofía del Serializer

Slide 118

Slide 118 text

«We want different representations of the same data structure without enrichment during the serialization process» Kevin Dunglas https://github.com/symfony/symfony/issues/19330#issuecomment-233515204

Slide 119

Slide 119 text

@vicqr Críticas y elogios frecuentes - Ciertas cosas muy comunes son menos directas que en JMS - XML mal (pobre)

Slide 120

Slide 120 text

@vicqr Críticas y elogios frecuentes - Ciertas cosas muy comunes son menos directas que en JMS - XML mal (pobre) - Flexible, fácil de extender - Potente, permite cubrir necesidades complejas de tu lógica de negocio - Bien mantenido

Slide 121

Slide 121 text

@vicqr Ha ido mejorando y pretende seguir - Por ejemplo, algunas mejoras recientes: - DateTime Normalizer - Data URI Normalizer - CSV y YAML encoders

Slide 122

Slide 122 text

@vicqr Ha ido mejorando y pretende seguir - Por ejemplo, algunas mejoras recientes: - DateTime Normalizer - Data URI Normalizer - CSV y YAML encoders - Conversación continua acerca de cómo mejorar: - http://github.com/symfony/symfony/issues/16179 - http://github.com/symfony/symfony/issues/19330 - http://github.com/symfony/symfony/pull/19374

Slide 123

Slide 123 text

@vicqr Ha ido mejorando y pretende seguir - Por ejemplo, algunas mejoras recientes: - DateTime Normalizer - Data URI Normalizer - CSV y YAML encoders - Conversación continua acerca de cómo mejorar: - http://github.com/symfony/symfony/issues/16179 - http://github.com/symfony/symfony/issues/19330 - http://github.com/symfony/symfony/pull/19374 - API Platform lo usa

Slide 124

Slide 124 text

@vicqr Ha ido mejorando y pretende seguir - Por ejemplo, algunas mejoras recientes: - DateTime Normalizer - Data URI Normalizer - CSV y YAML encoders - Conversación continua acerca de cómo mejorar: - http://github.com/symfony/symfony/issues/16179 - http://github.com/symfony/symfony/issues/19330 - http://github.com/symfony/symfony/pull/19374 - API Platform lo usa Las perspectivas son muy buenas

Slide 125

Slide 125 text

Serialicemos algo menos fácil TRABAJANDO CON AMBOS

Slide 126

Slide 126 text

@vicqr Serialicemos nuestra misión espacial { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } Quiero llamarlo “mission” No quiero mostrarlo Quiero mostrarlo en el list Quiero añadir “thumb_” Solo en la versión 2 de la API Quiero que sea un campo más

Slide 127

Slide 127 text

@vicqr Serialicemos nuestra misión espacial { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } { mission: "Apolo18", email: "[email protected]", logo: "thumb_logo.jpg", spaceship: "Orion" } En el show

Slide 128

Slide 128 text

@vicqr Serialicemos nuestra misión espacial { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } { mission: "Apolo18", email: "[email protected]", logo: "thumb_logo.jpg", spaceship: "Orion" } En el list

Slide 129

Slide 129 text

@vicqr Serialicemos nuestra misión espacial { id: 18, name: "Apolo18", budget: "USD 6 billion", email: "[email protected]", logo: "logo.jpg", twitter: "apolo18", spaceship: { id: 29, name: "Orion" } } { mission: "Apolo18", email: "[email protected]", logo: "thumb_logo.jpg", twitter: "apolo18", spaceship: "Orion" } En la versión 2

Slide 130

Slide 130 text

@vicqr Serialicemos nuestra misión espacial - Renombrar propiedades - Exponer solo las que quiero - Tener distintas representaciones - Modificar el valor de una propiedad - Tener distintas versiones de la API - Que spaceship sea solo un nombre

Slide 131

Slide 131 text

@vicqr Con JMSSerializerBundle - Renombrar propiedades - Exponer solo las que quiero - Tener distintas representaciones - Modificar el valor de una propiedad - Tener distintas versiones de la API - Que spaceship sea solo un nombre @SerializedName @ExclusionStrategy, etc. @Groups @Accesor @Until, @Since @VirtualProperty

Slide 132

Slide 132 text

@vicqr Con JMSSerializerBundle - Renombrar propiedades - Exponer solo las que quiero - Tener distintas representaciones - Modificar el valor de una propiedad - Tener distintas versiones de la API - Que spaceship sea solo un nombre @SerializedName @ExclusionStrategy, etc. @Groups @Accesor @Until, @Since @VirtualProperty No hay problema @Type - ¿Serializar objetos encadenados? - ¿Deserializar objetos encadenados?

Slide 133

Slide 133 text

@vicqr Con Symfony Serializer - Renombrar propiedades - Exponer solo las que quiero - Tener distintas representaciones - Modificar el valor de una propiedad - Tener distintas versiones de la API - Que spaceship sea solo un nombre Un getter nuevo @Groups @Groups Un getter nuevo @Groups Un getter nuevo

Slide 134

Slide 134 text

@vicqr Con Symfony Serializer - Renombrar propiedades - Exponer solo las que quiero - Tener distintas representaciones - Modificar el valor de una propiedad - Tener distintas versiones de la API - Que spaceship sea solo un nombre Un getter nuevo @Groups @Groups Un getter nuevo @Groups Un getter nuevo O escribir tus normalizers, cuando quieras

Slide 135

Slide 135 text

@vicqr Con Symfony Serializer - Renombrar propiedades - Exponer solo las que quiero - Tener distintas representaciones - Modificar el valor de una propiedad - Tener distintas versiones de la API - Que spaceship sea solo un nombre Un getter nuevo @Groups @Groups Un getter nuevo @Groups Un getter nuevo O escribir tus normalizers, cuando quieras Ojo referencias circulares Pasar Extractor - ¿Serializar objetos encadenados? - ¿Deserializar objetos encadenados?

Slide 136

Slide 136 text

COMPARANDO ¿Entonces cuál uso?

Slide 137

Slide 137 text

Pues depende, los dos están muy bien

Slide 138

Slide 138 text

Pues depende, los dos están muy bien

Slide 139

Slide 139 text

Pues depende, los dos están muy bien

Slide 140

Slide 140 text

Más que verlo como “cuál es mejor” hay que entender que son dos animales distintos https://www.flickr.com/photos/5of7/5531923725

Slide 141

Slide 141 text

@vicqr Síntesis de críticas y puntos fuertes Licencia Mantenimiento Flexibilidad Curva aprendizaje Out-of-the-box XML JMSSERIALIZERBUNDLE SYMFONY SERIALIZER

Slide 142

Slide 142 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML?

Slide 143

Slide 143 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí Debería usar JMS

Slide 144

Slide 144 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí No ¿Quiero “marranear” en el proceso de serialización? Debería usar JMS

Slide 145

Slide 145 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí No ¿Quiero “marranear” en el proceso de serialización? Sí Conviene que use JMS Debería usar JMS

Slide 146

Slide 146 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí No ¿Las transformaciones que quiero hacer son bastante comunes? No ¿Quiero “marranear” en el proceso de serialización? Sí Conviene que use JMS Debería usar JMS

Slide 147

Slide 147 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí No ¿Las transformaciones que quiero hacer son bastante comunes? Sí Quizá sea más rápido usar JMS No ¿Quiero “marranear” en el proceso de serialización? Sí Conviene que use JMS Debería usar JMS

Slide 148

Slide 148 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí No ¿Las transformaciones que quiero hacer son bastante comunes? Sí Quizá sea más rápido usar JMS No ¿Quiero “marranear” en el proceso de serialización? Sí Conviene que use JMS Debería usar JMS No El componente Serializer me vendrá muy bien

Slide 149

Slide 149 text

@vicqr ¿Y la performance? - Son parecidos - En el Symfony Serializer lo más lento es el ObjectNormalizer - Aunque se ha hecho más rápido y sigue siendo optimizado

Slide 150

Slide 150 text

@vicqr ¿Y la performance? - Son parecidos - En el Symfony Serializer lo más lento es el ObjectNormalizer - Aunque se ha hecho más rápido y sigue siendo optimizado https://github.com/symfony/symfony/issues/16179 Discusión y comparativas

Slide 151

Slide 151 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí No ¿Las transformaciones que quiero hacer son bastante comunes? Sí Quizá sea más rápido usar JMS No ¿Quiero “marranear” en el proceso de serialización? Sí Conviene que use JMS Debería usar JMS No El componente Serializer me vendrá muy bien

Slide 152

Slide 152 text

@vicqr Casos de uso ¿Quiero trabajar bastante con XML? Sí No ¿Las transformaciones que quiero hacer son bastante comunes? Sí Quizá sea más rápido usar JMS No ¿Quiero “marranear” en el proceso de serialización? Sí Conviene que use JMS Debería usar JMS No El componente Serializer me vendrá muy bien ¿La performance importa mucho? Puedo usar el ObjectNormalizer Debería usar otro o hacerme el mío No Sí

Slide 153

Slide 153 text

@vicqr Experiencia personal 1. Hace años prefería JMSSerializer 2. En algún momento encontré algo que no supe cómo hacer y cambié 3. La primera impresión con SfSerializer fue que era costoso 4. A día de hoy prefiero SfSerializer 5. Si tengo que hacer algo rápido cojo JMSSerializer

Slide 154

Slide 154 text

@vicqr Experiencia personal 1. Hace años prefería JMSSerializer 2. En algún momento encontré algo que no supe cómo hacer y cambié 3. La primera impresión con SfSerializer fue que era costoso 4. A día de hoy prefiero SfSerializer 5. Si tengo que hacer algo rápido cojo JMSSerializer Por lo que he visto por ahí, es una evolución bastante común

Slide 155

Slide 155 text

APUNTES FINALES Qué recordar

Slide 156

Slide 156 text

@vicqr Qué recordar El serializador nos facilita crear distintas representaciones de los objetos Tanto el bundle como el componente son dos muy buenas herramientas Son DISTINTAS, están enfocadas diferente y son óptimas para distintos casos

Slide 157

Slide 157 text

@vicqr Qué recordar El serializador nos facilita crear distintas representaciones de los objetos Tanto el bundle como el componente son dos muy buenas herramientas Son DISTINTAS, están enfocadas diferente y son óptimas para distintos casos El JMSSerializer te da más “hecho” El componente Serializer te facilita más montar lo que necesites

Slide 158

Slide 158 text

@vicqr Resumen en un comentario de Github Just saying, but to me the Symfony's serializer does not especially suffer from a bad design, especially because its philosophy is far from the JMS serializer one. The idea of the Symfony's serializer is to keep things simple, not trying to answer every use-cases natively, but instead providing a great and simple architecture. Despite the fact it offers some great features, I'm almost never using the ObjectNormalizer and rather rely on custom normalizers (sometimes encoders) for each of my needs. Because when I'm writing code for my application, I know exactly what the output should be. I do not need something answering everything, just good and simple interfaces over it. This is way less brainfucking than a JMS Serializer, as soon as you're not trying to answer very generic needs. Now I can understand some of your concerns if you need to handle things in a very generic way, but to me there is nothing impossible with the current architecture regarding this. But anyway, I don't think the Symfony's serializer should try to replace entirely a JMS Serializer. Those are simply two different tools. Use or don't use them. https://github.com/symfony/symfony/issues/19330#issuecomment-233405451

Slide 159

Slide 159 text

No content

Slide 160

Slide 160 text

¡Con el Serializer no puedo hacer XMLs decentes!

Slide 161

Slide 161 text

¡Con el Serializer no puedo hacer XMLs decentes! ¡El JMS es una basura!

Slide 162

Slide 162 text

¡Con el Serializer no puedo hacer XMLs decentes! ¡El JMS es una basura! ¡¿Para qué quieres normalizadores y encoders?!

Slide 163

Slide 163 text

¡Con el Serializer no puedo hacer XMLs decentes! ¡El JMS es una basura! ¡¿Para qué quieres normalizadores y encoders?! ¡Deshonras a tu familia utilizando ese código!

Slide 164

Slide 164 text

Consultoría, formación y desarrollo @limenius @vicqr [email protected] ¡Gracias! Organizamos React Alicante 28-30 Sep. 2017 @ReactAlicante