Skip to content

Commit 8ffc0b6

Browse files
janedbalondrejmirtes
authored andcommitted
Rewrite to ExpressionTypeResolverExtension
1 parent fce74ca commit 8ffc0b6

File tree

3 files changed

+77
-72
lines changed

3 files changed

+77
-72
lines changed

extension.neon

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,6 @@ services:
136136
class: PHPStan\Type\Doctrine\Query\QueryGetDqlDynamicReturnTypeExtension
137137
tags:
138138
- phpstan.broker.dynamicMethodReturnTypeExtension
139-
-
140-
class: PHPStan\Type\Doctrine\QueryBuilder\QueryBuilderReturnedDynamicReturnTypeExtension
141-
tags:
142-
- phpstan.broker.dynamicMethodReturnTypeExtension
143139
-
144140
class: PHPStan\Type\Doctrine\CreateQueryDynamicReturnTypeExtension
145141
arguments:
@@ -173,6 +169,11 @@ services:
173169
descendIntoOtherMethods: %doctrine.searchOtherMethodsForQueryBuilderBeginning%
174170
parser: @defaultAnalysisParser
175171

172+
-
173+
class: PHPStan\Type\Doctrine\QueryBuilder\ReturnQueryBuilderExpressionTypeResolverExtension
174+
tags:
175+
- phpstan.broker.expressionTypeResolverExtension
176+
176177
-
177178
class: PHPStan\Stubs\Doctrine\StubFilesExtensionLoader
178179
tags:

src/Type/Doctrine/QueryBuilder/QueryBuilderReturnedDynamicReturnTypeExtension.php

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Doctrine\QueryBuilder;
4+
5+
use Doctrine\ORM\QueryBuilder;
6+
use PhpParser\Node\Expr;
7+
use PhpParser\Node\Expr\MethodCall;
8+
use PhpParser\Node\Identifier;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Reflection\ParametersAcceptorSelector;
11+
use PHPStan\Type\ExpressionTypeResolverExtension;
12+
use PHPStan\Type\ObjectType;
13+
use PHPStan\Type\Type;
14+
use PHPStan\Type\TypeCombinator;
15+
use function count;
16+
use function str_starts_with;
17+
18+
class ReturnQueryBuilderExpressionTypeResolverExtension implements ExpressionTypeResolverExtension
19+
{
20+
21+
/** @var OtherMethodQueryBuilderParser */
22+
private $otherMethodQueryBuilderParser;
23+
24+
public function __construct(
25+
OtherMethodQueryBuilderParser $otherMethodQueryBuilderParser
26+
)
27+
{
28+
$this->otherMethodQueryBuilderParser = $otherMethodQueryBuilderParser;
29+
}
30+
31+
public function getType(Expr $expr, Scope $scope): ?Type
32+
{
33+
if (!$expr instanceof MethodCall) {
34+
return null;
35+
}
36+
37+
if (!$expr->name instanceof Identifier) {
38+
return null;
39+
}
40+
41+
$queryBuilderType = new ObjectType(QueryBuilder::class);
42+
$callerType = $scope->getType($expr->var);
43+
44+
foreach ($callerType->getObjectClassNames() as $callerObjectClassName) {
45+
if (str_starts_with($callerObjectClassName, 'Doctrine')) {
46+
return null; // do not dive into native Doctrine methods (like EntityRepository->createQueryBuilder)
47+
}
48+
}
49+
50+
$methodReflection = $scope->getMethodReflection($callerType, $expr->name->name);
51+
52+
if ($methodReflection === null) {
53+
return null;
54+
}
55+
56+
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
57+
58+
$returnsQueryBuilder = $queryBuilderType->isSuperTypeOf($returnType)->yes();
59+
60+
if (!$returnsQueryBuilder) {
61+
return null;
62+
}
63+
64+
$queryBuilderTypes = $this->otherMethodQueryBuilderParser->findQueryBuilderTypesInCalledMethod($scope, $expr);
65+
if (count($queryBuilderTypes) === 0) {
66+
return null;
67+
}
68+
69+
return TypeCombinator::union(...$queryBuilderTypes);
70+
}
71+
72+
}

0 commit comments

Comments
 (0)