Reputation: 21268
Having the following PHP class
class SampleObject
{
private $map;
private $array;
public function getMap(): array
{
return $map;
}
public function setMap(array $map)
{
$this->map = $map;
}
public function getArray(): array
{
return $this->array;
}
public function setArray(array $array) {
$this->array = $array;
}
}
and two instances:
$inst1 = new SampleObject();
$inst2 = new SampleObject();
$inst1->setMap(['key' => 'value']);
$inst1->setArray([1]);
$inst2->setMap([]);
$inst2->setArray([]);
When they are serialized with JMS Serializer to json, the first one becomes:
{"map": {"key": "value"}, "array": [1]}
and the second one:
{"map": [], "array": []}
How to force the serializer to serialize the second object as {"map": {}, "array": []}
?
Upvotes: 1
Views: 2966
Reputation: 753
You can modify the array serialization behavior by setting context information on the serialize
method (or using annotations etc.)
You'll find these examples about serializing arrays and hashes in the cookbook:
<?php
// default (let the PHP's json_encode function decide)
$serializer->serialize([1, 2]); // [1, 2]
$serializer->serialize(['a', 'b']); // ['a', 'b']
$serializer->serialize(['c' => 'd']); // {"c" => "d"}
// same as default (let the PHP's json_encode function decide)
$serializer->serialize([1, 2], SerializationContext::create()->setInitialType('array')); // [1, 2]
$serializer->serialize([1 => 2], SerializationContext::create()->setInitialType('array')); // {"1": 2}
$serializer->serialize(['a', 'b'], SerializationContext::create()->setInitialType('array')); // ['a', 'b']
$serializer->serialize(['c' => 'd'], SerializationContext::create()->setInitialType('array')); // {"c" => "d"}
// typehint as strict array, keys will be always discarded
$serializer->serialize([], SerializationContext::create()->setInitialType('array<integer>')); // []
$serializer->serialize([1, 2], SerializationContext::create()->setInitialType('array<integer>')); // [1, 2]
$serializer->serialize(['a', 'b'], SerializationContext::create()->setInitialType('array<integer>')); // ['a', 'b']
$serializer->serialize(['c' => 'd'], SerializationContext::create()->setInitialType('array<string>')); // ["d"]
// typehint as hash, keys will be always considered
$serializer->serialize([], SerializationContext::create()->setInitialType('array<integer,integer>')); // {}
$serializer->serialize([1, 2], SerializationContext::create()->setInitialType('array<integer,integer>')); // {"0" : 1, "1" : 2}
$serializer->serialize(['a', 'b'], SerializationContext::create()->setInitialType('array<integer,integer>')); // {"0" : "a", "1" : "b"}
$serializer->serialize(['c' => 'd'], SerializationContext::create()->setInitialType('array<string,string>')); // {"d" : "d"}
Upvotes: 1
Reputation: 21268
As @EmanuelOster suggested in the comment, the custom handler can be used for this purpose. While the solution is not perfect (an annotation on the field would be much better), it works. Here is a sample handler
class SampleObjectSerializer implements SubscribingHandlerInterface {
public static function getSubscribingMethods() {
return [
[
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => SampleObject::class,
'method' => 'serialize',
],
];
}
public function serialize(JsonSerializationVisitor $visitor, SampleObject $object, array $type, Context $context) {
return [
'array' => $object->getArray(),
'map' => $this->emptyArrayAsObject($object->getMap()),
];
}
/**
* Forces to searialize empty array as json object (i.e. {} instead of []).
* @see https://stackoverflow.com/q/41588574/878514
*/
private function emptyArrayAsObject(array $array) {
if (count($array) == 0) {
return new \stdClass();
}
return $array;
}
}
If using Symfony, you need to register it.
Upvotes: 1