2

I have Reservation entity, which contains some ReservationRev(isions) collection. ReservationRev contains PersonStay collection.

In Reservation I have virtual property personStays (getter, add, remove, setter).

When I try to POST Reservation with personStays I get an error - denormalizer for Collection can't be found.

class Reservation

/**
 * @var Collection
 * @Doctrine\ORM\Mapping\OneToMany(
 *     targetEntity="Zakjakub\OswisAccommodationBundle\Entity\ReservationRev",
 *     mappedBy="container",
 *     cascade={"all"},
 *     orphanRemoval=true
 * )
 */
protected $revisions;

public function __construct(Nameable $nameable, ...) {
    $this->revisions = new ArrayCollection();
    $this->addRevision(new ReservationRev($nameable));
    ...
}

final public function addPersonStay(?PersonStay $personStay): void
{
    if (!$this->getPersonStays()->contains($personStay)) {
        $newRevision = clone $this->getRevisionByDate();
        $newRevision->addPersonStay($personStay);
        $this->addRevision($newRevision);
    }
}

final public function getPersonStays(?\DateTime $dateTime = null): Collection
{
    return $this->getRevisionByDate($dateTime)->getPersonStays() ?? new ArrayCollection();
}

final public function removePersonStay(?PersonStay $personStay): void
{
    if ($this->getPersonStays()->contains($personStay)) {
        $newRevision = clone $this->getRevisionByDate();
        $newRevision->removePersonStay($personStay);
        $this->addRevision($newRevision);
    }
}

final public function setPersonStays(?Collection $personStays): void
{
    $newRevision = clone $this->getRevisionByDate();
    $newRevision->setPersonStays($personStays ?? new ArrayCollection());
    $this->addRevision($newRevision);
}

class ReservationRev

/**
 * @var Collection
 * @Doctrine\ORM\Mapping\ManyToMany(
 *     targetEntity="Zakjakub\OswisAccommodationBundle\Entity\PersonStay",
 *     inversedBy="reservationRevisions",
 *     cascade={"all"}
 * )
 * @Doctrine\ORM\Mapping\JoinTable(name="accommodation_reservations_person_stays")
 */
protected $personStays;

/**
 * @var Reservation
 * @Doctrine\ORM\Mapping\ManyToOne(
 *     targetEntity="Zakjakub\OswisAccommodationBundle\Entity\Reservation",
 *     inversedBy="revisions"
 * )
 * @Doctrine\ORM\Mapping\JoinColumn(name="container_id", referencedColumnName="id")
 */
protected $container;

public function __construct(Nameable $nameable, ...) {
    $this->personStays = new ArrayCollection();
    ...
}

final public function addPersonStay(?PersonStay $personStay): void
{
    if ($personStay) {
        return;
    }
    if (!$this->personStays->contains($personStay)) {
        $this->personStays->add($personStay);
        $personStay->addReservationRevision($this);
    }
}

final public function removePersonStay(?PersonStay $personStay): void
{
    if ($personStay) {
        return;
    }
    if ($this->personStays->removeElement($personStay)) {
        $personStay->removeReservationRevision($this);
    }
}

final public function setPersonStays(Collection $personStays): void
{
    foreach ($this->personStays as $personStay) {
        if (!$personStays->contains($personStay)) {
            $this->removePersonStay($personStay);
        }
    }
    foreach ($personStays as $personStay) {
        if (!$this->personStays->contains($personStay)) {
            $this->addPersonStay($personStay);
        }
    }
}

/**
 * @return Collection
 */
final public function getPersonStays(): Collection
{
    return $this->personStays ?? new ArrayCollection();
}

class PersonStay

/**
 * @var Person
 * @Doctrine\ORM\Mapping\ManyToOne(
 *     targetEntity="Zakjakub\OswisAccommodationBundle\Entity\Person",
 *     inversedBy="personStays",
 *     cascade={"all"}
 * )
 * @Doctrine\ORM\Mapping\JoinColumn(name="person_id", referencedColumnName="id")
 */
