Search code examples
phpjms-serializer

Mixing Accessor and SkipWhenEmpty in JMS Serializer


I'm using JMS serializer in a project, and I'm struggling with one thing.

I'm using the @Accessor annotation (On a DateTime property) to echo only the date without the time. But on some of my objects, I won't have any information and I don't want the date key to be outputted when this case occurs.

Without the @Accessor, I can easily use @SkipWhenEmpty which works perfectly on other attributes. But it seems I can't mix the two of them ?

Here is my example code :

composer.json:

{
    "require": {
        "jms/serializer": "^1.14"
    }
}

StackOverflowExample.php:

<?php

declare(strict_types=1);

use JMS\Serializer\Annotation as Serializer;

class StackOverflowExample
{
    /**
     * @var \DateTime
     * @Serializer\Accessor(getter="getDate")
     * @Serializer\SkipWhenEmpty()
     */
    private $date;

    /**
     * @var string
     * @Serializer\SkipWhenEmpty()
     */
    private $title;

    public function getDate(): string
    {
        if (null === $this->date) {
            return '';
        }

        return $this->date->format('Y-m-d');
    }

    public function setDate(\DateTime $date): void
    {
        $this->date = $date;
    }

    public function getTitle(): string
    {
        return $this->title;
    }

    public function setTitle(string $title): void
    {
        $this->title = $title;
    }
}

stackoverflow.php:

<?php

$loader = require __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/StackOverflowExample.php';
\Doctrine\Common\Annotations\AnnotationRegistry::registerLoader([$loader, 'loadClass']);

$serializer = \JMS\Serializer\SerializerBuilder::create()->build();

$testWithDateAndTitle = new StackOverflowExample();
$testWithDateAndTitle->setDate(new DateTime());
$testWithDateAndTitle->setTitle('Example with date and title');

$testWithDateAndNoTitle = new StackOverflowExample();
$testWithDateAndNoTitle->setDate(new DateTime());

$testWithNoDateButTitle = new StackOverflowExample();
$testWithNoDateButTitle->setTitle('Example with title but no date');

echo $serializer->serialize($testWithDateAndTitle, 'json').PHP_EOL;
echo $serializer->serialize($testWithDateAndNoTitle, 'json').PHP_EOL;
echo $serializer->serialize($testWithNoDateButTitle, 'json').PHP_EOL;

When executing stackoverflow.php, here is the data it outputs:

{"date":"2019-05-03","title":"Example with date and title"}
{"date":"2019-05-03"}
{"date":"","title":"Example with title but no date"}

The first line is a control.

On the second line, when omitting to set a title there is no "title" key in the outputted json, thanks to @SkipWhenEmpty

But on the third line, even with @SkipWhenEmpty, I still have the date key.

Is there something I'm forgetting ? How could I echo the date field only when it is filled ?


Solution

  • With my research, i think you need return null and not

    return '';

    in your getDate function.

    See