Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repository extending ServiceEntityRepository not using generic #651

Closed
andersonamuller opened this issue Mar 26, 2025 · 8 comments
Closed

Comments

@andersonamuller
Copy link

andersonamuller commented Mar 26, 2025

When running PHPStan from another vendor than the one the doctrine package is installed it doesn't seem to work as expected.

I have created a reproducible repo in https://github.com/andersonamuller/phpstan-doctrine-repro

composer install
composer -d app install
vendor/bin/phpstan --configuration=app/phpstan.php

It does NOT work for the documented case:

<?php
namespace App\Repository;

use App\Entity\MyEntity;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

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

    public function findFirst(): ?MyEntity
    {
        return $this->find(1);
    }
}

But it does work in this other case that we shouldn't extend from:

<?php
namespace App\Repository;

use App\Entity\MyEntity;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryProxy;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepositoryProxy<MyEntity>
 */
class MyRepositoryProxy extends ServiceEntityRepositoryProxy
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, MyEntity::class);
    }

    public function findFirst(): ?MyEntity
    {
        return $this->find(1);
    }
}
@ondrejmirtes
Copy link
Member

phpstan-doctrine is not aware of ServiceEntityRepositoryProxy in any way. Looking at the docs it's an internal class you should not extend: https://github.com/doctrine/DoctrineBundle/blob/66b89bcfd250e31303a545e1b59773a007977d0e/src/Repository/ServiceEntityRepositoryProxy.php#L22-L28

@andersonamuller
Copy link
Author

Yes, maybe I was not clear, I'm only extending the proxy class, because the other one did not work.

If you run the analysis on the repo I shared you see this output

 vendor/bin/phpstan --configuration=app/phpstan.php --debug -vvv

 ! [NOTE] The Xdebug PHP extension is active, but "--xdebug" is not used.                                               
 !        The process was restarted and it will not halt at breakpoints.                                                
 !        Use "--xdebug" if you want to halt at breakpoints.                                                            

Result cache not used because of debug mode.
/var/www/opt/andersonamuller/phpstan-doctrine-repro/app/src/Repository/MyRepository.php
--- consumed 14 MB, total 78 MB, took 0.20 s
/var/www/opt/andersonamuller/phpstan-doctrine-repro/app/src/Repository/MyRepositoryProxy.php
--- consumed 0 B, total 78 MB, took 0.04 s
/var/www/opt/andersonamuller/phpstan-doctrine-repro/app/src/Kernel.php
--- consumed 10.5 MB, total 88.5 MB, took 0.25 s
/var/www/opt/andersonamuller/phpstan-doctrine-repro/app/src/Entity/MyEntity.php
--- consumed 0 B, total 88.5 MB, took 0.02 s
/var/www/opt/andersonamuller/phpstan-doctrine-repro/app/bootstrap.php
--- consumed 0 B, total 88.5 MB, took 0.01 s
Result cache is saved.
 ------ ----------------------------------------------------------------------------------------------------------------- 
  Line   src/Repository/MyRepository.php                                                                                  
 ------ ----------------------------------------------------------------------------------------------------------------- 
  23     Method App\Repository\MyRepository::findFirst() should return App\Entity\MyEntity|null but returns object|null.  
         🪪  return.type                                                                                                  
 ------ ----------------------------------------------------------------------------------------------------------------- 


                                                                                                                        
 [ERROR] Found 1 error                                                                                                  
                                                                                                                        

PHP runtime version: 8.4.5
PHP version for analysis: 8.4.5 (from runtime)

PHPStan version: 2.1.11
PHPStan running from:
/var/www/opt/andersonamuller/phpstan-doctrine-repro/vendor/phpstan/phpstan

Extension installer:
phpstan/phpstan-doctrine: 2.0.2

Discovered Composer project root:
/var/www/opt/andersonamuller/phpstan-doctrine-repro

Parallel processing scheduler:
# of detected CPU cores:   20
# of analysed files:       5
# of jobs:                 1
# of spawned processes:    1

Doctrine's objectManagerLoader: No
Installed Doctrine packages:
doctrine/dbal: 4.2.3
doctrine/orm: 3.3.2
doctrine/collections: 2.3.0
doctrine/persistence: 4.0.0

Elapsed time: 1 second
Used memory: 88.5 MB

@ondrejmirtes
Copy link
Member

Running vendor/bin/phpstan --configuration=app/phpstan.php from root does not work, but running:

../vendor/bin/phpstan analyse --configuration phpstan.php

from app works as expected.

Not sure why you're using two composer.json files. PHPStan works best when you include it in the project you're analysing.

The reason why running it from inside app works is because it sees composer.json in the current working directory, which lets it see Doctrine dependencies.

@andersonamuller
Copy link
Author

andersonamuller commented Mar 26, 2025

We use a monorepo for different applications and don´t want to install phpstan with all the plugins in each one, so the phpstan is installed as a separate tool, also to avoid dependency conflicts.

Thanks for the suggestion, I will try that.

@ondrejmirtes
Copy link
Member

also to avoid dependency conflicts.

You cannot have dependency conflicts with PHPStan: https://github.com/phpstan/phpstan/blob/fdd5ad98e8a8a5a061f791e82fac5b16f0a51a1e/composer.json#L6-L8

@janedbal
Copy link
Contributor

You cannot have dependency conflicts with PHPStan

Technically, you can. As PHPStan is often used with other extension libs.

@andersonamuller
Copy link
Author

andersonamuller commented Mar 27, 2025

Running vendor/bin/phpstan --configuration=app/phpstan.php from root does not work, but running:

../vendor/bin/phpstan analyse --configuration phpstan.php

from app works as expected.

Not sure why you're using two composer.json files. PHPStan works best when you include it in the project you're analysing.

The reason why running it from inside app works is because it sees composer.json in the current working directory, which lets it see Doctrine dependencies.

Yes that worked! Thank you. My wrong assumption was that phpstan was changing the working directory based on the config file location, like phpunit does for instance. I even used the app/vendor/autoload.php in the parameters.bootstrapFiles section, which helped in some other cases, but it was not enough for this specific case.

I will close that one, but let me know if this deserves to be pointed at some documentation.

@andersonamuller
Copy link
Author

You cannot have dependency conflicts with PHPStan

Technically, you can. As PHPStan is often used with other extension libs.

Exactly, we use it with other extensions, and is just how generally we use development tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants