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

Leveraging the Serializer Component

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.

Hugo Hamon

September 27, 2012
Tweet

More Decks by Hugo Hamon

Other Decks in Technology

Transcript

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

    View Slide

  2. Hugo HAMON
    SensioLabs

    View Slide

  3. Serialization is the process of
    converting an object state
    into a format that can be
    stored and resurrected later
    Wikipedia  

    View Slide

  4. The Serializer
    serializes and
    unserializes objects.

    View Slide

  5. Normalizers
    Array
    Serializer
    Object
    XML
    JSON
    YAML

    Denormalizers
    Encoders
    Decoders

    View Slide

  6. Objects are turned
    into arrays by
    normalizers.

    View Slide

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

    View Slide

  8. The Serializer
    Interface.

    View Slide

  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);
    }

    View Slide

  10. The Normalizer
    Interface.

    View Slide

  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);
    }

    View Slide

  12. The Denormalizer
    Interface.

    View Slide

  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);
    }

    View Slide

  14. The Encoder
    Interface.

    View Slide

  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);
    }

    View Slide

  16. The Decoder
    Interface.

    View Slide

  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);
    }

    View Slide

  18. Basic Usage

    View Slide

  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);

    View Slide

  20. Serializing an
    Object.

    View Slide

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

    View Slide

  22. View Slide

  23. Ignoring
    attributes from
    serialization.

    View Slide

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

    View Slide

  25. No more ID and Customer name!

    View Slide

  26. Unserializing
    a string.

    View Slide

  27. $xml = '...';
    // 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')
    ;

    View Slide

  28. Extending the Serializer

    View Slide

  29. Adding support
    for YAML
    serialization.

    View Slide

  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;
    }
    }

    View Slide

  31. use Acme\SerializerBundle\Encoder\YamlEncoder;
    $serializer = new Serializer(
    array(new GetSetMethodNormalizer()),
    array(new YamlEncoder(), ...)
    );
    $yaml = $serializer->serialize($booking,
    'yaml');

    View Slide

  32. reference: SLT-123456
    arrival: '2012-09-26'
    departure: '2012-09-29'
    designation: 'Deluxe Suite'

    View Slide

  33. Adding support
    for YAML
    unserialization.

    View Slide

  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;
    }
    }

    View Slide

  35. $yaml = <<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();

    View Slide

  36. The JMS Serializer Bundle

    View Slide

  37. The Serializer
    service.

    View Slide

  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');

    View Slide

  39. Twig helpers.

    View Slide

  40. {# uses JSON #}
    {{ booking | serialize }}
    {# Custom output format #}
    {{ booking | serialize('json') }}
    {{ booking | serialize('xml') }}
    {{ booking | serialize('yml') }}

    View Slide

  41. Customizing
    the XML root
    node.

    View Slide

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

    View Slide



  43. SLT-123456
    2012-09-26
    2012-09-29
    Deluxe Suite

    View Slide

  44. Serializing a
    property to a
    XML attribute.

    View Slide

  45. namespace Acme\BookingBundle;
    use JMS\SerializerBundle\Annotation\XmlRoot;
    use JMS\SerializerBundle\Annotation\XmlAttribute;
    /** @XmlRoot("booking") */
    class Booking
    {
    /** @XmlAttribute */
    private $reference;
    // ...
    }

    View Slide



  46. 2012-09-26
    2012-09-29
    Deluxe Suite

    View Slide

  47. Serializing an
    object to a
    single XML node

    View Slide

  48. namespace Acme\BookingBundle;
    use JMS\SerializerBundle\Annotation\XmlRoot;
    /**
    * @XmlRoot("booking")
    */
    class Booking
    {
    /** @var Price */
    private $price;
    }

    View Slide

  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;
    }

    View Slide

  50. $booking = new Booking();
    $booking->setReference('SLT-123456');
    // ...
    $booking->setPrice(new Price(120, 12, 'EUR'));



    2012-09-29
    120

    View Slide

  51. Excluding or
    Exposing
    properties.

    View Slide

  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;
    }

    View Slide


  53. SLT-123456

    View Slide

  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;
    }

    View Slide



  55. SLT-123456
    2012-09-26
    2012-09-29
    Deluxe Suite

    View Slide

  56. Managing objects
    properties
    versioning

    View Slide

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

    View Slide

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

    View Slide

  59. $booking->setMembershipNumber('3942945839');
    $booking->setLoyaltyNumber('0973525332');
    $serializer->setVersion('1.8.2');



    3942945839

    View Slide

  60. $booking->setMembershipNumber('3942945839');
    $booking->setLoyaltyNumber('0973525332');
    $serializer->setVersion('1.9');



    0973525332

    View Slide

  61. Offering several
    views of a
    serialized object.

    View Slide

  62. namespace Acme\BookingBundle;
    use JMS\SerializerBundle\Annotation\Groups;
    class Booking
    {
    /** @Groups({ "list" }) */
    private $id;
    /** @Groups({ "list", "details" }) */
    private $reference;
    /** @Groups({ "details" }) */
    private $designation;
    }

    View Slide


  63. SLT-123456
    Deluxe Suite

    $serializer = $this->get('serializer');
    $serializer->setGroups(array('details'));
    $serializer->serialize($booking, 'xml');

    View Slide

  64. Forcing the
    serializer to call
    getters & setters.

    View Slide

  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');
    }
    }

    View Slide



  66. SLT-123456
    09/26/2012
    2012-09-29


    View Slide

  67. Mapping a property
    to another getter or
    setter method.

    View Slide

  68. use JMS\SerializerBundle\Annotation\Accessor;
    class Booking
    {
    /**
    * @Accessor(
    * setter = "setShortDesignation",
    * getter = "getShortDesignation"
    * )
    */
    private $designation;
    }

    View Slide

  69. Customizing the
    order in which
    properties are
    serialized.

    View Slide

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

    View Slide

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

    View Slide



  72. SLT-123456
    2012-09-26
    2012-09-29
    Deluxe Suite
    3942945839
    119.6

    View Slide

  73. Typing properties
    for a complete
    unserialization.

    View Slide

  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;
    }

    View Slide

  75. View Slide