phpstan-doctrine icon indicating copy to clipboard operation
phpstan-doctrine copied to clipboard

QueryBuilder Result returns mixed when created in another method

Open alexander-schranz opened this issue 3 years ago • 23 comments

I'm still running into the https://github.com/phpstan/phpstan-doctrine/issues/266 issue, which I thought should be fixed with: https://github.com/phpstan/phpstan-doctrine/commit/149cf71c3b470f815ad8ad658606e9217db22d9f

But in my cases it ends still in mixed state.

I created a reproducer here:

git clone [email protected]:alexander-schranz/phpstan-query-builder-reproducer.git
cd phpstan-query-builder-reproducer/
composer install

vendor/bin/phpstan analyse

https://github.com/alexander-schranz/phpstan-query-builder-reproducer/blob/main/src/Repository/VisitorRepository.php

Output:

 ------ ----------------------------------------------------------------------------------------------------------
  Line   src/Repository/VisitorRepository.php
 ------ ----------------------------------------------------------------------------------------------------------
  46     Dumped type: mixed
  48     Method App\Repository\VisitorRepository::findBy() should return iterable<App\Entity\Visitor> but returns
         mixed.
  60     Dumped type: mixed
  62     Method App\Repository\VisitorRepository::findFlatBy() should return iterable<array{id: int, title:
         string|null}> but returns mixed.
  75     Dumped type: mixed
  77     Method App\Repository\VisitorRepository::findOneBy() should return App\Entity\Visitor|null but returns
         mixed.
  90     Dumped type: mixed
  92     Method App\Repository\VisitorRepository::getOneBy() should return App\Entity\Visitor but returns mixed.
 ------ ----------------------------------------------------------------------------------------------------------

Not sure what is different then to the test case 🤔

alexander-schranz avatar Mar 29 '22 12:03 alexander-schranz

Have the same problem here, but cannot find the root cause. The QueryResultDynamicReturnTypeExtension always gives me MixedType as $queryResultType so i cannot infer the right type. But i cannot figure out why this is the case.

sabbelasichon avatar Jun 28 '22 14:06 sabbelasichon

Should have read better the documentation. Added the option objectManagerLoader with a proper php configuration and now it works.

sabbelasichon avatar Jun 28 '22 21:06 sabbelasichon

Nice but apparently it's not the case for the reproduction repo: https://github.com/alexander-schranz/phpstan-query-builder-reproducer/blob/26c04ecb3495a187f75d8082e53a5749cc62b3ff/phpstan.neon#L18

ondrejmirtes avatar Jun 28 '22 21:06 ondrejmirtes

Same probleme here. @sabbelasichon can you explain please what does mean Added the option objectManagerLoader with a proper php configuration

lenybernard avatar Jul 18 '22 20:07 lenybernard

@lenybernard

can you explain please what does mean Added the option objectManagerLoader with a proper php configuration

See README about objectManagerLoader configuration:

  • https://github.com/phpstan/phpstan-doctrine#configuration

Or here another example from our sulu/skeleton which is symfony based:

  • https://github.com/sulu/skeleton/blob/581ad8dbcca60def7c5b3f66cc125c4cc3111296/phpstan.neon#L7-L8
  • https://github.com/sulu/skeleton/blob/2.5/tests/phpstan/object-manager.php

Sadly it doesn't work for my case. But hope it works for you.

alexander-schranz avatar Jul 18 '22 21:07 alexander-schranz

@alexander-schranz same problem for me. The proposed solution does not work... 😢

cyrille-osyla avatar Jul 19 '22 13:07 cyrille-osyla

Can't get it to work either with the suggestions mentioned above. To ignore this error (supports subnamespaces like App\Entity\Foo\Bar and findXXX() methods returning a (nullable) entity or array of entities):

# phpstan.neon
parameters:
  ignoreErrors:
    - '#Method App\\Repository\\(\w+\\)*\w+Repository::(get|find)\w+\(\) should return ((array|iterable)<)?App\\Entity\\(\w+\\)*\w+(>)?(\|null)? but returns (object|mixed)\.#'

CodeCasterNL avatar Jul 19 '22 14:07 CodeCasterNL

Ignored error pattern #Method App\\Repository\\(\w+\\)*\w+Repository::find\w+\(\) should return (array<)?App\\Entity\\(\w+\\)*\w+(>)?(\|null)? but returns mixed\.# was not matched in reported errors. @CodeCasterNL Any idea ?

cyrille-osyla avatar Jul 19 '22 14:07 cyrille-osyla

@cyrille-osyla which errors are reported for your repositories when you run PHPStan?

CodeCasterNL avatar Jul 19 '22 14:07 CodeCasterNL

@CodeCasterNL Method App\Repository\Category\CategoryRepository::getOneCategoryById() should return App\Entity\Category\Category but returns mixed.

cyrille-osyla avatar Jul 19 '22 14:07 cyrille-osyla

There's a helpful tool on PHPStan's website to generate the ignoreErrors entry: https://phpstan.org/user-guide/ignoring-errors#generate-an-ignoreerrors-entry

ondrejmirtes avatar Jul 19 '22 14:07 ondrejmirtes

@cyrille-osyla I've updated the regex, your method started with "get" instead of "find".

CodeCasterNL avatar Jul 19 '22 14:07 CodeCasterNL

@CodeCasterNL ah yes sorry... I had changed the name of the method to fix the phpstan problem otherwise. Now it works thank you

@ondrejmirtes good to know thank you !

cyrille-osyla avatar Jul 20 '22 07:07 cyrille-osyla

Hi! Is there a way to fix this without ignoring it?

takeoto avatar Apr 12 '23 08:04 takeoto

I'm also running into this issue in a bleeding edge development environment, both with Symfony 6.2 and 6.3-beta.

Simple reproducer:

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<Unit>
 */
class UnitRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Unit::class);
    }

    /**
     * @return Unit[]
     */
    public function getUnits(): array
    {
        return $this->createQueryBuilder('u')->getQuery()->getResult();
    }
}

Gives:

  35     Method App\Repository\UnitRepository::getUnits() should return array<App\Entity\Unit> but returns mixed.

Notably this only occurs at level 9, it passes without issue on level 8. PHPStan documents level 9 as:

be strict about the mixed type - the only allowed operation you can do with it is to pass it to another mixed

Looking at https://github.com/phpstan/phpstan-doctrine/blob/1.3.x/stubs/ORM/QueryBuilder.stub#L17-L22 it would seem PHPStan is shooting its own foot - the stub is prescribing something that cannot pass level 9 by definition.

curry684 avatar May 17 '23 12:05 curry684