Last active
April 9, 2020 08:24
-
-
Save pounard/25d2a8d4502a6bb61e660957196a5773 to your computer and use it in GitHub Desktop.
Symfony serializer type map decorator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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