Search code examples
phpsymfonyserializationjmsserializerbundlejms-serializer

How to serialize empty array to JSON object (curly braces) with JMS Serializer in Symfony


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": []}?


Solution

  • 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.