6

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
    }
]
David Spiess
  • 600
  • 1
  • 11
  • 21

1 Answers1

7

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.

Kuba Birecki
  • 2,926
  • 1
  • 13
  • 16
  • I actually tried that already, but it only seems to work for serialization, not for deserialization. – David Spiess Apr 05 '16 at 19:39
  • 1
    How do you expect to skip null properties when deserializing ? If the data is not there, it will be null. – Kuba Birecki Apr 05 '16 at 19:43
  • Sounds indeed reasonable. So my only option would be to recursively filter all null properties out after i get the deserialized object? – David Spiess Apr 05 '16 at 19:52
  • I'm not sure what you mean by filtering out null properties. Could you maybe post a simple example of what you have, and what you're trying to accomplish ? – Kuba Birecki Apr 05 '16 at 19:55
  • I updated my answer. Let me know if you find it helpful or if I missed something. – Kuba Birecki Apr 05 '16 at 20:42
  • if the fields aren't present, they aren't serialized and deserializing you don't assign anything, so they'll be null. What am I missing? This seems to be a question about a non-existent problem. – Scott Sosna Apr 05 '16 at 22:11
  • Old thread but still. Why are we using @Type-annotations then? If i use the annotation @Type('string') and initialize my field with an empty string as well then i do not want a null value in there. Due to using reflection and phps weak types the object will be successfully deserialized...until i try to use a getter with a return type. – Tamali Oct 10 '19 at 09:07