Data Data Serialization Serialization with with Symfony Symfony - - PowerPoint PPT Presentation

data data serialization serialization with with symfony
SMART_READER_LITE
LIVE PREVIEW

Data Data Serialization Serialization with with Symfony Symfony - - PowerPoint PPT Presentation

Data Data Serialization Serialization with with Symfony Symfony & & Drupal Drupal SensioLabs Hugo Hamon Hugo Hamon Head of training at SensioLabs Book author Speaker at Conferences Symfony contributor Travel lover @hhamon


slide-1
SLIDE 1

SensioLabs

Data Data Serialization Serialization with with Symfony Symfony & & Drupal Drupal

slide-2
SLIDE 2

Hugo Hamon Hugo Hamon

Head of training at SensioLabs Book author Speaker at Conferences Symfony contributor Travel lover @hhamon

slide-3
SLIDE 3

« Serialization is the process of translating translating data structures or data structures or object

  • bject

state state into into a format a format that that can can be be stored stored and and reconstructed reconstructed later in the same or another computer environment. »

  • - Wikipedia.
slide-4
SLIDE 4

Examples Examples: :

HTTP Messages XML SOAP JSON YAML CSV…

slide-5
SLIDE 5

Most Common Usages: Most Common Usages: Storage in a file or a database REST APIs SOAP Web Services Distributing objects (Java)

slide-6
SLIDE 6

Data Serialization with PHP

slide-7
SLIDE 7

Serializing Data Structures with PHP

slide-8
SLIDE 8

serialize(18); serialize(12.50); serialize(null null); serialize(true true); serialize(false false); serialize('John Smith'); serialize([ 'a', 'b' ]); serialize(new new stdClass());

slide-9
SLIDE 9

i:18; i:18; d:12.5; d:12.5; N; N; b:1; b:1; b:0; b:0; s:10:"John Smith"; s:10:"John Smith"; a:3:{i:0;s:1:"a";i:1;s:1:"b";} a:3:{i:0;s:1:"a";i:1;s:1:"b";} O:8:"stdClass":0:{} O:8:"stdClass":0:{}

slide-10
SLIDE 10

i:18 18; ; d:12.5 12.5; ; b:1; ; b:0; ; N:; :; T:VALUE VALUE; ; 18 18 12.5 12.5 true true false false null null VALUE VALUE

slide-11
SLIDE 11

s:1:"a" "a"; ; s:2:"it" "it"; ; s:5:"peach" "peach"; ; s:10 10:"John Smith" "John Smith"; ;

s:l:"VALUE" "VALUE"; ;

a a it it peach peach John Smith John Smith

VALUE VALUE

slide-12
SLIDE 12

