Skip to content

Instantly share code, notes, and snippets.

@joshlopes
Created March 28, 2018 13:28
Show Gist options
  • Save joshlopes/7aa196bf5108877e1f0c0c67224d39aa to your computer and use it in GitHub Desktop.
Save joshlopes/7aa196bf5108877e1f0c0c67224d39aa to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace App\Bridge\Symfony\Serializer;
use App\Serializer\ModelDenormalizeInterface;
use App\Serializer\ModelNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer as SymfonyObjectNormalizer;
/**
* Decorate Symfony object normalizer with a set of rules
*
* Important notes:
* - You will never serialise / deserialize multiple times in the same cycle
* - You will never use custom serialization callbacks for the same property name cross objects
*
* This custom normalizer will:
* - [normalize] remove all empty and null values from the models properties
* - [normalize] set callbacks based on the model (Note: if the same property name is given it will override)
* - [denormalize] set callbacks based on the model denormalize method (Needs to be implementing the ModelDenormalizationInterface)
* - [denormalize] when preparing the data a set of callbacks will also be taken in consideration
*/
class CustomNormalizer extends SymfonyObjectNormalizer
{
public function normalize($object, $format = null, array $context = [])
{
if ($object instanceof ModelNormalizerInterface) {
// can bring some conflicts
$this->callbacks = array_merge($this->callbacks, $object->normalize());
}
$data = parent::normalize($object, $format, $context);
// remove every "null" / empty value
return array_filter($data, function ($value) {
return null !== $value;
});
}
public function denormalize($data, $class, $format = null, array $context = [])
{
if (\in_array(ModelDenormalizeInterface::class, class_implements($class), true)) {
/** @var ModelDenormalizeInterface $object */
$object = new $class();
$this->callbacks = array_merge($this->callbacks, $object->denormalize());
}
return parent::denormalize($data, $class, $format, $context);
}
/**
* Decorate the function so we can run the callbacks define
* for denormalization / preparing the data for the setters
*
* This function is only invoked before denormalizing the data
*/
public function prepareForDenormalization($data): array
{
$data = parent::prepareForDenormalization($data);
foreach ($this->callbacks as $property => $callback) {
if (isset($data[$property])) {
$data[$property] = $callback($data[$property], $data);
}
}
return $data;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment