Skip to content

[Serializer] Preserve array keys while normalize/denormalize variadic parameters #49616

@melya

Description

@melya

Description

Hi symfony!

Currently I'm in a need in preserving array keys when normalize/denormalize variadic parameters.
And hopefully this will be helpful for community.

Next example shows everything I'd like to propose

   // serializer/Tests/Normalizer/AbstractNormalizerTest.php


    /**
     * @dataProvider getNormalizer
     */
    public function testVariadicSerializationWithPreservingKeys(AbstractNormalizer $normalizer): void
    {
        $d1 = new Dummy();
        $d1->foo = 'Foo';
        $d1->bar = 'Bar';
        $d1->baz = 'Baz';
        $d1->qux = 'Quz';
        $d2 = new Dummy();
        $d2->foo = 'FOO';
        $d2->bar = 'BAR';
        $d2->baz = 'BAZ';
        $d2->qux = 'QUZ';
        $arr = ["d1" => $d1, "d2" => $d2];
        $obj = new VariadicConstructorTypedArgsDummy(...$arr);

        $serializer = new Serializer([$normalizer], [new JsonEncoder()]);
        $normalizer->setSerializer($serializer);

        $this->assertEquals(
            '{"foo":{"d1":{"foo":"Foo","bar":"Bar","baz":"Baz","qux":"Quz"},"d2":{"foo":"FOO","bar":"BAR","baz":"BAZ","qux":"QUZ"}}}',
            $data = $serializer->serialize($obj, 'json')
        );
        
        // Currently the result of serialization will be as bellow (without preserving keys)
        /*
        {
            "foo": [
                {
                    "foo": "Foo",
                    "bar": "Bar",
                    "baz": "Baz",
                    "qux": "Quz"
                },
                {
                    "foo": "FOO",
                    "bar": "BAR",
                    "baz": "BAZ",
                    "qux": "QUZ"
                }
            ]
        }
        */

        $dummy = $normalizer->denormalize(json_decode($data, true), VariadicConstructorTypedArgsDummy::class);
        $this->assertInstanceOf(VariadicConstructorTypedArgsDummy::class, $dummy);
        $this->assertEquals($arr, $dummy->getFoo());
    }

Tested with

PHP: 8.1
symfony/serializer:6.2

Example

Seems like there is a simple change needed

// serializer/Normalizer/AbstractNormalizer.php::346

abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface
{
// ...

    protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes, string $format = null)
    {
       // ... 
       // Line: 346
                        $variadicParameters = [];
                        // Fix is in respecting $parameterKey while denormalizing parameter
                        foreach ($data[$paramName] as $parameterKey => $parameterData) {
                            $variadicParameters[$parameterKey] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $attributeContext, $format);
                        }
       // ...                        
    }
// ...
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions