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

support for doctrine/orm 3+?

Open arderyp opened this issue 1 year ago • 11 comments

I just upgraded orm from 2.19.0 to 3.1.0`, and as a result all of my repositories are now showing phpstan errors that this package was formerly handling, such as:

Method App\Users\Repository\UsersRolesRepository::findAll() should return array<App\Entity\UsersRoles>  
but returns mixed.

This method was triggering no such error before the orm upgrade.

I've confirmed the issue also exists on the latest orm 3.0.x

arderyp avatar Mar 05 '24 00:03 arderyp

I'm running:

phpstan-doctrine 1.3.62 orm 3.1.0 dbal 3.8.3

When I upgraded orm from latest 2.x to 3.0.x and 3.1.x, I got lots of errors about EntityManager methods returning mixed.

Am I missing something, or is orm3 only supported WITH dbal4?

I opened another issue before finding this one.

EDIT: bumping to dbal4 is throwing different errors now:

1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 -- -------------------------------------------------------------------------------------------------------------------------------------------- 
     Error                                                                                                                                       
 -- -------------------------------------------------------------------------------------------------------------------------------------------- 
     Internal error: Internal error: Doctrine\DBAL\Connection\StaticServerVersionProvider::__construct(): Argument #1 ($version) must be of      
     type string, float given, called in /app/vendor/doctrine/dbal/src/Connection.php on line 186 while  
     analysing file /app/src/Common/Repository/ApplicationsRepository.php                                
     Run PHPStan with -v option and post the stack trace to:                                                                                     
     https://github.com/phpstan/phpstan/issues/new?template=Bug_report.yaml                                                                      
     Child process error (exit code 1):                                                                                                          
 -- -------------------------------------------------------------------------------------------------------------------------------------------- 
                                                                                                               
 [ERROR] Found 2 errors

arderyp avatar Mar 05 '24 03:03 arderyp

related to https://github.com/phpstan/phpstan-doctrine/issues/529

arderyp avatar Mar 05 '24 03:03 arderyp

perhaps this is also related: https://github.com/phpstan/phpstan-doctrine/issues/308#issuecomment-1551310265

arderyp avatar Mar 05 '24 03:03 arderyp

Please post the code that leads to "Method App\Users\Repository\UsersRolesRepository::findAll() should return array<App\Entity\UsersRoles>
but returns mixed.".

And please open a separate issue for the internal error, and post the stack trace as the error message instructs you to.

ondrejmirtes avatar Mar 05 '24 06:03 ondrejmirtes

Sure. Again, no errors at all on orm 2.x and dbal 3.x. No other changes other than updating the doctrine packages.

[orm3/dbal3] findAll() should return array<App\Entity\UsersRoles> but returns mixed

<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Applications;
use Doctrine\ORM\EntityRepository;

/** @extends EntityRepository<Applications> */
class ApplicationsRepository extends EntityRepository
{
    /** @return Applications[] */
    public function findAll(): array
    {
        return $this->getEntityManager()->createQueryBuilder()
            ->select('a', 'ae')
            ->from(Applications::class, 'a')
            ->leftJoin('a.expirations', 'ae')
            ->getQuery()
            ->getResult();
    }
}

[orm3/dbal3] Internal error

Note: Using configuration file /app/phpstan.neon.
 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%  1 sec

 -- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
     Error                                                                                                                                                                   
 -- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
     Internal error: Internal error: Doctrine\DBAL\Connection\StaticServerVersionProvider::__construct(): Argument #1 ($version) must be of                                  
     type string, float given, called in /app/vendor/doctrine/dbal/src/Connection.php on line 186 while                              
     analysing file /app/src/Common/Repository/ApplicationsRepository.php                                                            
                                                                                                                                                                             
     Post the following stack trace to https://github.com/phpstan/phpstan/issues/new?template=Bug_report.yaml:                                                               
     ## /app/vendor/doctrine/dbal/src/Connection/StaticServerVersionProvider.php(11)                                                 
     #0 /app/vendor/doctrine/dbal/src/Connection.php(186):                                                                           
     Doctrine\DBAL\Connection\StaticServerVersionProvider->__construct()                                                                                                     
     #1 /app/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php(724):                                                          
     Doctrine\DBAL\Connection->getDatabasePlatform()                                                                                                                         
     #2 /app/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php(546):                                                          
     Doctrine\ORM\Mapping\ClassMetadataFactory->getTargetPlatform()                                                                                                          
     #3 /app/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php(174):                                                          
     Doctrine\ORM\Mapping\ClassMetadataFactory->completeIdGeneratorMapping()                                                                                                 
     #4 /app/vendor/doctrine/doctrine-bundle/Mapping/ClassMetadataFactory.php(18):                                                   
     Doctrine\ORM\Mapping\ClassMetadataFactory->doLoadMetadata()                                                                                                             
     #5 /app/vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php(343):                              
     Doctrine\Bundle\DoctrineBundle\Mapping\ClassMetadataFactory->doLoadMetadata()                                                                                           
     #6 /app/vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php(207):                              
     Doctrine\Persistence\Mapping\AbstractClassMetadataFactory->loadMetadata()                                                                                               
     #7 /app/vendor/doctrine/orm/src/EntityManager.php(215):                                                                         
     Doctrine\Persistence\Mapping\AbstractClassMetadataFactory->getMetadataFor()                                                                                             
     #8 /app/vendor/doctrine/orm/src/Query/Parser.php(1570):                                                                         
     Doctrine\ORM\EntityManager->getClassMetadata()                                                                                                                          
     #9 /app/vendor/doctrine/orm/src/Query/Parser.php(1414):                                                                         
     Doctrine\ORM\Query\Parser->RangeVariableDeclaration()                                                                                                                   
     #10 /app/vendor/doctrine/orm/src/Query/Parser.php(1183):                                                                        
     Doctrine\ORM\Query\Parser->IdentificationVariableDeclaration()                                                                                                          
     #11 /app/vendor/doctrine/orm/src/Query/Parser.php(769): Doctrine\ORM\Query\Parser->FromClause()                                 
     #12 /app/vendor/doctrine/orm/src/Query/Parser.php(740):                                                                         
     Doctrine\ORM\Query\Parser->SelectStatement()                                                                                                                            
     #13 /app/vendor/doctrine/orm/src/Query/Parser.php(221): Doctrine\ORM\Query\Parser->QueryLanguage()                              
     #14 /app/vendor/doctrine/orm/src/Query/Parser.php(309): Doctrine\ORM\Query\Parser->getAST()                                     
     #15 /app/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/Query/QueryResultTypeWalker.php(121):                                
     Doctrine\ORM\Query\Parser->parse()                                                                                                                                      
     #16                                                                                                                                                                     
     /app/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php(198):    
     PHPStan\Type\Doctrine\Query\QueryResultTypeWalker::walk()                                                                                                               
     #17                                                                                                                                                                     
     /app/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php(181):    
     PHPStan\Type\Doctrine\QueryBuilder\QueryBuilderGetQueryDynamicReturnTypeExtension->getQueryType()                                                                       
     #18 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(3619):                                       
     PHPStan\Type\Doctrine\QueryBuilder\QueryBuilderGetQueryDynamicReturnTypeExtension->getTypeFromMethodCall()                                                              
     #19 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(1416):                                       
     PHPStan\Analyser\MutatingScope->methodCallReturnType()                                                                                                                  
     #20 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(1422):                                       
     PHPStan\Analyser\MutatingScope->PHPStan\Analyser\{closure}()                                                                                                            
     #21 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(587):                                        
     PHPStan\Analyser\MutatingScope->resolveType()                                                                                                                           
     #22                                                                                                                                                                     
     /app/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/QueryBuilder/ReturnQueryBuilderExpressionTypeResolverExtension.php(78):  
     PHPStan\Analyser\MutatingScope->getType()                                                                                                                               
     #23                                                                                                                                                                     
     /app/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/QueryBuilder/ReturnQueryBuilderExpressionTypeResolverExtension.php(46):  
     PHPStan\Type\Doctrine\QueryBuilder\ReturnQueryBuilderExpressionTypeResolverExtension->getMethodReflection()                                                             
     #24 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(605):                                        
     PHPStan\Type\Doctrine\QueryBuilder\ReturnQueryBuilderExpressionTypeResolverExtension->getType()                                                                         
     #25 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(587):                                        
     PHPStan\Analyser\MutatingScope->resolveType()                                                                                                                           
     #26 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Rules/FunctionReturnTypeCheck.php(52):                                  
     PHPStan\Analyser\MutatingScope->getType()                                                                                                                               
     #27 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Rules/Methods/ReturnTypeRule.php(43):                                   
     PHPStan\Rules\FunctionReturnTypeCheck->checkReturnType()                                                                                                                
     #28 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(107):                                         
     PHPStan\Rules\Methods\ReturnTypeRule->processNode()                                                                                                                     
     #29 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Node/ClassStatementsGatherer.php(108):                                  
     PHPStan\Analyser\FileAnalyser->PHPStan\Analyser\{closure}()                                                                                                             
     #30 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(577):                                    
     PHPStan\Node\ClassStatementsGatherer->__invoke()                                                                                                                        
     #31 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(468):                                    
     PHPStan\Analyser\NodeScopeResolver::PHPStan\Analyser\{closure}()                                                                                                        
     #32 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(411):                                    
     PHPStan\Analyser\NodeScopeResolver->processStmtNode()                                                                                                                   
     #33 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(576):                                    
     PHPStan\Analyser\NodeScopeResolver->processStmtNodes()                                                                                                                  
     #34 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(411):                                    
     PHPStan\Analyser\NodeScopeResolver->processStmtNode()                                                                                                                   
     #35 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(678):                                    
     PHPStan\Analyser\NodeScopeResolver->processStmtNodes()                                                                                                                  
     #36 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(411):                                    
     PHPStan\Analyser\NodeScopeResolver->processStmtNode()                                                                                                                   
     #37 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(650):                                    
     PHPStan\Analyser\NodeScopeResolver->processStmtNodes()                                                                                                                  
     #38 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(380):                                    
     PHPStan\Analyser\NodeScopeResolver->processStmtNode()                                                                                                                   
     #39 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(166):                                         
     PHPStan\Analyser\NodeScopeResolver->processNodes()                                                                                                                      
     #40 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php(132):                                         
     PHPStan\Analyser\FileAnalyser->analyseFile()                                                                                                                            
     #41                                                                                                                                                                     
     phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):             
     PHPStan\Command\WorkerCommand->PHPStan\Command\{closure}()                                                                                                              
     #42 phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/clue/ndjson-react/src/Decoder.php(117):                              
     _PHPStan_cc8d35ffb\Evenement\EventEmitter->emit()                                                                                                                       
     #43                                                                                                                                                                     
     phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):             
     _PHPStan_cc8d35ffb\Clue\React\NDJson\Decoder->handleData()                                                                                                              
     #44 phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/Util.php(62):                                       
     _PHPStan_cc8d35ffb\Evenement\EventEmitter->emit()                                                                                                                       
     #45                                                                                                                                                                     
     phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):             
     _PHPStan_cc8d35ffb\React\Stream\Util::_PHPStan_cc8d35ffb\React\Stream\{closure}()                                                                                       
     #46                                                                                                                                                                     
     phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/DuplexResourceStream.php(154):                          
     _PHPStan_cc8d35ffb\Evenement\EventEmitter->emit()                                                                                                                       
     #47                                                                                                                                                                     
     phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(201):                          
     _PHPStan_cc8d35ffb\React\Stream\DuplexResourceStream->handleData()                                                                                                      
     #48                                                                                                                                                                     
     phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(173):                          
     _PHPStan_cc8d35ffb\React\EventLoop\StreamSelectLoop->waitForStreamActivity()                                                                                            
     #49 phar:///app/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php(98):                                          
     _PHPStan_cc8d35ffb\React\EventLoop\StreamSelectLoop->run()                                                                                                              
     #50                                                                                                                                                                     
     phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Command/Command.php(259):                                
     PHPStan\Command\WorkerCommand->execute()                                                                                                                                
     #51 phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(870):                                
     _PHPStan_cc8d35ffb\Symfony\Component\Console\Command\Command->run()                                                                                                     
     #52 phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(261):                                
     _PHPStan_cc8d35ffb\Symfony\Component\Console\Application->doRunCommand()                                                                                                
     #53 phar:///app/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(157):                                
     _PHPStan_cc8d35ffb\Symfony\Component\Console\Application->doRun()                                                                                                       
     #54 phar:///app/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(124):                                                           
     _PHPStan_cc8d35ffb\Symfony\Component\Console\Application->run()                                                                                                         
     #55 phar:///app/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(125):                                                           
     _PHPStan_cc8d35ffb\{closure}()                                                                                                                                          
     #56 /app/vendor/phpstan/phpstan/phpstan(8): require('...')                                                                      
     #57 /app/vendor/bin/phpstan(119): include('...')                                                                                
     #58 {main}                                                                                                                                                              
     Child process error (exit code 1):                                                                                                                                      
 -- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 

 [ERROR] Found 2 errors                                                                                                 
                                                                                                                        
Used memory: 132.5 MB

arderyp avatar Mar 05 '24 17:03 arderyp

if there's something you'd like me to test @ondrejmirtes, or some other info I can provide to help, just let me know.

I know it's a bit thorny to debug these more complex dependency issues remotely, since it can't be easily replicated on phpstan,org

as always, I value all of your work!

arderyp avatar Mar 06 '24 22:03 arderyp

hey @ondrejmirtes, just wanted to check in on this

or perhaps the answer is, it simply isn't supported at this time (due to https://github.com/phpstan/phpstan-doctrine/issues/529)?

arderyp avatar Jun 28 '24 00:06 arderyp

Hi, phpstan-doctrine fully supports ORM 3 and DBAL 4.

You're experiencing this error:

Internal error: Internal error: Doctrine\DBAL\Connection\StaticServerVersionProvider::__construct(): Argument #1 ($version) must be of type string, float given, called in /app/vendor/doctrine/dbal/src/Connection.php on line 186 while analysing file /app/src/Common/Repository/ApplicationsRepository.php

So in your case the analysis is crashing because of these lines:

https://github.com/doctrine/dbal/blob/90424473eb144659a89fb1b5c9bca37297085351/src/Connection.php#L185-L189

Meaning this is not a fault of phpstan-doctrine, but of your own Connection configuration. $this->params['serverVersion'] and $this->params['primary']['serverVersion'] need to contain a string, not a float.

Please refer to the Doctrine documentation to figure out how to configure this properly.

It's also possible this is a bug in DBAL itself.

As for:

Method App\Users\Repository\UsersRolesRepository::findAll() should return array<App\Entity\UsersRoles>
but returns mixed.

I'm not sure what goes wrong in this case. We have tests for this scenario that are passing even with ORM 3/DBAL 4.

ondrejmirtes avatar Jun 28 '24 08:06 ondrejmirtes

extremely helpful, I really appreciate you taking the time to provide such a helpful response!

arderyp avatar Jun 28 '24 16:06 arderyp

@ondrejmirtes I've just tested and getting the same results on orm 3.2.1 using ->serverVersion('8.0.25') in my doctrine config. Is there something I should debug/dump that would be helpful?

EDIT: this is while running dbal 3.8.6, trying 4.x now...

arderyp avatar Jun 28 '24 17:06 arderyp

@ondrejmirtes I think the serverVersion issue demonstrated here, which you explained how to fix, was a red herring. This issue was suddenly triggered on dbal 4 because a new deprecation was introduced in 4 that required a verbose version number (like 1.2.3 instead o 1.2, not to mention the string vs float issue)

Once I addressed that, the original issues resurfaced, lots of expected mixed despite apparently proper configuration and no issues on orm 3.1.0/dbal 3.8.3. I am not running:

dbal 4.0.4 orm 3.2.1 phpstan-doctrine 1.4.3

Examples:

Method App\Repository\ApplicationsRepository::findAll() should return array<App\Entity\Applications> but returns mixed. 

<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Applications;
use Doctrine\ORM\EntityRepository;

/** @extends EntityRepository<Applications> */
class ApplicationsRepository extends EntityRepository
{
    /** @return Applications[] */
    public function findAll(): array
    {
        return $this->getEntityManager()->createQueryBuilder()
            ->select('a', 'ae')
            ->from(Applications::class, 'a')
            ->leftJoin('a.expirations', 'ae')
            ->getQuery()
            ->getResult();
    }
}

Oddly enough, it resolves this issue: https://github.com/phpstan/phpstan-doctrine/issues/525

arderyp avatar Jun 28 '24 18:06 arderyp

Hey, I'm sorry, but I don't see anything actionable I could use to fix these errors. If you find the time, please submit a failing test here.

ondrejmirtes avatar Sep 01 '24 13:09 ondrejmirtes