Serializer has serialize / deserialize • Object to Format: serialize • Format to Object: deserialize Object Format (JSON, XML, CSV) serialize deserialize
Normalizer is Converter between Object and Array • Object to Array: normalize • Array to Object: denormalize Object Format (JSON, XML, CSV) serialize deserialize Array normalize denormalize Normalizer
Encoder is Converter between Array And Format • Array to Format: endode • Format to Array: decode Object Format (JSON, XML, CSV) serialize deserialize Array normalize denormalize encode decode Encoder
[TIPS] Two types of Documents on Symfony.com • There are two types of documents on the Symfony.com 1. The Symfony Component 2. How to use the Symfony Component in the Symfony Framework • If you use another framework, you should read the above 1 instead of 2
Data Model final class Cat { private int $id; private string $name; private string $imageUrl; private string $gender; private ?float $weight = null; // snip } [note] getters/setters are omitted in this slide
002: ListView Model namespace App\ViewModel; use App\Model\v000\Cat; final class ListView implements \JsonSerializable { public function __construct(private Cat $cat) { } public function jsonSerialize(): mixed { return [ 'id' => $this->cat->getId(), 'name' => $this->cat->getName(), 'image_url' => $this->cat->getImageUrl(), ]; } } src/ViewModel/ListView.php
Data Model final class Cat { private int $id; private string $name; private string $imageUrl; private string $gender; private ?float $weight = null; // snip } [note] getters/setters are omitted in this slide
ObjectNormalizer • Default Normalizer on Symfony Framework • Most powerful normalizer • Convert between Object and Array • Property name and value converts to key and value of hash
Doctrine Annotations • The Reader utility of Annotation and Attribute class Sample { /** * @SampleAnnotation */ public function Foo(): void { } } class Sample { #[SampleAttribute] public function Foo(): void { } }
103: Add Groups attribute to Data Model namespace App\Model\v103; use Symfony\Component\Serializer\Annotation\Groups; final class Cat { #[Groups(['list'])] private int $id; #[Groups(['list'])] private string $name; #[Groups(['list'])] private string $imageUrl; private string $gender; private ?float $weight = null; // snip src/Model/v103/Cat.php
104: Add SerializedName to Data Model namespace App\Model\v104; use Symfony\Component\Serializer\Annotation\SerializedName; final class Cat { #[Groups('list')] private int $id; #[Groups('list')] private string $name; #[Groups('list')] #[SerializedName('image_url')] private string $imageUrl; // snip src/Model/v104/Cat.php
105: Add attribute to method namespace App\Model\v105; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; final class Cat { // snip #[Groups('list')] #[SerializedName('lower_name')] public function getLowerCaseName(): string { return mb_strtolower($this->getName()); } // snip src/Model/v105/Cat.php
ArrayDenormalizer • Deserialize JSON array to Object array, use ArrayDenormalizer • "Denormalizer" only effects to the process of denormalize Object Format (JSON, XML, CSV) Array serialize deserialize normalize denormalize encode decode
TinyTomlEncoder namespace App\Encoder; use App\Encoder\TinyTomlEncoder\Dumper; use App\Encoder\TinyTomlEncoder\Parser; use Symfony\Component\Serializer\Encoder\DecoderInterface; use Symfony\Component\Serializer\Encoder\EncoderInterface; class TinyTomlEncoder implements EncoderInterface, DecoderInterface { public const FORMAT = 'toml'; private Dumper $dumper; private Parser $parser; public function __construct(Dumper $dumper = null, Parser $parser = null) { $this->dumper = $dumper ?? new Dumper(); $this->parser = $parser ?? new Parser(); } // snip src/Encoder/TinyTomlEncoder.php
[TIPS] Other Encoders implemented by API Platform • The API Platform uses the Symfony Serializer • They implement some useful custom Encoders for API: • JSON-LD, GraphQL, OpenAPI, HAL, JSON:API, and so on • See also: https://api-platform.com/
ChainEncoder implements these: final public function encode(mixed $data, string $format, array $context = []): string public function supportsEncoding(string $format, array $context = []): bool public function needsNormalization(string $format, array $context = []): bool
ChainDecorder implements these: final public function decode(string $data, string $format, array $context = []): mixed public function supportsDecoding(string $format, array $context = []): bool
Serialize flow final public function serialize(mixed $data, string $format, array $context = []): string return $this->encoder->encode($data, $format, $context); if ($this->encoder->supportsEncoding($format, $context)) if ($this->encoder->needsNormalization($format, $context)) { $data = $this->normalize($data, $format, $context); } throw new Exception No $normalizers [Note] These codes are not real, it's image
Deserialize flow final public function deserialize(mixed $data, string $type, string $format, array $context = []): mixed return $this->denormalize($data, $type, $format, $context); if ($this->encoder->supportsDecoding($format, $context)) $this->decoder->decode($data, $format, $context); throw new Exception No $normalizers [Note] These codes are not real, it's image
Summary of flow: It's simple • Each Encoder • It knows its own supported format • It receives its own supported context • Each Normalizer • It knows its own supported format and data • It receives its own supported context • Serializer • It choices Encoder by format • It choices Normalizer by format and data
Multiple formats, Same interface • Serializer is supporting multiple formats as the same interface • Custom Encoders and Normalizers can be easily created • They can also be used in the same interface
Good code design • Serializer implementation is simple • It only controls Normalizers and Encoders • Splitting Normalizer and Encoder is a good idea • Splitting NormalizeInterface and DenormalizeInterface, too • Splitting EncoderInterface and DecorderInterface, too
Read the docs • This talk is not enough to all about SymfonySerializer • You can find many topics on the official docs: • https://symfony.com/doc/current/components/serializer.html
Cat names and images • Names of Cat are taken from: • https://www.anicom-sompo.co.jp/special/name_cat/cat_2022/ • Photos of Cat (CC BY 2.0) • https://flickr.com/photos/tboard/6949552141/ • https://flickr.com/photos/mandywonder/33002985171 • https://flickr.com/photos/cuatrok77/8436333647 • https://flickr.com/photos/stone65/7795933612