Slide 1

Slide 1 text

http://www.flickr.com/photos/netzer/38270856 Leveraging the Serializer Component

Slide 2

Slide 2 text

Hugo HAMON SensioLabs

Slide 3

Slide 3 text

1. Introduction

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

The Serializer serializes and unserializes objects.

Slide 6

Slide 6 text

Normalizers Array Serializer Object XML JSON YAML … Denormalizers Encoders Decoders

Slide 7

Slide 7 text

The Serializer Interface.

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

The Normalizer Interface.

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

The Denormalizer Interface.

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

The Encoder Interface.

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

The Decoder Interface.

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

2. Basic Usage

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Serializing an Object.

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Ignoring attributes from serialization.

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

No more ID and Customer name!

Slide 25

Slide 25 text

Unserializing a string.

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

3. Extending the Serializer

Slide 28

Slide 28 text

Adding support for YAML serialization.

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Adding support for YAML unserialization.

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

$yaml = <<decode($yaml, 'yaml'); $booking = $serializer->denormalize($data, $class, 'yaml'); echo $booking->getReference();

Slide 34

Slide 34 text

4. The JMSSerializer Bundle

Slide 35

Slide 35 text

The Serializer service.

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

Twig helpers.

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

YAML Con guration

Slide 40

Slide 40 text

# AcmeBookingBundle\Resources\config\serializer\Booking.yml Acme\BookingBundle\Booking: exclusion_policy: ALL xml_root_name: booking exclude: true access_type: public_method # ... properties: reference: expose: true type: string amount: expose: true type: double # ...

Slide 41

Slide 41 text

XML Con guration

Slide 42

Slide 42 text

# AcmeBookingBundle\Resources\config\serializer\Booking.xml

Slide 43

Slide 43 text

Annotations Con guration

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Customizing the XML root node.

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Serializing a property to a XML attribute.

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

2012-09-26 2012-09-29 Deluxe Suite

Slide 51

Slide 51 text

Serializing an object to a single XML node

Slide 52

Slide 52 text

/** * @Serialize\XmlRoot("booking") * */ class Booking { /** * @var Price */ private $price; }

Slide 53

Slide 53 text

class Price { /** @Serialize\XmlValue */ private $amount; /** @Serialize\XmlAttribute */ private $vat; /** @Serialize\XmlAttribute */ private $currency; }

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

Excluding or Exposing properties.

Slide 56

Slide 56 text

/** * @Serialize\ExclusionPolicy("all") * @Serialize\XmlRoot("booking") */ class Booking { /** * @Serialize\Expose */ private $reference; }

Slide 57

Slide 57 text

SLT-123456

Slide 58

Slide 58 text

/** * @Serialize\ExclusionPolicy("none") * @Serialize\XmlRoot("booking") */ class Booking { /** * @Serialize\Exclude */ private $price; }

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

Managing objects properties versioning

Slide 61

Slide 61 text

// ... class Booking { /** * @Serialize\Since("1.8.4") * @Serialize\SerializedName("loyalty") */ private $loyaltyNumber; // ... }

Slide 62

Slide 62 text

// ... class Booking { /** * @Serialize\Until("1.8.3") * @Serialize\SerializedName("loyalty") */ private $membershipNumber; // ... }

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

Detecting the version & format automatically

Slide 66

Slide 66 text

namespace Acme\BookingBundle\Listener; use Symfony\Component\HttpKernel\Event\KernelEvent; use JMS\SerializerBundle\Serializer\SerializerInterface; class ApiVersionListener { public function __construct(SerializerInterface $serializer) { $this->serializer = $serializer; } public function onKernelRequest(KernelEvent $event) { $request = $event->getRequest(); $accept = $request->headers->get('Accept'); // look for: application/vnd.hhamon-v{version}+{format} if ($accept && preg_match('/([0-9\.]+)?\+(xml|json)$/', $accept, $matches)) { $request->setRequestFormat($matches[2]); $this->serializer->setVersion($matches[1]); } } }

Slide 67

Slide 67 text

Offering several views of a serialized object.

Slide 68

Slide 68 text

// ... class Booking { /** @Serialize\Groups({ "list" }) */ private $id; /** @Serialize\Groups({ "list", "details" }) */ private $reference; /** @Serialize\Groups({ "details" }) */ private $designation; }

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

Forcing the serializer to call getters & setters.

Slide 71

Slide 71 text

class Booking { /** @Serialize\AccessType("public_method") */ private $arrival; public function setArrival($arrival) { $this->arrival = new \DateTime($arrival); } public function getArrival() { return $this->arrival->format('m/d/Y'); } }

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Mapping a property to another getter or setter method.

Slide 74

Slide 74 text

class Booking { /** * @Serialize\Accessor( * setter = "setShortDesignation", * getter = "getShortDesignation" * ) * */ private $designation; }

Slide 75

Slide 75 text

Customizing the order in which properties are serialized.

Slide 76

Slide 76 text

/** * @Serialize\AccessOrder("alphabetical") * */ class Booking { // ... }

Slide 77

Slide 77 text

/** * @Serialize\AccessOrder(custom = { * "reference", * "arrival", * "departure" * }) * */ class Booking { // ... }

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

Typing properties for a complete unserialization.

Slide 80

Slide 80 text

class Booking { /** @Serialize\Type("string") */ private $reference; /** @Serialize\Type("DateTime") */ private $arrival; /** @Serialize\Type("Acme\BookingBundle\Price") */ private $price; }

Slide 81

Slide 81 text

5. Doctrine Support

Slide 82

Slide 82 text

Serializing a Doctrine entity

Slide 83

Slide 83 text

class BookingController extends Controller { /** * @Route( * "/booking/{reference}.{_format}", * defaults = { "_format" = "xml" } * ) */ public function showAction(Booking $booking) { $serializer = $this->container->get('serializer'); $xml = $serializer->serialize($booking, 'xml'); return new Response($xml); } }

Slide 84

Slide 84 text

1 440 86.24 1 130 5 90

Slide 85

Slide 85 text

Serializing a Doctrine Collection

Slide 86

Slide 86 text

class BookingController extends Controller { public function indexAction() { $em = $this->get('doctrine')->getManager(); $bookings = $em ->getRepository('AcmeBookingBundle:Booking') ->findAll() ; $serializer = $this->container->get('serializer'); $xml = $serializer->serialize($bookings, 'xml'); return new Response($xml); } }

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

Unserializing a Doctrine entity

Slide 89

Slide 89 text

$json = '{"id":1,"reference":"GH45IZ8","arrival":"12\/ 23\/2012","departure":"12\/25\/2012","amount": 440,"vat":86.24,"currency":"EUR","customer":{"id": 1, "username":"hhamon"},"rooms":[{"id": 1,"number":"420","type":"double","price":130},{"id": 5,"number":"518","type":"single","price":90}]}'; $serializer = $this->container->get('serializer'); $booking = $serializer->deserialize( $json, 'Acme\BookingBundle\Entity\Booking', 'json' );

Slide 90

Slide 90 text

https://joind.in/talk/view/7568