Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exclude null properties in JMS Serializer

My consumed XML API has an option to retrieve only parts of the response. This causes the resulting object to have a lot of NULL properties if this feature is used. Is there a way to actually skip NULL properties? I tried to implement an exclusion strategy with

shouldSkipProperty(PropertyMetadata $property, Context $context)`

but i realized there is no way to access the current property value.

An example would be the following class

class Hotel {
    /**
     * @Type("string")
     */
    public $id;

    /**
     * @Type("integer")
     */
    public $bookable;

    /**
     * @Type("string")
     */
    public $name;

    /**
     * @Type("integer")
     */
    public $type;

    /**
     * @Type("double")
     */
    public $stars;

    /**
     * @Type("MssPhp\Schema\Response\Address")
     */
    public $address;

    /**
     * @Type("integer")
     */
    public $themes;

    /**
     * @Type("integer")
     */
    public $features;

    /**
     * @Type("MssPhp\Schema\Response\Location")
     */
    public $location;

    /**
     * @Type("MssPhp\Schema\Response\Pos")
     */
    public $pos;

    /**
     * @Type("integer")
     */
    public $price_engine;

    /**
     * @Type("string")
     */
    public $language;

    /**
     * @Type("integer")
     */
    public $price_from;
}

which deserializes in this specific api call to the following object with a lot of null properties.

"hotel": [
    {
        "id": "11230",
        "bookable": 1,
        "name": "Hotel Test",
        "type": 1,
        "stars": 3,
        "address": null,
        "themes": null,
        "features": null,
        "location": null,
        "pos": null,
        "price_engine": 0,
        "language": "de",
        "price_from": 56
    }
]

But i want it to be

"hotel": [
    {
        "id": "11230",
        "bookable": 1,
        "name": "Hotel Test",
        "type": 1,
        "stars": 3,
        "price_engine": 0,
        "language": "de",
        "price_from": 56
    }
]
like image 455
David Spiess Avatar asked Apr 05 '16 14:04

David Spiess


1 Answers

You can configure JMS Serializer to skip null properties like so:

$serializer = JMS\SerializerBuilder::create();              
$serializedString = $serializer->serialize(
    $data,
    'xml',
    JMS\SerializationContext::create()->setSerializeNull(true)
);

Taken from this issue.

UPDATE:

Unfortunately, if you don't want the empty properties when deserializing, there is no other way then removing them yourself.

However, I'm not sure what your use case for actually wanting to remove these properties is, but it doesn't look like the Hotel class contains much logic. In this case, I'm wondering whether the result has should be a class at all ?

I think it would be more natural to have the data represented as an associative array instead of an object. Of course, JMS Serializer cannot deserialize your data into an array, so you will need a data transfer object.

It's enough that you add dumpArray and loadArray methods to your existing Hotel class. These will be used for transforming the data into your desired result and vice versa. There is your DTO.

/**
 * Sets the object's properties based on the passed array
 */
public function loadArray(array $data)
{
}

/**
 * Returns an associative array based on the objects properties
 */
public function dumpArray()
{
    // filter out the properties that are empty here
}

I believe it's the cleanest approach and it might reflect what you're trying to do more.

I hope this helps.

like image 183
Kuba Birecki Avatar answered Sep 19 '22 15:09

Kuba Birecki