Home > Back-end >  Doctrine PHPStan entity relation Collection never written, only read
Doctrine PHPStan entity relation Collection never written, only read

Time:05-30

I am attempting to use the correct typings according to Doctrine and PHPStan, however with an entity relation, I can't seem to make it right.

I am using PHP 8.1.6, Doctrine 2.6.3, PHPStan 1.7.3 and PHPStan/Doctrine 1.3.6.

My entity looks like this:

#[ORM\Entity]
class Thing
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(options: ['unsigned' => true])]
    private ?int $id;

    #[ORM\Column]
    private string $name;

    /** @var Collection&iterable<Item> $items */
    #[ORM\OneToMany(mappedBy: 'thing', targetEntity: Item::class)]
    private Collection $items;

    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * @return iterable<Items>
     */
    public function getItems(): iterable
    {
        return $this->items;
    }
}

For the ID, it's not complaining (doctrine rules are loaded into PHPStan, which works just fine). However, for the $items Collection, it's saying "is never written, only read". This makes no sense as it is a Collection, and will not be written (but rather added to through it's methods).

I am not quite understanding why it is giving me this error, and I can't seem to find much about it, other than "It should work".

CodePudding user response:

You have no "setters" nor "adders/removers" for that private property. So, PhpStan is indeed right.

Either remove that property entirely from the inversed side of that relation (aka in the Thing class) or add some "adders/removers".

This usually looks something like this.

public function addItem(Item $item): self
{
    if (!$this->items->contains($items)) {
        $this->items[] = $item;
        // optional but keeps both sides in sync
        $item->setThing($this);
    }

    return $this;
}

public function removeItem(Item $item): self
{
    $this->items->removeElement($item);
    // should your Item::thing be not nullable, skip this
    $item->setThing(null);

    return $this;
}
  • Related