Skip to content

Commit f6259c4

Browse files
committed
Support new Expr() in QueryBuilder calls
1 parent 0c093ae commit f6259c4

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Type\Doctrine\QueryBuilder;
44

55
use PhpParser\Node\Expr\MethodCall;
6+
use PhpParser\Node\Expr\New_;
67
use PhpParser\Node\Identifier;
78
use PHPStan\Analyser\Scope;
89
use PHPStan\Reflection\MethodReflection;
@@ -13,6 +14,7 @@
1314
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
1415
use PHPStan\Type\Doctrine\Query\QueryType;
1516
use PHPStan\Type\Type;
17+
use PHPStan\Type\TypeWithClassName;
1618
use function in_array;
1719
use function method_exists;
1820
use function strtolower;
@@ -127,8 +129,16 @@ protected function processArgs(Scope $scope, string $methodName, array $methodCa
127129
$args = [];
128130
foreach ($methodCallArgs as $arg) {
129131
$value = $scope->getType($arg->value);
132+
if (
133+
$arg->value instanceof New_
134+
&& $value instanceof TypeWithClassName
135+
&& strpos($value->getClassName(), 'Doctrine\ORM\Query\Expr') === 0
136+
) {
137+
$className = $value->getClassName();
138+
$args[] = new $className(...$this->processArgs($scope, '__construct', $arg->value->args));
139+
continue;
140+
}
130141
// todo $qb->expr() support
131-
// todo new Expr\Andx support
132142
if ($value instanceof ConstantArrayType) {
133143
$array = [];
134144
foreach ($value->getKeyTypes() as $i => $keyType) {

tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ public function testRule(): void
5454
'QueryBuilder: [Semantical Error] line 0, col 60 near \'transient = \': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named transient',
5555
107,
5656
],
57+
[
58+
"QueryBuilder: [Syntax Error] line 0, col 82: Error: Expected end of string, got ')'\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE e.id = 1 ORDER BY e.name) ASC",
59+
129,
60+
],
61+
[
62+
'QueryBuilder: [Semantical Error] line 0, col 78 near \'name ASC\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named name',
63+
139,
64+
],
5765
]);
5866
}
5967

tests/Rules/Doctrine/ORM/data/query-builder-dql.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,34 @@ public function limitOffsetCorrect(int $offset, int $limit): void
124124
->getQuery();
125125
}
126126

127+
public function addNewExprSyntaxError(): void
128+
{
129+
$this->entityManager->createQueryBuilder()
130+
->select('e')
131+
->from(MyEntity::class, 'e')
132+
->andWhere('e.id = 1')
133+
->add('orderBy', new \Doctrine\ORM\Query\Expr\OrderBy('e.name)', 'ASC'))
134+
->getQuery();
135+
}
136+
137+
public function addNewExprSemanticError(): void
138+
{
139+
$this->entityManager->createQueryBuilder()
140+
->select('e')
141+
->from(MyEntity::class, 'e')
142+
->andWhere('e.id = 1')
143+
->add('orderBy', new \Doctrine\ORM\Query\Expr\OrderBy('e.name', 'ASC'))
144+
->getQuery();
145+
}
146+
147+
public function addNewExprCorrect(): void
148+
{
149+
$this->entityManager->createQueryBuilder()
150+
->select('e')
151+
->from(MyEntity::class, 'e')
152+
->andWhere('e.id = 1')
153+
->add('orderBy', new \Doctrine\ORM\Query\Expr\OrderBy('e.title', 'ASC'))
154+
->getQuery();
155+
}
156+
127157
}

0 commit comments

Comments
 (0)