Closed smilesrg closed 2 years ago
UPD: Put iterable type to a setter, because
public function setNestedFoos(iterable $foos);
works well, but
/**
* @param NestedFoo[] $nestedFoos
*/
public function setNestedFoos(\Doctrine\Common\Collections\Collection $nestedFoos);
will lead to a type error:
Failed to denormalize attribute "nestedFoos" value for class "App\Document\Foo": Expected argument of type "Doctrine\Common\Collections\Collection", "array" given at property path "nestedFoos".
if you want to use the ArrayCollection
type, set it just right in the setter:
/**
* @param iterable<NestedFoo> $nestedFoos
*/
public function setNestedFoos(iterable $nestedFoos)
{
if ($nestedFoos instanceof Collection) {
$this->nestedFoos = $nestedFoos;
} else {
$this->nestedFoos = new ArrayCollection($nestedFoos);
}
}
You can also want to type-hint your property with the Collection
interface, full class listing would look like this:
namespace App\Document;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ODM\Document
*/
class Foo
{
/**
* @var Collection<NestedFoo>
*
* @ODM\Field
* @Assert\All({
* @Assert\Type(NestedFoo::class)
* })
* @Assert\Valid()
*/
private Collection $nestedFoos;
public function __construct()
{
$this->nestedFoos = new ArrayCollection();
}
/**
* @return Collection<NestedFoo>
*/
public function getNestedFoos(): Collection
{
return $this->nestedFoos;
}
/**
* @param iterable<NestedFoo> $nestedFoos
*/
public function setNestedFoos(iterable $nestedFoos)
{
if ($nestedFoos instanceof Collection) {
$this->nestedFoos = $nestedFoos;
} else {
$this->nestedFoos = new ArrayCollection($nestedFoos);
}
}
}
I'm not sure if it's better to use ArrayCollection
instead of Collection
.
this is a symfony or jms serializer question i guess.
The right type hint to use in the property is Collection
. In your settrs you can use whatever you prefer but the important thing is that when setting the prop you make it a subclass of Collection
(as example ArrayCollection
).
On a side note, Your setNestedFoos
should avoid $this->nestedFoos = new ArrayCollection((array)$nestedFoos);
but rather try to update the collection making a diff of it (otherwise you might get some weird edgecases...)
this is a symfony or jms serializer question i guess.
It goes tightly with the “fos_rest.request_body” converter, so I mention that it is worth adding these hints to the docs.
In your settrs you can use whatever you prefer
No. If I use Collection
, serializer deserializes a collection of nested entities into the array of objects. And that will lead to a type error.
I faced with the issue where
fos_rest.request_body
could not detect the type of nested objects. I used MongoDB ODM. Without@var
annotation it doesn't detect nested object types, also field type should beiterable
and initialized as anArrayCollection
Example:Similar problem and my answer on Stackoverflow: https://stackoverflow.com/questions/60410008/symfony-fos-rest-request-body-converter-do-not-deserialize-nested-dto-classes/68236473#68236473
I think it worth adding to the documentation "how to specify the type of the nested object for a proper deserialization" as it didn't mentioned anywhere, I had to spend half of the day digging this issue.