$data = [ $data = [ 'a' 'a', , 'b' 'b' ]

a a = Array = Array 2 2 = Array length (# of elements) = Array length (# of elements) i = Index = Index n n = Index name = Index name s s = String = String 1 1 = String length (# of chars) = String length (# of chars) "x" = Value = Value

a:2:{ :{i:0;s:1:"a" "a";i:1;s:1:"b" "b";} ;}

slide-13
SLIDE 13

$data = $data = new new stdClass stdClass(); ();

O O = Object = Object 8 8 = Class name length = Class name length

"stdClass stdClass" = Class name

= Class name

0 = Object size (# of properties)

= Object size (# of properties)

O:8:"stdClass" "stdClass":0:{} :{}

slide-14
SLIDE 14

$a = unserialize('i:18; i:18;'); $b = unserialize('d:12.5; :12.5;'); $c = unserialize('b:1; :1;'); $d = unserialize('b:0; :0;'); $e = unserialize('N:; :;'); $f = unserialize('s:10:"John Smith"; s:10:"John Smith";'); $g = unserialize('a:2:{i:0;s:1:"a";i:1;s:1:"b";} a:2:{i:0;s:1:"a";i:1;s:1:"b";}'); $h = unserialize('O:8:"stdClass":0:{} O:8:"stdClass":0:{}');

slide-15
SLIDE 15

Object (de)Serialization Handling

slide-16
SLIDE 16

__sleep() __wakeup()

slide-17
SLIDE 17

namespace namespace Database; class class Connection Connection { private private $link; private private $dsn; private private $user; private private $pwd; public public function function __construct($dsn, $username, $password) { $this->dsn = $dsn; $this->user = $username; $this->pwd = $password; } private private function function connect() { if if (!$this->link instanceof \PDO) { $this->link = new new \PDO($this->dsn, $this->user, $this->pwd); } } }

slide-18
SLIDE 18

class class Connection Connection { // … public public function function __sleep() { return return [ 'dsn', 'user', 'pwd' ]; } public public function function __wakeup() { $this->connect(); } }

slide-19
SLIDE 19

use use Database\Connection; $dsn = 'mysql:host=localhost;dbname=test'; $usr = 'root'; $pwd = ''; $db = new new Connection($dsn, $usr, $pwd); $db->query('SELECT ...'); $serialized = serialize($db); $db = unserialize($serialized); $db->query('SELECT ...');

slide-20
SLIDE 20

Serializable Interface

slide-21
SLIDE 21

class class Connection Connection implements implements \Serializable { public public function function serialize() { return return serialize([ 'dsn' => $this->dsn, 'user' => $this->user, 'password' => $this->pwd, ]); } }

slide-22
SLIDE 22

class class Connection Connection implements implements \Serializable { public public function function unserialize($data) { $data = unserialize($data); $this->dsn = $data['dsn']; $this->user = $data['user']; $this->pwd = $data['password']; $this->connect(); } }

slide-23
SLIDE 23

What about JSON as serialization format?

slide-24
SLIDE 24

json_encode() json_decode() JsonSerializable

slide-25
SLIDE 25

class class ArrayValue ArrayValue implements implements JsonSerializable { public public function function __construct(array array $array) { $this->array = $array; } public public function function jsonSerialize() { return return $this->array; } } json_encode(new new ArrayValue([1, 2, 3]));

slide-26
SLIDE 26

Serialization is a very complex task…

slide-27
SLIDE 27

The Symfony Serializer

slide-28
SLIDE 28

«The Serializer component is meant to be used to turn objects into a specific format (XML, JSON, YAML, ...) and the other way around. »

  • - Symfony.com
slide-29
SLIDE 29

http://symfony.com/doc/current/components/serializer.html

slide-30
SLIDE 30

class class Serializer Serializer { final final function function serialize($data, $format, array array $context = []) final final function function deserialize($data, $type, $format, array array $context = []); function function normalize($data, $format = null null, array array $context = []) function function denormalize($data, $type, $format = null null, array array $context = []); function function supportsNormalization($data, $format = null null); function function supportsDenormalization($data, $type, $format = null null) final final function function encode($data, $format, array array $context = []); final final function function decode($data, $format, array array $context = []); function function supportsEncoding($format); function function supportsDecoding($format); }

The he Serializ erializer er P Public API ublic API

slide-31
SLIDE 31

use use Symfony\Component\Serializer\Serializer; use use Symfony\Component\Serializer\Normalizer; use use Symfony\Component\Serializer\Encoder; // Setup the normalizers $normalizers[] = new new Normalizer\PropertyNormalizer(); // Setup the encoders $encoders[] = new new Encoder\JsonEncoder(); $encoders[] = new new Encoder\XmlEncoder(); // Setup the serializer $serializer = new new Serializer($normalizers, $encoders); // Use the serializer $serializer->serialize($object, 'json'); $serializer->deserialize($data, 'Acme\User','json');

slide-32
SLIDE 32

Normaliz

  • rmalizers

ers / / Denormaliz enormalizers ers

Name ¡ Goal ¡

Property

Normalizes public / private properties to an associative array.

GetSetMethod Normalizes properties by calling getter, isser & setter methods. Object

Normalizes objects with the PropertyAccess component.

Custom

Normalizes an object by delegating serialization to it.

slide-33
SLIDE 33

Enc Encoders

  • ders /

/ Dec ecoders

  • ders

Name ¡ Goal ¡

JsonEncoder Encodes & decodes an array from/to JSON. XmlEncoder

Encodes & decodes an array from/to XML.

ChainEncoder Chains multiple encoders. ChainDecoder Chain multiple decoders.

slide-34
SLIDE 34

Serializer Basic Usages

slide-35
SLIDE 35

class class Movie Movie { private private $id; private private $title; private private $slug; private private $description; private private $duration; private private $releaseDate; private private $storageKey; }

slide-36
SLIDE 36

$movie = new new Movie(); $movie->setTitle('Seven'); $movie->setSlug('seven'); $movie->setDescription('A brilliant…'); $movie->setDuration(130); $movie->setReleaseDate('1996-01-31');

Serializing erializing an Objec an Object t

slide-37
SLIDE 37

$data = $serializer->serialize( $movie, 'json' ); $movie = $serializer->deserialize( $data, 'Movie', 'json' );

slide-38
SLIDE 38

Properties Serialization

slide-39
SLIDE 39

{ "id":null, "title":"Seven", "slug":"seven", "description":"A … thriller!", "duration":130, "releaseDate":"1996-01-31", "storageKey":null }

JSON JSON Serializa erialization tion

slide-40
SLIDE 40

<?xml version="1.0"?> <response> <id/> <title>Seven</title> <slug>seven</slug> <description>A … thriller!</description> <duration>130</duration> <releaseDate>1996-01-31</releaseDate> <storageKey/> </response>

XML XML Serializa erialization tion

slide-41
SLIDE 41

String Deserialization

slide-42
SLIDE 42

$data = <<<DATA { "id":null, "title":"Seven", "slug":"seven", "description":"A brilliant thriller!", "duration":130, "releaseDate":"1996-01-31", "storageKey":null } DATA; $movie = $serializer->deserialize($data, 'Movie', 'json'); print_r($movie);

JSON JSON Deserializa eserialization tion

slide-43
SLIDE 43

$data = <<<DATA <?xml version="1.0"?> <response> <id/> <title>Seven</title> <slug>seven</slug> <description>A … thriller!</description> <duration>130</duration> <releaseDate>1996-01-31</releaseDate> <storageKey/> </response> DATA; $movie = $serializer->deserialize($data, 'Movie', 'xml'); print_r($movie);

XML XML Deserializa eserialization tion

slide-44
SLIDE 44

Movie Object ( [id:Movie:private] => [title:Movie:private] => Seven [slug:Movie:private] => seven [description:Movie:private] => A … thriller! [duration:Movie:private] => 130 [releaseDate:Movie:private] => 1996-01-31 [storageKey:Movie:private] => )

String String Deserializa eserialization tion

slide-45
SLIDE 45

class class Movie Movie { // ... function function __construct($id = null null, $title = null null, $slug = null null) { $this->id = $id; $this->title = $title; $this->slug = $slug; } }

Construc

  • nstructor
  • r Initializa

Initialization tion

Constructor arguments must match properties names. ¡

slide-46
SLIDE 46

Going Further with the Serializer

slide-47
SLIDE 47

Getter, Hasser & Isser Methods Normalizer

slide-48
SLIDE 48

// Setup the normalizers $normalizers normalizers[] = [] = new new Normalizer Normalizer\ObjectNormalizer ObjectNormalizer(); (); $normalizers normalizers[] = [] = new new Normalizer Normalizer\GetSetMethodNormalizer GetSetMethodNormalizer(); (); $normalizers[] = new new Normalizer\PropertyNormalizer(); // Setup the encoders $encoders[] = new new Encoder\JsonEncoder(); $encoders[] = new new Encoder\XmlEncoder(); // Setup the serializer $serializer = new new Serializer($normalizers, $encoders); // Use the serializer $serializer->serialize($object, 'json'); $serializer->deserialize($data, 'Acme\User','json');

The object normalizer can invoke « hasser » methods. ¡

slide-49
SLIDE 49

class class Movie Movie { public public function function getId() { return return $this->id; } public public function function getTitle() { return return $this->title; } public public function function hasGenre() { return return false; } // ... public public function function isReleased() { return new return new \DateTime DateTime($this->releaseDate) <= new new \DateTime DateTime(); } }

The normalizer invokes getter & isser methods. ¡

slide-50
SLIDE 50

{ "id":null, "title":"Seven", "slug":"seven", "description":"A … thriller!", "duration":130, "releaseDate":"1996-01-31", "storageKey":null, "genre" genre":false :false, , " "released released":true true, , }

JSON JSON Serializa erialization tion

slide-51
SLIDE 51

<?xml version="1.0"?> <response> <id/> <title>Seven</title> <slug>seven</slug> <description>A … thriller!</description> <duration>130</duration> <releaseDate>1996-01-31</releaseDate> <storageKey/> <genre>0</genre> <genre>0</genre> < <released released>1</ >1</released released> > </response>

XML XML Serializa erialization tion

slide-52
SLIDE 52

Ignoring Attributes

slide-53
SLIDE 53

$normalizer = new new GetSetMethodNormalizer(); $normalizer->setIgnoredAttributes([ 'storageKey' ]);

<?xml version="1.0"?> <response> <id/> <title>Seven</title> <slug>seven</slug> <description>A … thriller!</description> <duration>130</duration> <releaseDate>1996-01-31</releaseDate> <released>1</released> </response>

slide-54
SLIDE 54

Converting properties names to underscore case.

slide-55
SLIDE 55

$converter = new new CamelCaseToSnakeCaseNameConverter(); $normalizer = new new GetSetMethodNormalizer(null, $converter);

<?xml version="1.0"?> <response> <id/> <title>Seven</title> <slug>seven</slug> <description>A … thriller!</description> <duration>130</duration> <release_date release_date>1996-01-31</ >1996-01-31</release_date release_date> > <released>1</released> </response>

slide-56
SLIDE 56

Customizing all serialized properties names.

slide-57
SLIDE 57

class class PrefixNameConverter PrefixNameConverter implements implements NameConverterInterface { private private $prefix; public public function function __construct($prefix) { $this->prefix = $prefix; } public public function function normalize($propertyName) { return return $this->prefix.'_'.$propertyName; } public public function function denormalize($propertyName) { if if ($this->prefix.'_' === substr($propertyName, 0, count($this->prefix))) { return return substr($propertyName, count($this->prefix)); } return return $propertyName; } }

The NameConverterInterface has been introduced in 2.7. ¡

slide-58
SLIDE 58

$converter = new new PrefixNameConverter('movie'); $normalizer = new new GetSetMethodNormalizer(null, $converter);

<?xml version="1.0"?> <response> <movie_id/> <movie_title>Seven</movie_title> <movie_slug>seven</movie_slug> <movie_description>A … thriller!</movie_description> <movie_duration>130</movie_duration> <movie_release_date>1996-01-31</movie_release_date> <movie_released>1</movie_released> </response>

slide-59
SLIDE 59

Changing the XML root name.

slide-60
SLIDE 60

$serializer->serialize($movie, 'xml', [ 'xml_root_node_name' => 'movie', ]);

<?xml version="1.0"?> <movie> <id/> <title>Seven</title> ... </movie>

slide-61
SLIDE 61

Deserializing into an existing object.

slide-62
SLIDE 62

$data = <<<DATA <?xml version="1.0"?> <movie> <duration>130</duration> <releaseDate>1996-01-31</releaseDate> </movie> DATA; $movie1 = new new Movie(1234, 'Seven', 'seven'); $movie2 = $serializer->deserialize($data, 'Movie', 'xml', [ 'xml_root_node_name' => 'movie', 'object_to_populate' => $movie1, ]);

slide-63
SLIDE 63

Movie Object ( [id:Movie:private id:Movie:private] => 1234 ] => 1234 [ [title:Movie:private title:Movie:private] => ] => Seven Seven [ [slug:Movie:private slug:Movie:private] => ] => seven seven [description:Movie:private] => [duration:Movie:private duration:Movie:private] => 130 ] => 130 [ [releaseDate:Movie:private releaseDate:Movie:private] => 1996-01-31 ] => 1996-01-31 [storageKey:Movie:private] => [genre:Movie:private] => )

The « description » property remains empty while « duration » and « releaseDate » properties are set. ¡

slide-64
SLIDE 64

Serializer Advanced Features

slide-65
SLIDE 65

Serializing More Complex Object Graphs.

slide-66
SLIDE 66

class class Movie Movie { /** @var Genre */ private private $genre; /** @var Directors[] */ private private $directors; /** * Each role keeps a reference to that Movie object * and a reference to an Actor object playing that * role in the movie. * * @var Role[] */ private private $roles; }

slide-67
SLIDE 67

One to One Unidirectional Relationship

slide-68
SLIDE 68

$genre = new new Genre(42, 'Thriller', 'thriller'); $movie = new new Movie(1234, 'Seven', 'seven'); $movie->setGenre($genre); $movie->setStorageKey('movie-42-1234'); $movie->setDuration(130); $movie->setDescription('A brilliant thriller!'); $movie->setReleaseDate('1996-01-31'); echo echo $serializer->serialize($movie, 'xml', [ 'xml_root_node_name' => 'movie', ]);

slide-69
SLIDE 69

<?xml version="1.0"?> <movie movie> > <genre> <genre> <id> <id>42</id> </id> <slug> <slug>thriller</slug> </slug> < <title title>Thriller</ </title title> > </genre> </genre> <id> <id>1234</id> </id> < <title title>Seven</ </title title> > <duration> <duration>130</duration> </duration> < <released released>1</ </released released> > <slug> <slug>seven</slug> </slug> <description> <description>A brilliant thriller!</description> </description> < <release_date release_date>1996-01-31</ </release_date release_date> > </ </movie movie>

slide-70
SLIDE 70

{ "genre":{ "id":42, "slug":"thriller", "title":"Thriller" }, "id":1234, "title":"Seven", "duration":130, "released":true, "slug":"seven", "description":"A brilliant thriller!", "release_date":"1996-01-31" }

slide-71
SLIDE 71

One to Many Unidirectional Relationship

slide-72
SLIDE 72

$fincher = new new Director(); $fincher->setId(973463); $fincher->setName('David Fincher'); $fincher->setBirthday('1962-05-10'); $kopelson = new new Director(); $kopelson->setId(783237); $kopelson->setName('Arnold Kopelson'); $kopelson->setBirthday('1935-02-14'); $movie = new new Movie(1234, 'Seven', 'seven'); $movie->addDirector($fincher); $movie->addDirector($kopelson);

slide-73
SLIDE 73

<?xml version="1.0"?> <movie movie> > <!-- ... --> <!-- ... --> < <directors directors> > <id> <id>973463</id> </id> < <name name>David Fincher</ </name name> > < <birthday birthday>1962-05-10</ </birthday birthday> > < <deathday deathday/> /> </ </directors directors> > < <directors directors> > <id> <id>783237</id> </id> < <name name>Arnold Kopelson</ </name name> > < <birthday birthday>1935-02-14</ </birthday birthday> > < <deathday deathday/> /> </ </directors directors> > </ </movie movie>

slide-74
SLIDE 74

{ "genre":{ "id":42, "slug":"thriller", "title":"Thriller" }, "id":1234, "title":"Seven", "duration":130, "released":true, "slug":"seven", "description":"A brilliant thriller!", "release_date":"1996-01-31", "directors":[ { "id":973463, "name":"David Fincher", "birthday":"1962-05-10", "deathday":null }, { "id":783237, "name":"Arnold Kopelson", "birthday":"1935-02-14", "deathday":null } ] }

slide-75
SLIDE 75

Many to Many Bidirectional Relationship

slide-76
SLIDE 76

class class Role Role { private private $id; private private $character; private private $movie; private private $actor; function function __construct($id, Movie $movie, Actor $actor, $character) { $this->id = $id; $this->movie = $movie; $this->actor = $actor; $this->character = $character; } }

The « Role » instance keeps a reference to the « Movie » that also keeps references to « roles » played by actors. ¡

slide-77
SLIDE 77

$movie = new new Movie(1234, 'Seven', 'seven'); // ... $pitt = new new Actor(); $pitt->setId(328470); $pitt->setName('Brad Pitt'); $pitt->setBirthday('1963-12-18'); $freeman = new new Actor(); $freeman->setId(329443); $freeman->setName('Morgan Freeman'); $freeman->setBirthday('1937-06-01'); $mills = new new Role(233, $movie, $pitt, 'David Mills'); $sommerset = new new Role(328, $movie, $freeman, 'William Sommerset'); $movie->addRole($mills); $movie->addRole($sommerset); $serializer->serialize($movie, 'json');

slide-78
SLIDE 78

PHP Fatal PHP Fatal error error: Uncaught exception 'Symfony\Component\Serializer \Exception \CircularReferenceException' with message 'A circular reference has been detected (configured limit: 1).' in /Volumes/Development/Sites/ Serializer/vendor/symfony/serializer/ Normalizer/AbstractNormalizer.php:221

slide-79
SLIDE 79

Handling Circular References

slide-80
SLIDE 80

$normalizer = new new ObjectNormalizer(null null, $converter); $normalizer->setIgnoredAttributes([ 'storageKey' ]); // Return the object unique identifier instead of the // instance to stop a potential infinite serialization loop. $normalizer->setCircularReferenceHandler(function function ($object) { return return $object->getId(); });

Handling Handling Cir Circular ular Ref Refer erenc ences es

Circular references support has been introduced in Symfony 2.6. ¡

slide-81
SLIDE 81

{ ... "roles":[ { "actor":{ "id":328470, "name":"Brad Pitt", "birthday":"1963-12-18", "deathday":null }, "character":"David Mills", "id":233163, "movie":1234 "movie":1234 }, ... ] }

slide-82
SLIDE 82

Using Callback Normalizers.

slide-83
SLIDE 83

$movie = new new Movie(1234, 'Seven', 'seven'); $movie->setReleaseDate(new \DateTime('1996-01-31')); $pitt = new new Actor(); $pitt->setBirthday(new \DateTime('1963-12-18')); $fincher = new new Director(); $fincher->setBirthday(new \DateTime('1962-05-10')); $serializer->serialize($movie, 'json');

Actors, Directors and Movies now stores date representations as « DateTime » objects. These instance must be serialized too. ¡

slide-84
SLIDE 84

<release_date release_date> > < <last_errors last_errors> > < <warning_count warning_count>0</ </warning_count warning_count> > <warnings/> <warnings/> < <error_count error_count>0</ </error_count error_count> > < <errors errors/> /> </ </last_errors last_errors> > < <timezone timezone> > < <name name>Europe/Paris</ </name name> > <location> <location> < <country_code country_code>FR</ </country_code country_code> > <latitude> <latitude>48.86666</latitude> </latitude> <longitude> <longitude>2.33333</longitude> </longitude> < <comments comments></ ></comments comments> > </location> </location> </ </timezone timezone> > <offset> <offset>3600</offset> </offset> < <timestamp timestamp>823042800</ </timestamp timestamp> > </ </release_date release_date>

Without custom serializer to handle « DateTime » instance, the Serializer serializes any date object as follows: ¡

slide-85
SLIDE 85

$normalizer = new new Normalizer\ObjectNormalizer(... ...); $callback = function function ($dateTime) { return return $dateTime instanceof \DateTime ? $dateTime->format(\DateTime::ISO8601) : ''; }; $normalizer->setCallbacks([ 'releaseDate' => $callback, 'birthday' => $callback, 'deathday' => $callback, ]);

The built-in normalizers allow to set PHP callbacks to handle custom serialization steps. ¡

slide-86
SLIDE 86

<?xml version="1.0"?> <movie movie> > <!-- ... --> <!-- ... --> < <release_date release_date>1996-01-31T00:00:00+0100</ </release_date release_date> > < <directors directors> > <id> <id>973463</id> </id> < <name name>David Fincher</ </name name> > < <birthday birthday>1962-05-10T00:00:00+0100</ </birthday birthday> > < <deathday deathday/> /> </ </directors directors> > < <directors directors> > <id> <id>783237</id> </id> < <name name>Arnold Kopelson</ </name name> > < <birthday birthday>1935-02-14T00:00:00+0000</ </birthday birthday> > < <deathday deathday/> /> </ </directors directors> > </ </movie movie>

slide-87
SLIDE 87

{ "genre":{ "id":42, "slug":"thriller", "title":"Thriller" }, "id":1234, "title":"Seven", "duration":130, "released":true, "slug":"seven", "description":"A brilliant thriller!", "release_date":"1996-01-31T00:00:00+0000", "release_date":"1996-01-31T00:00:00+0000", "directors":[ { "id":973463, "name":"David Fincher", "birthday":"1962-05-10T00:00:00+0000", "birthday":"1962-05-10T00:00:00+0000", "deathday":null }, { "id":783237, "name":"Arnold Kopelson", "birthday":"1935-02-14T00:00:00+0000", "birthday":"1935-02-14T00:00:00+0000", "deathday":null } ] }

slide-88
SLIDE 88

Using the Custom Normalizer.

slide-89
SLIDE 89

Adding dding the C the Cust ustom

  • m Normaliz
  • rmalizer

er

The built-in « Custom » normalizer is responsible for automatically calling the « normalize() » and « denormalize() » methods of your objects if they implement the corresponding

  • interface. ¡

$normalizers[] = new new Normalizer\CustomNormalizer();

slide-90
SLIDE 90

use use Symfony\Component\Serializer\Normalizer\NormalizableInterface; use use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class class Role Role implements implements NormalizableInterface { private private $id; private private $character; private private $movie; private private $actor; function function normalize(NormalizerInterface $normalizer, $format = null null, array array $context = []) { return return [ 'id' => $this->id, 'character' => $this->character, 'actor' => $this->actor, ]; } }

slide-91
SLIDE 91

Serialization Groups

slide-92
SLIDE 92

Annota Annotation C tion Configura

  • nfiguration

tion

use use Symfony\Component\Serializer\Annotation\Groups; class class Movie Movie { /** @Groups({"admins"}) */ private private $id; /** @Groups({"admins", "publishers", "users" }) */ private private $title; /** @Groups({"admins", "publishers" }) */ private private $slug; /** @Groups({"admins", "publishers", "users" }) */ private private $releaseDate; /** @Groups({ "admins", "publishers", "users" }) */ public public function function isReleased() { return return new new $this->releaseDate <= new new \DateTime(); } }

slide-93
SLIDE 93

Movie: attributes: id: groups: [ admins ] title: groups: [ admins, publishers, users ] slug: groups: [ admins, publishers ] releaseDate: groups: [ admins, publishers, users ] released: groups: [ admins, publishers, users ]

YAML C ML Configura

  • nfiguration

tion

slide-94
SLIDE 94

<?xml version="1.0" ?> <serializer serializer ...> <class <class name="Movie"> <attribute <attribute name="id"> <group> <group>admins</group> </group> </ </attribute attribute> <attribute attribute name="title"> <group> <group>admins</group> </group> <group> <group>publishers</group> </group> <group> <group>users</group> </group> </ </attribute attribute> <attribute attribute name="slug"> <group> <group>admins</group> </group> <group> <group>publishers</group> </group> </ </attribute attribute> </class> </class> </ </serializer serializer>

XML C XML Configura

  • nfiguration

tion

slide-95
SLIDE 95

use use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader; use use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; use use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use use Doctrine\Common\Annotations\AnnotationReader; use use Doctrine\Common\Cache\ArrayCache; // Setup a loader $loader = new new AnnotationLoader(new new AnnotationReader()); $loader = new new YamlFileLoader(__DIR__.'/config/serializer.yml'); $loader = new new XmlFileLoader(__DIR__.'/config/serializer.xml'); $cache = new new ArrayCache(); // Setup the normalizers $factory = new new ClassMetadataFactory($loader, $cache); $normalizer = new new Normalizer\ObjectNormalizer($factory, $converter); // ...

Load

  • ad Gr

Groups

  • ups Metada

Metadata ta

slide-96
SLIDE 96

$serializer->serialize($movie, 'xml', [ 'xml_root_node_name' => 'movie', 'groups' => [ 'users' ], ]); $serializer->deserialize($movie, 'Movie', 'xml', [ 'xml_root_node_name' => 'movie', 'groups' => [ 'users' ], ]);

Serializa erialization tion Gr Groups

  • ups
slide-97
SLIDE 97

Serializer Integration into Drupal 8

slide-98
SLIDE 98

The « Serialization » Core module integrates the Symfony Serializer into Drupal. »

slide-99
SLIDE 99

core core/modules/ /modules/serialization serialization/ / ├── serialization.info.yml ├── serialization.module ├── serialization.services.yml serialization.services.yml ├── src/ │ ├── Encoder/ Encoder/ │ ├── EntityResolver EntityResolver/ / │ ├── Normalizer Normalizer/ / │ ├── RegisterEntityResolversCompilerPass.php │ ├── RegisterSerializationClassesCompilerPass.php │ ├── SerializationServiceProvider.php │ └── Tests/ └── tests/ ├── modules/ ├── serialization_test/ └── src/

slide-100
SLIDE 100

Built Built-in

  • in Normaliz
  • rmalizers

ers

core/modules/serialization/src/Normalizer/ ├─ ComplexDataNormalizer.php (default) (default) ├─ ConfigEntityNormalizer.php ├─ ContentEntityNormalizer.php ├─ EntityNormalizer.php ├─ ListNormalizer.php ├─ NormalizerBase.php ├─ NullNormalizer.php └─ TypedDataNormalizer.php

slide-101
SLIDE 101

By default, the Drupal « Serializer » only uses its custom made normalizers.

slide-102
SLIDE 102

Regist Registering ering Serializa erialization tion S Ser ervic vices es

# core/modules/serialization/serialization.services.yml services: serializer serializer: class: Symfony\Component\Serializer\Serializer arguments: [{ }, { }] serializer.normalizer.list serializer.normalizer.list: class: Drupal\serialization\Normalizer\ListNormalizer tags:

  • { name: normalizer

normalizer } serializer.encoder.json serializer.encoder.json: : class: Drupal\serialization\Encoder\JsonEncoder tags:

  • { name: encoder

encoder, format: json json }

slide-103
SLIDE 103

Built Built-in S

  • in Ser

ervic vices es

serializer serializer # Normalizers serializer.normalizer.password_field_item serializer.normalizer.config_entity serializer.normalizer.content_entity serializer.normalizer.entity serializer.normalizer.complex_data serializer.normalizer.list serializer.normalizer.typed_data # Encoders serializer.encoder.json serializer.encoder.xml # Entity Resolvers (for HAL REST web services) serializer.entity_resolver serializer.entity_resolver.uuid serialization.entity_resolver.target_id

slide-104
SLIDE 104

The « Hal » Core module also integrates the Symfony Serializer into

  • Drupal. »
slide-105
SLIDE 105

core core/modules/ /modules/hal hal/ / ├── hal.info.yml ├── hal.module ├── hal.services.yml └── src ├── Encoder │ └── JsonEncoder.php ├── HalServiceProvider.php └── Normalizer ├── ContentEntityNormalizer.php ├── EntityReferenceItemNormalizer.php ├── FieldItemNormalizer.php ├── FieldNormalizer.php ├── FileEntityNormalizer.php └── NormalizerBase.php

slide-106
SLIDE 106

services: serializer.normalizer.entity_reference_item.hal serializer.normalizer.entity_reference_item.hal: : class: Drupal\hal\Normalizer\EntityReferenceItemNormalizer arguments: [@rest.link_manager, @serializer.entity_resolver] tags:

  • {
  • { name

name: : normalizer normalizer, , priority priority: 10 } : 10 } serializer.normalizer.entity.hal serializer.normalizer.entity.hal: : class: Drupal\hal\Normalizer\ContentEntityNormalizer arguments: [@rest.link_manager, @entity.manager, @module_handler] tags:

  • {
  • { name

name: : normalizer normalizer, , priority priority: 10 } : 10 } serializer.encoder.hal serializer.encoder.hal: : class: Drupal\hal\Encoder\JsonEncoder tags:

  • {
  • { name

name: encoder, : encoder, priority priority: 10, format: : 10, format: hal_json hal_json } }

Built Built-in S

  • in Ser

ervic vices es

slide-107
SLIDE 107

Going Further with Data Serialization

slide-108
SLIDE 108

JMS JMS Serializ erializer er Librar Library y

  • Yaml / XML / Json Serialization
  • Advanced Serialization Mapping
  • Handle Circular References gracefully
  • Advanced Metadata Confjguration
  • Integrates with Doctrine / Symfony / ZF…
  • Versionning support
  • Extensible at will

http://jmsyst.com/libs/serializer

slide-109
SLIDE 109

Some

  • me F

Final inal Though houghts ts

  • Serializing data is « mostly » easy to achieve!
  • Deserializing is not easy at all!
  • For simple use cases, use the Symfony Serializer!
  • For advanced use cases, use the JMS Serializer!

http://jmsyst.com/libs/serializer

slide-110
SLIDE 110

SensioLabs

Thank Thank You

  • u!

Hugo Hugo Hamon Hamon hugo.hamon@sensiolabs.com hugo.hamon@sensiolabs.com @hhamon hhamon