Elao/PhpEnums

Support for denormalizing XML to an integer Readable enum

Closed this issue · 2 comments

Consider the following enum class:

<?php

namespace App\Enum;

use Elao\Enum\ChoiceEnumTrait;
use Elao\Enum\ReadableEnum;

/**
 * @method static FooBarEnum FOO()
 * @method static FooBarEnum BAR()
 */
class FooBarEnum extends ReadableEnum
{
    use ChoiceEnumTrait;

    const FOO = 1;
    const BAR = 2;

    protected static function choices(): array
    {
        return [
            static::FOO => "Foo",
            static::BAR => "Bar",
        ];
    }
}

And the following object class:

<?php

namespace App\Model;

use App\Enum\FooBarEnum;

class SomeClass
{
    /**
     * @var FooBarEnum
     */
    private FooBarEnum $fooBarEnum

    /**
     * @return FooBarEnum
     */
    public function getFooBarEnum(): FooBarEnum
    {
        return $this->fooBarEnum;
    }

    /**
     * @param FooBarEnum $fooBarEnum
     */
    public function setFooBarEnum(FooBarEnum $fooBarEnum): void
    {
        $this->fooBarEnum = $fooBarEnum;
    }
}

Then I try to denormalize the following XML:

<some_class>
    <foo_bar_enum>1</foo_bar_enum>
</some_class>

I get the following error:

"1" is not an acceptable value for "App\Enum\FooBarEnum" enum.

I believe that this happens, because the value "1" is decoded as a string, because XML (see also the Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer).

As a workaround I tried to change the enum class:

// ...

    const FOO = "1";
    const BAR = "2";

// ...

That won't work either, because these constants are being used in this bundle as array keys, which are being mapped as integer by php.

My proposal would be to convert to an integer if necessary in a similar way as in the AbstractObjectDenormalizer, see code.

Sure, so basically attempting with the casted value as integer, if the format is XML or CSV and ctype_digit($data) || '-' === $data[0] && ctype_digit(substr($data, 1)) is true?
That'll might do it. Would you like to give it a try?

That should indeed be a good starter. I'll start a PR soon.