Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/1.3.x' into 1.4.x
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Mar 18, 2024
2 parents 9c4935f + 6ccde2b commit cf8f114
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 11 deletions.
6 changes: 4 additions & 2 deletions src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PHPStan\Type\ObjectType;
use PHPStan\Type\TypeUtils;
use Throwable;
use function array_values;
use function count;
use function sprintf;
use function strpos;
Expand Down Expand Up @@ -117,15 +118,16 @@ public function processNode(Node $node, Scope $scope): array
$message .= sprintf("\nDQL: %s", $dql->getValue());
}

$messages[] = RuleErrorBuilder::message($message)
// Use message as index to prevent duplicate
$messages[$message] = RuleErrorBuilder::message($message)
->identifier('doctrine.dql')
->build();
} catch (AssertionError $e) {
continue;
}
}

return $messages;
return array_values($messages);
}

}
23 changes: 19 additions & 4 deletions src/Type/Doctrine/Query/QueryType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,25 @@
class QueryType extends GenericObjectType
{

/** @var Type */
private $indexType;

/** @var Type */
private $resultType;

/** @var string */
private $dql;

public function __construct(string $dql, ?Type $indexType = null, ?Type $resultType = null)
public function __construct(string $dql, ?Type $indexType = null, ?Type $resultType = null, ?Type $subtractedType = null)
{
$this->indexType = $indexType ?? new MixedType();
$this->resultType = $resultType ?? new MixedType();

parent::__construct('Doctrine\ORM\Query', [
$indexType ?? new MixedType(),
$resultType ?? new MixedType(),
]);
$this->indexType,
$this->resultType,
], $subtractedType);

$this->dql = $dql;
}

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

public function changeSubtractedType(?Type $subtractedType): Type
{
return new self('Doctrine\ORM\Query', $this->indexType, $this->resultType, $subtractedType);
}

public function isSuperTypeOf(Type $type): TrinaryLogic
{
if ($type instanceof self) {
Expand Down
8 changes: 6 additions & 2 deletions tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleSlowTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,18 @@ public function testRuleBranches(): void
'QueryBuilder: [Semantical Error] line 0, col 58 near \'p.id = 1\': Error: \'p\' is not defined.',
59,
],
/*[
[
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
90,
],*/
],
[
'QueryBuilder: [Semantical Error] line 0, col 95 near \'foo = 1\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named foo',
107,
],
[
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
107,
],
];
$this->analyse([__DIR__ . '/data/query-builder-branches-dql.php'], $errors);
}
Expand Down
8 changes: 6 additions & 2 deletions tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,18 @@ public function testRuleBranches(): void
'QueryBuilder: [Semantical Error] line 0, col 58 near \'p.id = 1\': Error: \'p\' is not defined.',
59,
],
/*[
[
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
90,
],*/
],
[
'QueryBuilder: [Semantical Error] line 0, col 95 near \'foo = 1\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named foo',
107,
],
[
'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.',
107,
],
];
$this->analyse([__DIR__ . '/data/query-builder-branches-dql.php'], $errors);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function testQueryTypeIsInferredOnAcrossMethods(EntityManagerInterface $e
$branchingQuery = $this->getBranchingQueryBuilder($em)->getQuery();

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

public function testQueryTypeIsInferredOnAcrossMethodsEvenWhenVariableAssignmentIsUsed(EntityManagerInterface $em): void
Expand Down
13 changes: 13 additions & 0 deletions tests/Type/Doctrine/data/QueryResult/queryBuilderGetQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ public function testIndexByResultInfering(EntityManagerInterface $em): void
assertType('array<string, array{intColumn: int, stringNullColumn: string|null}>', $result);
}

public function testConditionalAddSelect(EntityManagerInterface $em, bool $bool): void
{
$qb = $em->createQueryBuilder();
if ($bool) {
$qb->select('m.intColumn');
} else {
$qb->select('m.intColumn', 'm.stringNullColumn');
}
$query = $qb->from(Many::class, 'm')->getQuery();

assertType('Doctrine\ORM\Query<null, array{intColumn: int}>|Doctrine\ORM\Query<null, array{intColumn: int, stringNullColumn: string|null}>', $query);
}

public function testQueryResultTypeIsMixedWhenDQLIsNotKnown(QueryBuilder $builder): void
{
$query = $builder->getQuery();
Expand Down

0 comments on commit cf8f114

Please sign in to comment.