Skip to content

Instantly share code, notes, and snippets.

@pounard
Last active April 9, 2020 08:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pounard/25d2a8d4502a6bb61e660957196a5773 to your computer and use it in GitHub Desktop.
Save pounard/25d2a8d4502a6bb61e660957196a5773 to your computer and use it in GitHub Desktop.
Symfony serializer type map decorator
<?php
/**
* Maps PHP native types to normalized names
*/
interface TypeMap
{
const TYPE_ARRAY = 'array';
const TYPE_NULL = 'null';
const TYPE_STRING = 'string';
/**
* From message instance guess message PHP native type (denormalized).
*/
public function getMessageType($message): string;
/**
* From PHP native type give the normalized aggregate type.
*/
public function getType(string $type): string;
}
/**
* Extends the type map and provide the reverse operation.
*/
interface NameMap extends TypeMap
{
/**
* From message instance guess message name (normalized)
*/
public function getMessageName($message): string;
/**
* From message name to PHP native type (denormalization)
*/
public function getName(string $type): string;
}
/**
* Default array-based implementation.
*/
final class DefaultNameMap implements NameMap
{
private $aliases = [];
private $nameToTypeMap = [];
private $typeToNameMap = [];
/**
* Default constructor
*
* @param string $map[]
* Keys are message normalize names, values are PHP native types to
* convert the messages to, this is a 1:1 map where a PHP message will
* be normalize the associated name.
* @param string[] $aliases
* Alias map for incomming normalized message names, this allows you
* to map historical names to changed PHP native types, but also map
* the same PHP native type over multiple names depending on the
* message source.
* Keys are legacy or duplicate names, values are either of normalized
* name or PHP native types. Althought for maintanability purpose, it's
* recommened to always use normalized names instead of PHP types.
*/
public function __construct(array $map = [], array $aliases = [])
{
$this->aliases = $aliases;
$this->nameToTypeMap = $map;
$this->typeToNameMap = \array_flip($map);
}
/**
* {@inheritdoc}
*/
public function getMessageType($message): string
{
if (null === $message) {
return NameMap::TYPE_NULL;
}
if (\is_array($message)) {
return NameMap::TYPE_ARRAY;
}
if (\is_string($message) || \is_resource($message)) {
return NameMap::TYPE_STRING;
}
if (\is_object($message)) {
return \get_class($message);
}
return \gettype($message);
}
/**
* {@inheritdoc}
*/
public function getMessageName($message): string
{
$type = $this->getMessageType($message);
return $this->typeToNameMap[$type] ?? $type;
}
/**
* {@inheritdoc}
*/
public function getName(string $type): string
{
return $this->typeToNameMap[$type] ?? $type;
}
/**
* {@inheritdoc}
*/
public function getType(string $name): string
{
$name = $this->aliases[$name] ?? $name;
return $this->nameToTypeMap[$name] ?? $name;
}
}
final class NameMapSerializer implements
DecoderInterface,
DenormalizerInterface,
NormalizerInterface,
SerializerInterface
{
/** @var NameMap */
private $nameMap;
/** @var \Symfony\Component\Serializer\Serializer */
private $decorated;
/**
* Default constructor
*/
public function __construct(NameMap $nameMap, $serializer)
{
$this->decorated = $serializer;
$this->nameMap = $nameMap;
}
/**
* {@inheritdoc}
*/
public function serialize($data, $format, array $context = [])
{
return $this->decorated->serialize($data, $format, $context);
}
/**
* {@inheritdoc}
*/
public function supportsDecoding($format, array $context = [])
{
return $this->decorated->supportsDecoding($format, $context);
}
/**
* {@inheritdoc}
*/
public function supportsNormalization($data, $format = null, array $context = [])
{
return $this->decorated->supportsNormalization($data, $format, $context);
}
/**
* {@inheritdoc}
*/
public function denormalize($data, $type, $format = null, array $context = [])
{
return $this->decorated->denormalize($data, $this->nameMap->getType($type), $format, $context);
}
/**
* {@inheritdoc}
*/
public function normalize($data, $format = null, array $context = [])
{
return $this->decorated->normalize($data, $format, $context);
}
/**
* {@inheritdoc}
*/
public function decode($data, $format, array $context = [])
{
return $this->decorated->decode($data, $format, $context);
}
/**
* {@inheritdoc}
*/
public function supportsDenormalization($data, $type, $format = null, array $context = [])
{
return $this->decorated->supportsDenormalization($data, $this->nameMap->getType($type), $format, $context);
}
/**
* {@inheritdoc}
*/
public function deserialize($data, $type, $format, array $context = [])
{
return $this->decorated->deserialize($data, $this->nameMap->getType($type), $format, $context);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment