Constructor argument with the same name as property
At first I had this DTO which in constructor does some logic to change weird API structure which I am consuming
readonly class Item
{
public ItemDetails $Details;
public function __construct(
public int $Id,
?object $Details = null,
) {
// Details->Item is array but it always contain one element
/** @var ?object{Name?: string} */
$item = $Details?->Item[0] ?? null;
$this->Details = new ItemDetails(
Name: $item->Name ?? null,
);
}
}
class ItemDetails
{
public function __construct(
public ?string $Name = null,
) {}
}
When I dropped readonly from Item, instead of receiving in constructor raw stdClass (which comes from SoapClient) I started to receive ItemDetails with Name as null. Which lead to unfortunate bugs.
I fixed this with transformer
class Item
{
public function __construct(
public int $Id,
#[MapFrom(transformer: [self::class, 'transformDetails'])]
public ItemDetails $Details,
) {}
public static function transformDetails(?stdClass $Details, mixed $source, mixed $context): ItemDetails
{
// Details->Item is array but it always contain one element
/** @var ?object{Name?: string} */
$item = $Details?->Item[0] ?? null;
return new ItemDetails(
Name: $item->Name ?? null,
);
}
}
I can see now that this is the right way to do this from the get go.
But it got me thinking should AutoMapper protect against this?
As far as I can tell this happened after removing readonly because with readonly properties AutoMapper assign them VoidTransformer which just passes parameter, but without readonly Details got assigned ObjectTransformer which created empty ItemDetails.
To fix this maybe use property metadata for constructor argument only if this argument is promoted?
I can work on implementation, I just wanted to know first will you support this