doctrine / orm

Doctrine Object Relational Mapper (ORM)
https://www.doctrine-project.org/projects/orm.html
MIT License
9.86k stars 2.5k forks source link

PHPDoc of `QueryBuilder::setAttributes` breaks Psalm #11451

Open MatteoFeltrin opened 1 month ago

MatteoFeltrin commented 1 month ago

BC Break Report

In our actual version (2.19.3), QueryBuilder::setParamters() was accepting a standard array as input

/**
  * @param ArrayCollection|mixed[] $parameters The query parameters to set.
  * @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
  *
  * @return $this
  */
public function setParameters($parameters) {}

In the latest version it wants an ArrayCollection<int, Parameter>.

/**
  * @psalm-param ArrayCollection<int, Parameter> $parameters
  *
  * @return $this
  */
public function setParameters(ArrayCollection $parameters): static {}

The problem here is that it is forcing the ArrayCollection to have int datatype as key, so it's not accepting an array of fixed width as this one:

$this->entityManager->createQueryBuilder()
            ->setParameters(new ArrayCollection(
                [
                    new Parameter('customStringId', $customStringId->id),
                    new Parameter('license', $license),
                ],
            ))

This is the error from Psalm:

Argument 1 of Doctrine\ORM\QueryBuilder::setParameters expects Doctrine\Common\Collections\ArrayCollection<int, Doctrine\ORM\Query\Parameter>, but Doctrine\Common\Collections\ArrayCollection<int<0, 1>, Doctrine\ORM\Query\Parameter> provided (see https://psalm.dev/004)
            ->setParameters(new ArrayCollection(
                [
                    new Parameter('customStringId', $customStringId->id),
                    new Parameter('license', $license),
                ],
            ))
Q A
BC Break yes
Version from 2.19.3 to 3.1.3.

Previous behavior

QueryBuilder::setParamters() was accepting any type of array -- mixed[]

Current behavior

PHPDoc of QueryBuilder::setParamters() is too strict, asking exaclty for int as key and not allowed fixed length array to be used

How to reproduce

Call the method ->setParameters of Doctrine 3 passing as parameter an ArrayCollection() with an array of fixed with as paramter, then execute Psalm.

Solution

A templating should be used to allow a more "flexible" int datatype to be inferred from the input parameter

/**
  * @template TKey of int
  * 
  * @psalm-param ArrayCollection<TKey, Parameter> $parameters
  *
  * @return $this
  */
public function setParameters(ArrayCollection $parameters): static {}