Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[Serializer] | [PropertyAccess] Add support to fold plain properties into objects during denormalization. #51510

Copy link
Copy link
Open
@AlexMinaev19

Description

@AlexMinaev19
Issue body actions

Description

Introduction

We already have the functionality to denormalize objects from different parts of data via #[SerializedPath('[some][path]')] and with different names via #[SerializedName('different_name)].
For example,

Let's imagine we have class Foo with the next structure:

class Foo
{
    public function __construct(
        #[SerializedPath('[internal][property]')] public string $bar,
        #[SerializedName('outter')] public string $some
    ) {
    }
}

and we have the next data to denormalize:

$data = [
    'internal' => [
        'property' => 'value1',
    ],
    'outter' => 'value2',
]

When we denormalize $data via $serializer we will get the object with desirable values:

//
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));

$metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);

$serializer = new Serializer(
    [new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter)],
    ['json' => new JsonEncoder()]
);

$object = $serializer->denormalize($data, Foo::class);
$object->bar; // 'value1'
$object->some; // 'value2'

Problem description

But what about another case, when you have a plain array with multiple fields and you want to fold them into different objects?
For example, we have the following data to denormalize:

$plainData = [
    'foo' => 'value1',
    'bar' => 'value2',
    'baz' => 'value3',
    'bam' => 'value4',
    'zam' => 'value5',
    'tam' => 'value6',
    ... // and so on...
]

We can map all of these values to properties in one class, but I want to separate them by some meaning in different objects.
For example, I have the following domain classes:

class Bar
{
    public function __construct(
        public string $valueFive,
        public string $valueThree,
    ) {
    }
}

class Baz
{
    public function __construct(
        public string $valueOne,
        public string $valueSix,
        public string $valueTwo,
    ) {
    }
}

class Request
{
    public function __construct(
        public string $valueFour,  // keep fourth value in this class => can be done via #[SerializedName('bam')]
        public Bar $bar, // fold the properties 5 and 3 in the Bar::class => ?
        public Baz $baz // fold properties 1, 6, and 2 in the Baz::class => ?
    ) {
    }
}

Example

Possible solution

We can allow wildcard for #[SerializedPath]. For example, #[SerializedPath('[*]')] or #[SerializedPath('[]')] which can tell the serializer to look at properties in the current (root) scope.

Example:

$plainData = [
    'foo' => 'value1',
    'bar' => 'value2',
    'baz' => 'value3',
    'bam' => 'value4',
    'zam' => 'value5',
    'tam' => 'value6',
    ... // and so on...
]

class Bar
{
    public function __construct(
        #[SerializedName('zam')] public string $valueFive,
        #[SerializedName('baz')] public string $valueThree,
    ) {
    }
}

class Baz
{
    public function __construct(
        #[SerializedName('foo')] public string $valueOne,
        #[SerializedName('tam')] public string $valueSix,
        #[SerializedName('bar')] public string $valueTwo,
    ) {
    }
}

class Request
{
    public function __construct(
        #[SerializedName('bam')] public string $valueFour,
        #[SerializedPath('[*]')] public Bar $bar,
        #[SerializedPath('[*]')] public Baz $baz 
    ) {
    }
}

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

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.