Closed
Description
Description
The documentation for ObjectNormalizer
states that "It supports calling the constructor during the denormalization process." but that is not true when one of the constructor arguments is an array of objects. Currently (since #19649), is is only possible to denormalize an "array of objects" property if that property has a setter method or is public.
Example
#!/usr/bin/env php
<?php
namespace App;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
require __DIR__ . '/vendor/autoload.php';
class Item
{
/**
* @var string
*/
private $id;
/**
* Item constructor.
* @param string $id
*/
public function __construct(string $id)
{
$this->id = $id;
}
public function getId(): string
{
return $this->id;
}
}
class Pack
{
/**
* @var Item[]
*/
private $items;
/**
* Pack constructor.
* @param Item[] $items
*/
public function __construct(array $items)
{
$this->items = $items;
}
public function getItems(): array
{
return $this->items;
}
}
$phpDocExtractor = new PhpDocExtractor();
$normalizer = new ObjectNormalizer(null, null, null, $phpDocExtractor);
$serializer = new Serializer([$normalizer, new ArrayDenormalizer()]);
$itemData = ["id" => "1"];
$listData = ['items' => [$itemData]];
dump($serializer->denormalize($listData, Pack::class));
Executing this script from a project root will print:
App\Pack {#20
-items: array:1 [
0 => array:1 [
"id" => "1"
]
]
}
The expected result is:
App\Pack {#18
-items: array:1 [
0 => App\Item {#40
-id: "1"
}
]
}
That expected result can be obtained by replacing the constructor of Pack
with a setter for $items
:
#!/usr/bin/env php
<?php
namespace App;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
require __DIR__ . '/vendor/autoload.php';
class Item
{
/**
* @var string
*/
private $id;
/**
* Item constructor.
* @param string $id
*/
public function __construct(string $id)
{
$this->id = $id;
}
public function getId(): string
{
return $this->id;
}
}
class Pack
{
/**
* @var Item[]
*/
private $items;
public function setItems(array $items): self
{
$this->items = $items;
return $this;
}
public function getItems(): array
{
return $this->items;
}
}
$phpDocExtractor = new PhpDocExtractor();
$normalizer = new ObjectNormalizer(null, null, null, $phpDocExtractor);
$serializer = new Serializer([$normalizer, new ArrayDenormalizer()]);
$itemData = ["id" => "1"];
$listData = ['items' => [$itemData]];
dump($serializer->denormalize($listData, Pack::class));