Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Leveraging the Serializer Component

E2ed7c278c8c49bb3e7fe0b7de039997?s=47 Hugo Hamon
September 27, 2012

Leveraging the Serializer Component

Symfony comes with a Serializer component, which allows you to normalize and serialize your objects to multiple representations such as XML or JSON. This component becomes very helpful in certain circumstances like exposing data through a REST API. This talk will be split into three different parts. The first part will introduce the Serializer component underneath architecture and its basic usage. Then, you will learn how easy it is to extend the serializer in order to add custom serialization formats. Finally, you will discover how you can take benefit from the JMSSerializerBundle bundle that makes objects serialization easy, fun and intuitive with annotations.

E2ed7c278c8c49bb3e7fe0b7de039997?s=128

Hugo Hamon

September 27, 2012
Tweet

Transcript

  1. Leveraging the Serializer Component Symfony Live 2012 – San Francisco

    – Sept. 27th
  2. Hugo HAMON SensioLabs

  3. Serialization is the process of converting an object state into

    a format that can be stored and resurrected later Wikipedia  
  4. The Serializer serializes and unserializes objects.

  5. Normalizers Array Serializer Object XML JSON YAML … Denormalizers Encoders

    Decoders
  6. Objects are turned into arrays by normalizers.

  7. Arrays are turned into various output formats by encoders.

  8. The Serializer Interface.

  9. namespace Symfony\Component\Serializer; interface SerializerInterface { /** * Serializes data in

    the appropriate format * * @param mixed $data any data * @param string $format format name * @return string */ public function serialize($data, $format); /** * Deserializes data into the given type. * * @param mixed $data * @param string $type * @param string $format */ public function deserialize($data, $type, $format); }
  10. The Normalizer Interface.

  11. namespace Symfony\Component\Serializer\Normalizer; interface NormalizerInterface { /** * Normalizes an object

    into a set of arrays/scalars * * @param object $object object to normalize * @param string $format format the normalization result will be encoded as * @return array|scalar */ public function normalize($object, $format = null); /** * Checks whether the given data are supported for normalization. * * @param mixed $data Data to normalize. * @param string $format The format being (de-)serialized from or into. * @return Boolean */ public function supportsNormalization($data, $format = null); }
  12. The Denormalizer Interface.

  13. interface DenormalizerInterface { /** * Denormalizes data back into an

    object of the given class. * * @param mixed $data data to restore * @param string $class the expected class to instantiate * @param string $format format the given data was extracted from * @return object */ public function denormalize($data, $class, $format = null); /** * Checks whether the given data are supported for denormalization. * * @param mixed $data Data to denormalize from. * @param string $type The class to which the data should be denormalized. * @param string $format The format being deserialized from. * @return Boolean */ public function supportsDenormalization($data, $type, $format = null); }
  14. The Encoder Interface.

  15. namespace Symfony\Component\Serializer\Encoder; interface EncoderInterface { /** * Encodes data into

    the given format * * @param mixed $data Data to encode * @param string $format Format name * * @return scalar */ public function encode($data, $format); /** * Checks whether the serializer can encode to given format * * @param string $format format name * @return Boolean */ public function supportsEncoding($format); }
  16. The Decoder Interface.

  17. namespace Symfony\Component\Serializer\Encoder; interface DecoderInterface { /** * Decodes a string

    into PHP data * * @param string $data Data to decode * @param string $format Format name * * @return mixed */ public function decode($data, $format); /** * Checks whether the serializer can decode from given format * * @param string $format format name * @return Boolean */ public function supportsDecoding($format); }
  18. Basic Usage

  19. use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; // Register

    the normalizers $normalizers[] = new GetSetMethodNormalizer(); // Register the encoders $encoders[] = new JsonEncoder(); $encoders[] = new XmlEncoder(); // Create and initialize the serializer $serializer = new Serializer($normalizers, $encoders);
  20. Serializing an Object.

  21. $serializer ->serialize($object, 'xml') ;

  22. None
  23. Ignoring attributes from serialization.

  24. $ignore = array('id', 'customer'); $normalizer = new GetSetMethodNormalizer(); $normalizer->setIgnoredAttributes($ignore);

  25. No more ID and Customer name!

  26. Unserializing a string.

  27. $xml = '<response>...</response>'; // Convert an XML string to an

    array $data = $serializer->decode($xml, 'xml'); // Convert the array to an object $class = 'Acme\BookingBundle\Booking'; $booking = $serializer ->denormalize($data, $class, 'xml') ;
  28. Extending the Serializer

  29. Adding support for YAML serialization.

  30. namespace Acme\SerializerBundle\Encoder; use Symfony\Component\Serializer\Encoder\EncoderInterface; use Symfony\Component\Yaml\Dumper; class YamlEncoder implements EncoderInterface

    { public function encode($data, $format) { $yaml = new Dumper(); return $yaml->dump($data, 2); } public function supportsEncoding($format) { return 'yaml' === $format; } }
  31. use Acme\SerializerBundle\Encoder\YamlEncoder; $serializer = new Serializer( array(new GetSetMethodNormalizer()), array(new YamlEncoder(),

    ...) ); $yaml = $serializer->serialize($booking, 'yaml');
  32. reference: SLT-123456 arrival: '2012-09-26' departure: '2012-09-29' designation: 'Deluxe Suite'

  33. Adding support for YAML unserialization.

  34. namespace Acme\SerializerBundle\Encoder; // ... use Symfony\Component\Serializer\Encoder\DecoderInterface; use Symfony\Component\Yaml\Parser; class YamlEncoder

    implements EncoderInterface, DecoderInterface { // ... public function decode($data, $format) { $yaml = new Parser(); return $yaml->parse($data); } public function supportsDecoding($format) { return 'yaml' === $format; } }
  35. $yaml = <<<EOY reference: SLT-123456 arrival: '2012-09-26' departure: '2012-09-29' designation:

    'Deluxe Suite' EOY; $class = 'Acme\BookingBundle\Booking'; $data = $serializer->decode($yaml, 'yaml'); $booking = $serializer->denormalize($data, $class, 'yaml'); echo $booking->getReference();
  36. The JMS Serializer Bundle

  37. The Serializer service.

  38. $s = $container->get('serializer'); $json = $s->serialize($object, 'json'); $xml = $s->serialize($object,

    'xml'); $yml = $s->serialize($object, 'yml'); $type = 'Acme\BookingBundle\Booking'; $obj = $s->deserialize($xml, $type, 'xml'); $obj = $s->deserialize($yml, $type, 'yml');
  39. Twig helpers.

  40. {# uses JSON #} {{ booking | serialize }} {#

    Custom output format #} {{ booking | serialize('json') }} {{ booking | serialize('xml') }} {{ booking | serialize('yml') }}
  41. Customizing the XML root node.

  42. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\XmlRoot; /** * @XmlRoot("booking") */ class Booking

    { // ... }
  43. <?xml version="1.0" encoding="UTF-8"?> <booking> <reference>SLT-123456</reference> <arrival>2012-09-26</arrival> <departure>2012-09-29</departure> <designation>Deluxe Suite</designation> </booking>

  44. Serializing a property to a XML attribute.

  45. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\XmlRoot; use JMS\SerializerBundle\Annotation\XmlAttribute; /** @XmlRoot("booking") */ class

    Booking { /** @XmlAttribute */ private $reference; // ... }
  46. <?xml version="1.0" encoding="UTF-8"?> <booking reference="SLT-123456"> <arrival>2012-09-26</arrival> <departure>2012-09-29</departure> <designation>Deluxe Suite</designation> </booking>

  47. Serializing an object to a single XML node

  48. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\XmlRoot; /** * @XmlRoot("booking") */ class Booking

    { /** @var Price */ private $price; }
  49. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\XmlAttribute; use JMS\SerializerBundle\Annotation\XmlValue; class Price { /**

    @XmlValue */ private $amount; /** @XmlAttribute */ private $vat; /** @XmlAttribute */ private $currency; }
  50. $booking = new Booking(); $booking->setReference('SLT-123456'); // ... $booking->setPrice(new Price(120, 12,

    'EUR')); <?xml version="1.0" encoding="UTF-8"?> <booking> <!-- ... --> <departure>2012-09-29</departure> <price vat="12" currency="EUR">120</price> </booking>
  51. Excluding or Exposing properties.

  52. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\ExclusionPolicy; use JMS\SerializerBundle\Annotation\Expose; use JMS\SerializerBundle\Annotation\XmlRoot; /** *

    @ExclusionPolicy("all") * @XmlRoot("booking") */ class Booking { /** @Expose */ private $reference; }
  53. <booking> <reference>SLT-123456</reference> </booking>

  54. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\ExclusionPolicy; use JMS\SerializerBundle\Annotation\Exclude; use JMS\SerializerBundle\Annotation\XmlRoot; /** *

    @ExclusionPolicy("none") * @XmlRoot("booking") */ class Booking { /** @Exclude */ private $price; }
  55. <?xml version="1.0" encoding="UTF-8"?> <booking> <reference>SLT-123456</reference> <arrival>2012-09-26</arrival> <departure>2012-09-29</departure> <designation>Deluxe Suite</designation> </booking>

  56. Managing objects properties versioning

  57. namespace Acme\BookingBundle; // ... use JMS\SerializerBundle\Annotation\Since; use JMS\SerializerBundle\Annotation\SerializedName; // ...

    class Booking { /** * @Since("1.8.4") * @SerializedName("loyalty") */ private $loyaltyNumber; // ... }
  58. namespace Acme\BookingBundle; // ... use JMS\SerializerBundle\Annotation\Until; // ... class Booking

    { /** * @Until("1.8.3") * @SerializedName("loyalty") */ private $membershipNumber; // ... }
  59. $booking->setMembershipNumber('3942945839'); $booking->setLoyaltyNumber('0973525332'); $serializer->setVersion('1.8.2'); <?xml version="1.0" encoding="UTF-8"?> <booking> <!-- ... -->

    <loyalty>3942945839</loyalty> </booking>
  60. $booking->setMembershipNumber('3942945839'); $booking->setLoyaltyNumber('0973525332'); $serializer->setVersion('1.9'); <?xml version="1.0" encoding="UTF-8"?> <booking> <!-- ... -->

    <loyalty>0973525332</loyalty> </booking>
  61. Offering several views of a serialized object.

  62. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\Groups; class Booking { /** @Groups({ "list"

    }) */ private $id; /** @Groups({ "list", "details" }) */ private $reference; /** @Groups({ "details" }) */ private $designation; }
  63. <booking> <reference>SLT-123456</reference> <designation>Deluxe Suite</designation> </booking> $serializer = $this->get('serializer'); $serializer->setGroups(array('details')); $serializer->serialize($booking,

    'xml');
  64. Forcing the serializer to call getters & setters.

  65. use JMS\SerializerBundle\Annotation\AccessType; class Booking { /** @AccessType("public_method") */ private $arrival;

    public function setArrival($arrival) { $this->arrival = new \DateTime($arrival); } public function getArrival() { return $this->arrival->format('m/d/Y'); } }
  66. <?xml version="1.0" encoding="UTF-8"?> <booking> <reference>SLT-123456</reference> <arrival>09/26/2012</arrival> <departure>2012-09-29</departure> <!-- ... -->

    </booking>
  67. Mapping a property to another getter or setter method.

  68. use JMS\SerializerBundle\Annotation\Accessor; class Booking { /** * @Accessor( * setter

    = "setShortDesignation", * getter = "getShortDesignation" * ) */ private $designation; }
  69. Customizing the order in which properties are serialized.

  70. use JMS\SerializerBundle\Annotation\AccessOrder; /** * @AccessOrder("alphabetical") */ class Booking { //

    ... }
  71. use JMS\SerializerBundle\Annotation\AccessOrder; /** * @AccessOrder(custom = { * "reference", *

    "arrival", * "departure" * }) */ class Booking { // ... }
  72. <?xml version="1.0" encoding="UTF-8"?> <booking> <reference>SLT-123456</reference> <arrival>2012-09-26</arrival> <departure>2012-09-29</departure> <designation>Deluxe Suite</designation> <loyalty>3942945839</loyalty>

    <price currency="EUR" vat="19.6">119.6</price> </booking>
  73. Typing properties for a complete unserialization.

  74. namespace Acme\BookingBundle; use JMS\SerializerBundle\Annotation\Type; class Booking { /** @Type("string") */

    private $reference; /** @Type("DateTime") */ private $arrival; /** @Type("Acme\BookingBundle\Price") */ private $price; }
  75. None