protected $person;

/**
 * @var Collection
 * @Doctrine\ORM\Mapping\ManyToMany(
 *     targetEntity="Zakjakub\OswisAccommodationBundle\Entity\ReservationRev",
 *     mappedBy="personStays"
 * )
 */
protected $reservationRevisions;

/**
 * @var Room
 * @Doctrine\ORM\Mapping\ManyToOne(
 *     targetEntity="Zakjakub\OswisAccommodationBundle\Entity\Room",
 *     inversedBy="personStays",
 *     cascade={"persist"}
 * )
 * @Doctrine\ORM\Mapping\JoinColumn(name="room_id", referencedColumnName="id")
 */
protected $room;

public function __construct(
    ?Person $person = null,
    ?ReservationRev $reservationRevision = null,
    ?Room $room = null,
    ...
) {
    $this->setPerson($person);
    $this->reservationRevisions = new ArrayCollection();
    $this->addReservationRevision($reservationRevision);
    $this->setRoom($room);
    ...
}

/**
 * @param ReservationRev|null $reservationRev
 */
final public function addReservationRevision(?ReservationRev $reservationRev): void
{
    if (!$reservationRev) {
        return;
    }
    if (!$this->reservationRevisions->contains($reservationRev)) {
        $this->reservationRevisions->add($reservationRev);
        $reservationRev->addPersonStay($this);
    }
}

/**
 * @return Person
 */
final public function getPerson(): ?Person
{
    return $this->person;
}

/**
 * Set person.
 *
 * @param Person|null $person
 */
final public function setPerson(?Person $person): void
{
    if (null !== $this->person) {
        $this->person->removePersonStay($this);
    }
    if ($person && $this->person !== $person) {
        $person->addPersonStay($this);
        $this->person = $person;
    }
}

/**
 * @return Room|null
 */
final public function getRoom(): ?Room
{
    return $this->room;
}

/**
 * @param Room|null $room
 */
final public function setRoom(?Room $room): void
{
    if (null !== $this->room) {
        $this->room->removePersonStay($this);
    }
    if ($room && $this->room !== $room) {
        $room->addPersonStay($this);
        $this->room = $room;
    }
}

/**
 * @return Collection
 */
final public function getReservationRevisions(): Collection
{
    return $this->reservationRevisions ?? new ArrayCollection();
}

/**
 * @param ReservationRev|null $reservationRev
 */
final public function removeReservationRevision(?ReservationRev $reservationRev): void
{
    if (!$reservationRev) {
        return;
    }
    if ($this->reservationRevisions->removeElement($reservationRev)) {
        $reservationRev->removePersonStay($this);
    }
}

POST

{ "personStays": null (or [] or [<some person stays>]), "description": "string", "note": "string" }

Error

Could not denormalize object of type Doctrine\\Common\\Collections\\Collection, no supporting normalizer found.

Symfony 4.2.2

Api-platform 2.3.6

Jakub Zak
  • 41
  • 2
  • 8
  • In `getPersonStays ` method you mentioned that it returns `Collection` here -> `: Collection`. Change it to `ArrayCollection`. And other places too. – Evgeny Ruban Jan 26 '19 at 20:08
  • `Return value of Zakjakub\OswisAccommodationBundle\Entity\Reservation::getPersonStays() must be an instance of Doctrine\Common\Collections\ArrayCollection, instance of Doctrine\ORM\PersistentCollection returned.` – Jakub Zak Jan 27 '19 at 12:33
  • check this answer https://stackoverflow.com/a/44099807/6130313 – Evgeny Ruban Jan 28 '19 at 13:23
  • Yes, I know how to fix it (I have it exactly as it says in the linked answer all the time - using Collection interface). But your previous answer says that I have to change it to ArrayCollection - it's oposite of linked answer. – Jakub Zak Jan 28 '19 at 17:08

0 Answers0