Psalm and PHPStan unable to read Symfony entity string:class

787 Views Asked by At

I'm implementing PHPStan into my application and also testing Psalm for automatic fixes, however I'm unable to make them read entity class strings (with colon) fe:

$repository = $this->em->getRepository('MyApp:EntityClass');

turns into Psalm error:

ERROR: UndefinedClass - src/Controller/MyController.php:229:48 - Class, interface or enum named MyApp:EntityClass does not exist (see https://psalm.dev/019)

and in PHP Stan

  Line   src/Controller/MyController.php                                                                                                               
 ------ --------------------------------------------------------------------------------------------------------------------------------------------------- 
  229    Parameter #1 $className of method Doctrine\ORM\EntityManagerInterface::getRepository() expects class-string<MyApp:EntityClass>, string given.  
 ------ --------------------------------------------------------------------------------------------------------------------------------------------------- 

Easiest way to fix this is to use \EntityClass::class instead of a string 'MyApp:EntityClass' however I would like to avoid that. Probable I need to use some annotation to make both tools interprete string correctly, but I have problems figuring out which one. It would also be nice to have it avaialble globaly via entire app, and don't use annotation each time I call a class via string. Currently I've just added this error to ignored ones but would like to know how to fix that.

1

There are 1 best solutions below

0
Michael Hirschler On

Easiest way to fix this is to use \EntityClass::class instead of a string 'MyApp:EntityClass' however I would like to avoid that.

You already wrote the recommended answer. Using shortname alias is deprecated since doctrine/orm v2.10. It'll probably be removed in v3.0. You should consider upgrading.

That said, this is the only sustainable solution.

$repository = $this->em->getRepository(EntityClass::class);

Install phpstan/phpstan-doctrine

Using phpstan without phpstan-doctrine is not recommended (while interpreting types of a doctrine entity). Install the phpstan extension phpstan/phpstan-doctrine and configure it. It interpretes types of QueryBuilder and Repository inside your project; like EntityManager::getReposiotry(EntityClass::class):

composer require --dev phpstan/phpstan-doctrine
# phpstan.neon
parameters:
    doctrine:
        objectManagerLoader: tests/object-manager.php

Optional: automatic refactoring

That said, you really should update your code base. To ease that process, you could use rector using the EntityAliasToClassConstantReferenceRector. Correctly configured, you're done in seconds.

composer require --dev rector/rector
// rector.php

<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Doctrine\Rector\MethodCall\EntityAliasToClassConstantReferenceRector;

return static function (RectorConfig $rectorConfig): void {
    $rectorConfig->phpstanConfig(__DIR__.'/phpstan.neon');

    $rectorConfig->ruleWithConfiguration(EntityAliasToClassConstantReferenceRector::class, [
        EntityAliasToClassConstantReferenceRector::ALIASES_TO_NAMESPACES => [
            'MyApp' => 'App\Entity',
        ]
    ]);
};