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 full-size slide

  2. Hugo HAMON
    SensioLabs

    View full-size slide

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

    View full-size slide

  4. The Serializer
    serializes and
    unserializes objects.

    View full-size slide

  5. Normalizers
    Array
    Serializer
    Object
    XML
    JSON
    YAML

    Denormalizers
    Encoders
    Decoders

    View full-size slide

  6. Objects are turned
    into arrays by
    normalizers.

    View full-size slide

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

    View full-size slide

  8. The Serializer
    Interface.

    View full-size 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 full-size slide

  10. The Normalizer
    Interface.

    View full-size 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 full-size slide

  12. The Denormalizer
    Interface.

    View full-size 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 full-size slide

  14. The Encoder
    Interface.

    View full-size 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 full-size slide

  16. The Decoder
    Interface.

    View full-size 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 full-size slide

  18. 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 full-size slide

  19. Serializing an
    Object.

    View full-size slide

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

    View full-size slide

  21. Ignoring
    attributes from
    serialization.

    View full-size slide

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

    View full-size slide

  23. No more ID and Customer name!

    View full-size slide

  24. Unserializing
    a string.

    View full-size slide

  25. $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 full-size slide

  26. Extending the Serializer

    View full-size slide

  27. Adding support
    for YAML
    serialization.

    View full-size slide

  28. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  31. Adding support
    for YAML
    unserialization.

    View full-size slide

  32. 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 full-size slide

  33. $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 full-size slide

  34. The JMS Serializer Bundle

    View full-size slide

  35. The Serializer
    service.

    View full-size slide

  36. $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 full-size slide

  37. Twig helpers.

    View full-size slide

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

    View full-size slide

  39. Customizing
    the XML root
    node.

    View full-size slide

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

    View full-size slide



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

    View full-size slide

  42. Serializing a
    property to a
    XML attribute.

    View full-size slide

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

    View full-size slide



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

    View full-size slide

  45. Serializing an
    object to a
    single XML node

    View full-size slide

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

    View full-size slide

  47. 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 full-size slide

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



    2012-09-29
    120

    View full-size slide

  49. Excluding or
    Exposing
    properties.

    View full-size slide

  50. 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 full-size slide

  51. 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 full-size slide



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

    View full-size slide

  53. Managing objects
    properties
    versioning

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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



    3942945839

    View full-size slide

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



    0973525332

    View full-size slide

  58. Offering several
    views of a
    serialized object.

    View full-size slide

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

    View full-size slide


  60. SLT-123456
    Deluxe Suite

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

    View full-size slide

  61. Forcing the
    serializer to call
    getters & setters.

    View full-size slide

  62. 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 full-size slide



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


    View full-size slide

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

    View full-size slide

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

    View full-size slide

  66. Customizing the
    order in which
    properties are
    serialized.

    View full-size slide

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

    View full-size slide

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

    View full-size slide



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

    View full-size slide

  70. Typing properties
    for a complete
    unserialization.

    View full-size slide

  71. 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 full-size slide