So I have many classes I want to serialize with Symfony serializer. For instance
class Foo
{
public $apple = 1;
public $pear = null;
public function serialize() {
Utils::serialize($this);
}
}
which I serialize with the following serialize()
call :
class Utils {
public static function serialize($object) {
$encoder = new XmlEncoder();
$normalizer = new ObjectNormalizer();
$serializer = new Serializer(array($normalizer), array($encoder));
$str = $serializer->serialize($object, 'xml')
}
}
The output produced gives me:
<apple>1</apple><pear/>
The output expected should be:
<apple>1</apple>
I took a look at the Symfony 2.8 doc and managed to find a quick solution by using $normalizer->setIgnoredAttributes("pear")
.
So the improved serialize static function looks like this
class Utils {
public static function ignoreNullAttributes($object) {
$ignored_attributes = array();
foreach($object as $member => $value) {
if (is_null($object->$member)) {
array_push($ignored_attributes, $member);
}
}
return $ignored_attributes;
}
public static function serialize($object) {
$encoder = new XmlEncoder();
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(Utils::ignoreNullAttributes($object));
$serializer = new Serializer(array($normalizer), array($encoder));
$str = $serializer->serialize($object, 'xml')
}
}
However, this solution does not satisfy me since I have more complicated cases where different Foo
can be owned by a same class. e.g.
class Bar
{
public $foo1; // (apple=null; pear=2)
public $foo2; // (apple=2; pear=null)
public function serialize() {
Utils::serialize($this);
}
}
Here I cannot use the setIgnoredAttributes
method since $foo1
and $foo2
do not have the same null elements. Furthermore, I do not call the serialize
method from the child class (i.e. Foo
) here so the setIgnoredAttributes
is empty.
Without having to write complex introspection code, how can I hide by default null element with Symfony 2.8 serializer ? I have seen for instance that it is enabled by default with JMSSerializer.
A solution would be to extend from ObjectNormalizer
class, override the normalize()
method and remove all null
values there:
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
class CustomObjectNormalizer extends ObjectNormalizer
{
public function normalize($object, $format = null, array $context = [])
{
$data = parent::normalize($object, $format, $context);
return array_filter($data, function ($value) {
return null !== $value;
});
}
}
$encoders = array(new XmlEncoder());
$normalizers = array(new CustomObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
// ...
If we have an array of Person like the one of the official documentation:
// ...
$person1 = new Person();
$person1->setName('foo');
$person1->setAge(null);
$person1->setSportsman(false);
$person2 = new Person();
$person2->setName('bar');
$person2->setAge(33);
$person2->setSportsman(null);
$persons = array($person1, $person2);
$xmlContent = $serializer->serialize($persons, 'xml');
echo $xmlContent;
The result will be those not null
nodes:
<?xml version="1.0"?>
<response>
<item key="0">
<name>foo</name>
<sportsman>0</sportsman>
</item>
<item key="1">
<name>bar</name>
<age>33</age>
</item>
</response>
There is a better solution also since November 2016 with this feature : [Serializer] XmlEncoder : Add a way to remove empty tags
You just have to put the context parameter remove_empty_tags
to true like this example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With