Skip to content

Commit cf8f114

Browse files
committed
Merge remote-tracking branch 'origin/1.3.x' into 1.4.x
2 parents 9c4935f + 6ccde2b commit cf8f114

File tree

6 files changed

+49
-11
lines changed

6 files changed

+49
-11
lines changed

src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PHPStan\Type\ObjectType;
1616
use PHPStan\Type\TypeUtils;
1717
use Throwable;
18+
use function array_values;
1819
use function count;
1920
use function sprintf;
2021
use function strpos;
@@ -117,15 +118,16 @@ public function processNode(Node $node, Scope $scope): array
117118
$message .= sprintf("\nDQL: %s", $dql->getValue());
118119
}
119120

120-
$messages[] = RuleErrorBuilder::message($message)
121+
// Use message as index to prevent duplicate
122+
$messages[$message] = RuleErrorBuilder::message($message)
121123
->identifier('doctrine.dql')
122124
->build();
123125
} catch (AssertionError $e) {
124126
continue;
125127
}
126128
}
127129

128-
return $messages;
130+
return array_values($messages);
129131
}
130132

131133
}

src/Type/Doctrine/Query/QueryType.php

+19-4
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,25 @@
1111
class QueryType extends GenericObjectType
1212
{
1313

14+
/** @var Type */
15+
private $indexType;
16+
17+
/** @var Type */
18+
private $resultType;
19+
1420
/** @var string */
1521
private $dql;
1622

17-
public function __construct(string $dql, ?Type $indexType = null, ?Type $resultType = null)
23+
public function __construct(string $dql, ?Type $indexType = null, ?Type $resultType = null, ?Type $subtractedType = null)
1824
{
25+
$this->indexType = $indexType ?? new MixedType();
26+
$this->resultType = $resultType ?? new MixedType();
27+
1928
parent::__construct('Doctrine\ORM\Query', [
20-
$indexType ?? new MixedType(),
21-
$resultType ?? new MixedType(),
22-
]);
29+
$this->indexType,
30+
$this->resultType,
31+
], $subtractedType);
32+
2333
$this->dql = $dql;
2434
}
2535

@@ -32,6 +42,11 @@ public function equals(Type $type): bool
3242
return parent::equals($type);
3343
}
3444

45+
public function changeSubtractedType(?Type $subtractedType): Type
46+
{
47+
return new self('Doctrine\ORM\Query', $this->indexType, $this->resultType, $subtractedType);
48+
}
49+
3550
public function isSuperTypeOf(Type $type): TrinaryLogic
3651
{
3752
if ($type instanceof self) {

tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleSlowTest.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,18 @@ public function testRuleBranches(): void
109109
'QueryBuilder: [Semantical Error] line 0, col 58 near \'p.id = 1\': Error: \'p\' is not defined.',
110110
59,
111111
],
112-
/*[
112+
[
113113
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
114114
90,
115-
],*/
115+
],
116116
[
117117
'QueryBuilder: [Semantical Error] line 0, col 95 near \'foo = 1\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named foo',
118118
107,
119119
],
120+
[
121+
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
122+
107,
123+
],
120124
];
121125
$this->analyse([__DIR__ . '/data/query-builder-branches-dql.php'], $errors);
122126
}

tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,18 @@ public function testRuleBranches(): void
109109
'QueryBuilder: [Semantical Error] line 0, col 58 near \'p.id = 1\': Error: \'p\' is not defined.',
110110
59,
111111
],
112-
/*[
112+
[
113113
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
114114
90,
115-
],*/
115+
],
116116
[
117117
'QueryBuilder: [Semantical Error] line 0, col 95 near \'foo = 1\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named foo',
118118
107,
119119
],
120+
[
121+
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
122+
107,
123+
],
120124
];
121125
$this->analyse([__DIR__ . '/data/query-builder-branches-dql.php'], $errors);
122126
}

tests/Type/Doctrine/data/QueryResult/queryBuilderExpressionTypeResolver.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function testQueryTypeIsInferredOnAcrossMethods(EntityManagerInterface $e
2626
$branchingQuery = $this->getBranchingQueryBuilder($em)->getQuery();
2727

2828
assertType('Doctrine\ORM\Query<null, QueryResult\Entities\Many>', $query);
29-
assertType('Doctrine\ORM\Query<null, QueryResult\Entities\Many>', $branchingQuery);
29+
assertType('Doctrine\ORM\Query<null, QueryResult\Entities\Many>#1|Doctrine\ORM\Query<null, QueryResult\Entities\Many>#2', $branchingQuery);
3030
}
3131

3232
public function testQueryTypeIsInferredOnAcrossMethodsEvenWhenVariableAssignmentIsUsed(EntityManagerInterface $em): void

tests/Type/Doctrine/data/QueryResult/queryBuilderGetQuery.php

+13
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ public function testIndexByResultInfering(EntityManagerInterface $em): void
103103
assertType('array<string, array{intColumn: int, stringNullColumn: string|null}>', $result);
104104
}
105105

106+
public function testConditionalAddSelect(EntityManagerInterface $em, bool $bool): void
107+
{
108+
$qb = $em->createQueryBuilder();
109+
if ($bool) {
110+
$qb->select('m.intColumn');
111+
} else {
112+
$qb->select('m.intColumn', 'm.stringNullColumn');
113+
}
114+
$query = $qb->from(Many::class, 'm')->getQuery();
115+
116+
assertType('Doctrine\ORM\Query<null, array{intColumn: int}>|Doctrine\ORM\Query<null, array{intColumn: int, stringNullColumn: string|null}>', $query);
117+
}
118+
106119
public function testQueryResultTypeIsMixedWhenDQLIsNotKnown(QueryBuilder $builder): void
107120
{
108121
$query = $builder->getQuery();

0 commit comments

Comments
 (0)