From 4675b3b31cd94ae7a192af72c8b53fcbc81bb92f Mon Sep 17 00:00:00 2001 From: Jean-Luc Herren Date: Mon, 8 Jan 2024 20:11:21 +0100 Subject: [PATCH 1/2] Failing test for #512 --- ...erGetQueryDynamicReturnTypeExtensionTest.php | 1 + .../Doctrine/data/QueryResult/Entities/One.php | 9 +++++++++ .../Type/Doctrine/data/QueryResult/bug-512.php | 17 +++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 tests/Type/Doctrine/data/QueryResult/bug-512.php diff --git a/tests/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtensionTest.php b/tests/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtensionTest.php index ac653713..2107951f 100644 --- a/tests/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtensionTest.php +++ b/tests/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtensionTest.php @@ -12,6 +12,7 @@ public function dataFileAsserts(): iterable { yield from $this->gatherAssertTypes(__DIR__ . '/../data/QueryResult/queryBuilderGetQuery.php'); yield from $this->gatherAssertTypes(__DIR__ . '/../data/QueryResult/bug-245.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/../data/QueryResult/bug-512.php'); } /** diff --git a/tests/Type/Doctrine/data/QueryResult/Entities/One.php b/tests/Type/Doctrine/data/QueryResult/Entities/One.php index 5605c945..dbd41caf 100644 --- a/tests/Type/Doctrine/data/QueryResult/Entities/One.php +++ b/tests/Type/Doctrine/data/QueryResult/Entities/One.php @@ -3,6 +3,7 @@ namespace QueryResult\Entities; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Embedded as ORMEmbedded; use Doctrine\ORM\Mapping\Entity; @@ -10,6 +11,7 @@ use Doctrine\ORM\Mapping\JoinColumn; use Doctrine\ORM\Mapping\OneToMany; use Doctrine\ORM\Mapping\OneToOne; +use Doctrine\ORM\QueryBuilder; /** * @Entity @@ -71,4 +73,11 @@ public function __construct() { $this->subOne = new SubOne(); } + + public static function createQueryBuilder(EntityManagerInterface $em): QueryBuilder + { + return $em->createQueryBuilder() + ->select('o') + ->from(self::class, 'o'); + } } diff --git a/tests/Type/Doctrine/data/QueryResult/bug-512.php b/tests/Type/Doctrine/data/QueryResult/bug-512.php new file mode 100644 index 00000000..09f72e5a --- /dev/null +++ b/tests/Type/Doctrine/data/QueryResult/bug-512.php @@ -0,0 +1,17 @@ +getQuery(); + assertType('Doctrine\ORM\Query', $query); + assertType('list', $query->getResult()); + } +} From 64fe4f4ddc5c74e12728c0379fbddfffd2a84d36 Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Tue, 9 Jan 2024 12:59:21 +0100 Subject: [PATCH 2/2] Resolve methodcall args in QueryBuilderType with proper Scope --- ...CreateQueryBuilderDynamicReturnTypeExtension.php | 3 ++- ...eryBuilderGetQueryDynamicReturnTypeExtension.php | 4 ++-- src/Type/Doctrine/QueryBuilder/QueryBuilderType.php | 13 ++++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php index 263f2284..13caea6b 100644 --- a/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php @@ -48,7 +48,8 @@ public function getTypeFromMethodCall( } return new $class( - $this->queryBuilderClass ?? 'Doctrine\ORM\QueryBuilder' + $this->queryBuilderClass ?? 'Doctrine\ORM\QueryBuilder', + $scope ); } diff --git a/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php index b956b690..e4afc0e1 100644 --- a/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php @@ -147,7 +147,7 @@ public function getTypeFromMethodCall( if ($lowerMethodName === 'set') { try { - $args = $this->argumentsProcessor->processArgs($scope, $methodName, array_slice($calledMethodCall->getArgs(), 0, 1)); + $args = $this->argumentsProcessor->processArgs($queryBuilderType->getScope(), $methodName, array_slice($calledMethodCall->getArgs(), 0, 1)); } catch (DynamicQueryBuilderArgumentException $e) { return $defaultReturnType; } @@ -162,7 +162,7 @@ public function getTypeFromMethodCall( } try { - $args = $this->argumentsProcessor->processArgs($scope, $methodName, $calledMethodCall->getArgs()); + $args = $this->argumentsProcessor->processArgs($queryBuilderType->getScope(), $methodName, $calledMethodCall->getArgs()); } catch (DynamicQueryBuilderArgumentException $e) { if (in_array($lowerMethodName, self::METHODS_NOT_AFFECTING_RESULT_TYPE, true)) { continue; diff --git a/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php b/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php index 729cda17..f1cfdb7d 100644 --- a/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php +++ b/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php @@ -3,6 +3,7 @@ namespace PHPStan\Type\Doctrine\QueryBuilder; use PhpParser\Node\Expr\MethodCall; +use PHPStan\Analyser\Scope; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use function md5; @@ -16,12 +17,22 @@ abstract class QueryBuilderType extends ObjectType /** @var array */ private $methodCalls = []; + /** @var Scope */ + private $scope; + final public function __construct( string $className, + Scope $scope, ?Type $subtractedType = null ) { parent::__construct($className, $subtractedType); + $this->scope = $scope; + } + + final public function getScope(): Scope + { + return $this->scope; } /** @@ -34,7 +45,7 @@ public function getMethodCalls(): array public function append(MethodCall $methodCall): self { - $object = new static($this->getClassName()); + $object = new static($this->getClassName(), $this->getScope()); $object->methodCalls = $this->methodCalls; $object->methodCalls[substr(md5(uniqid()), 0, 10)] = $methodCall;