automapper icon indicating copy to clipboard operation
automapper copied to clipboard

Support for Nested Property Mapping for Array to Object mapping

Open TheoD02 opened this issue 1 year ago • 2 comments

Description

I would like to map using nested properties for array to object mapping in the current implementation.

Example

Given an input array:

[
    'saved_at' => '2024-01-01',
    'track' => [
        'uri' => 'uri-code',
     ]
]

And the following entity definition:

#[ORM\Entity(repositoryClass: TrackRepository::class)]
class Track
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[MapFrom(source: 'array', property: 'track.uri')] // tested with [track][uri] like PropertyAccessor
    #[ORM\Column(length: 100)]
    private ?string $uri = null;

    // ... other properties and methods
}

Issue

Currently, when attempting to map the nested track.uri property to the Track entity's uri property, the generated mapping does not appear to handle nested properties as expected. The generated code is:

if (array_key_exists('track.uri', $value) && \AutoMapper\MapperContext::isAllowedAttribute($context, 'track.uri', !isset($value['track.uri'])) && (!array_key_exists('groups', $context) || !$context['groups'])) {
    $result->setUri($value['track.uri']);
}

The code attempts to access track.uri as a single key in the array, instead of navigating through the nested structure.

Expected Behavior

The mapping should properly navigate the nested array structure and map the track.uri value to the uri property of the Track entity. For instance:

if (isset($value['track']['uri']) && \AutoMapper\MapperContext::isAllowedAttribute($context, 'track.uri', !isset($value['track']['uri'])) && (!array_key_exists('groups', $context) || !$context['groups'])) {
    $result->setUri($value['track']['uri']);
}

Questions

  1. Is it possible to support nested properties for array to object mapping?
  2. If not currently supported, are there plans to implement this feature?

TheoD02 avatar Jul 27 '24 15:07 TheoD02

👍 It would be great. As a workaroud, you can use transformer :

    #[MapFrom(source: 'array', property: 'track', transformer: "source['track']['uri'] ?? null")]
    #[ORM\Column(length: 100)]
    private ?string $uri = null;

dsoriano avatar Sep 30 '24 13:09 dsoriano

You should indeed use a transformer for that, we don't want to do property interpolation here, some api may provide a dot in their property name (weird but already seen it).

I keep this open as we should certainly provide a documentation about how to do this (not the first time it is asked)

joelwurtz avatar Oct 22 '24 09:10 joelwurtz