diff --git a/src/Rules/Doctrine/ORM/MagicRepositoryMethodCallRule.php b/src/Rules/Doctrine/ORM/MagicRepositoryMethodCallRule.php index 021dd273..ef8939ce 100644 --- a/src/Rules/Doctrine/ORM/MagicRepositoryMethodCallRule.php +++ b/src/Rules/Doctrine/ORM/MagicRepositoryMethodCallRule.php @@ -4,6 +4,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Broker\Broker; use PHPStan\Rules\Rule; use PHPStan\Type\Doctrine\ObjectMetadataResolver; use PHPStan\Type\Doctrine\ObjectRepositoryType; @@ -15,9 +16,13 @@ class MagicRepositoryMethodCallRule implements Rule /** @var ObjectMetadataResolver */ private $objectMetadataResolver; - public function __construct(ObjectMetadataResolver $objectMetadataResolver) + /** @var Broker */ + private $broker; + + public function __construct(ObjectMetadataResolver $objectMetadataResolver, Broker $broker) { $this->objectMetadataResolver = $objectMetadataResolver; + $this->broker = $broker; } public function getNodeType(): string @@ -78,6 +83,11 @@ public function processNode(Node $node, Scope $scope): array return []; } + $repositoryReflectionClass = $this->broker->getClass($calledOnType->getClassName()); + if ($repositoryReflectionClass->hasNativeMethod($methodName)) { + return []; + } + return [sprintf( 'Call to method %s::%s() - entity %s does not have a field named $%s.', $calledOnType->describe(VerbosityLevel::typeOnly()), diff --git a/tests/Rules/Doctrine/ORM/MagicRepositoryMethodCallRuleTest.php b/tests/Rules/Doctrine/ORM/MagicRepositoryMethodCallRuleTest.php index 76818817..60ea5d65 100644 --- a/tests/Rules/Doctrine/ORM/MagicRepositoryMethodCallRuleTest.php +++ b/tests/Rules/Doctrine/ORM/MagicRepositoryMethodCallRuleTest.php @@ -12,7 +12,9 @@ class MagicRepositoryMethodCallRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MagicRepositoryMethodCallRule(new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', null)); + $broker = $this->createBroker(); + + return new MagicRepositoryMethodCallRule(new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', null), $broker); } public function testRule(): void @@ -26,21 +28,33 @@ public function testRule(): void 'Call to method Doctrine\ORM\EntityRepository::findByNonexistent() - entity PHPStan\Rules\Doctrine\ORM\MyEntity does not have a field named $nonexistent.', 25, ], + [ + 'Call to method Doctrine\ORM\EntityRepository::findByCustomMethod() - entity PHPStan\Rules\Doctrine\ORM\MyEntity does not have a field named $customMethod.', + 26, + ], [ 'Call to method Doctrine\ORM\EntityRepository::findOneByTransient() - entity PHPStan\Rules\Doctrine\ORM\MyEntity does not have a field named $transient.', - 34, + 35, ], [ 'Call to method Doctrine\ORM\EntityRepository::findOneByNonexistent() - entity PHPStan\Rules\Doctrine\ORM\MyEntity does not have a field named $nonexistent.', - 35, + 36, ], [ 'Call to method Doctrine\ORM\EntityRepository::countByTransient() - entity PHPStan\Rules\Doctrine\ORM\MyEntity does not have a field named $transient.', - 44, + 45, ], [ 'Call to method Doctrine\ORM\EntityRepository::countByNonexistent() - entity PHPStan\Rules\Doctrine\ORM\MyEntity does not have a field named $nonexistent.', - 45, + 46, + ], + [ + 'Call to method PHPStan\Rules\Doctrine\ORM\TestRepository::findByTransient() - entity PHPStan\Rules\Doctrine\ORM\MySecondEntity does not have a field named $transient.', + 55, + ], + [ + 'Call to method PHPStan\Rules\Doctrine\ORM\TestRepository::findByNonexistent() - entity PHPStan\Rules\Doctrine\ORM\MySecondEntity does not have a field named $nonexistent.', + 56, ], ]); } diff --git a/tests/Rules/Doctrine/ORM/data/MySecondEntity.php b/tests/Rules/Doctrine/ORM/data/MySecondEntity.php new file mode 100644 index 00000000..d1b31308 --- /dev/null +++ b/tests/Rules/Doctrine/ORM/data/MySecondEntity.php @@ -0,0 +1,32 @@ +getResult(); } + public function findByCustomMethod(): array + { + return []; + } + } diff --git a/tests/Rules/Doctrine/ORM/data/magic-repository.php b/tests/Rules/Doctrine/ORM/data/magic-repository.php index e157b16a..2a031e46 100644 --- a/tests/Rules/Doctrine/ORM/data/magic-repository.php +++ b/tests/Rules/Doctrine/ORM/data/magic-repository.php @@ -23,6 +23,7 @@ public function doFindBy(): void $entityRepository->findByTitle('test'); $entityRepository->findByTransient('test'); $entityRepository->findByNonexistent('test'); + $entityRepository->findByCustomMethod(); } public function doFindOneBy(): void @@ -45,4 +46,14 @@ public function doCountBy(): void $entityRepository->countByNonexistent('test'); } + public function doFindByWithRepository(): void + { + $entityRepository = $this->entityManager->getRepository(MySecondEntity::class); + $entityRepository->findBy(['id' => 1]); + $entityRepository->findById(1); + $entityRepository->findByTitle('test'); + $entityRepository->findByTransient('test'); + $entityRepository->findByNonexistent('test'); + $entityRepository->findByCustomMethod(); + } }