From 6051e97bf3aa530e0a1d8f8bf5489ee7649396ca Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 28 Jun 2024 16:49:09 +0200 Subject: [PATCH] Do not infer getArrayResult for now --- .../HydrationModeReturnTypeResolver.php | 48 ------------- .../QueryResultDynamicReturnTypeExtension.php | 37 ++++------ ...QueryResultTypeWalkerHydrationModeTest.php | 70 ------------------- .../Doctrine/data/QueryResult/queryResult.php | 35 ---------- 4 files changed, 15 insertions(+), 175 deletions(-) diff --git a/src/Type/Doctrine/HydrationModeReturnTypeResolver.php b/src/Type/Doctrine/HydrationModeReturnTypeResolver.php index c37a0c96..dabf4d9b 100644 --- a/src/Type/Doctrine/HydrationModeReturnTypeResolver.php +++ b/src/Type/Doctrine/HydrationModeReturnTypeResolver.php @@ -10,13 +10,10 @@ use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntegerType; use PHPStan\Type\IterableType; -use PHPStan\Type\MixedType; use PHPStan\Type\ObjectWithoutClassType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeTraverser; use PHPStan\Type\TypeUtils; -use PHPStan\Type\TypeWithClassName; use PHPStan\Type\VoidType; class HydrationModeReturnTypeResolver @@ -47,9 +44,6 @@ public function getMethodReturnTypeForHydrationMode( switch ($hydrationMode) { case AbstractQuery::HYDRATE_OBJECT: break; - case AbstractQuery::HYDRATE_ARRAY: - $queryResultType = $this->getArrayHydratedReturnType($queryResultType, $objectManager); - break; case AbstractQuery::HYDRATE_SIMPLEOBJECT: $queryResultType = $this->getSimpleObjectHydratedReturnType($queryResultType); break; @@ -90,48 +84,6 @@ public function getMethodReturnTypeForHydrationMode( } } - /** - * When we're array-hydrating object, we're not sure of the shape of the array. - * We could return `new ArrayType(new MixedType(), new MixedType())` - * but the lack of precision in the array keys/values would give false positive. - * - * @see https://github.com/phpstan/phpstan-doctrine/pull/412#issuecomment-1497092934 - */ - private function getArrayHydratedReturnType(Type $queryResultType, ?ObjectManager $objectManager): ?Type - { - $mixedFound = false; - $queryResultType = TypeTraverser::map( - $queryResultType, - static function (Type $type, callable $traverse) use ($objectManager, &$mixedFound): Type { - $isObject = (new ObjectWithoutClassType())->isSuperTypeOf($type); - if ($isObject->no()) { - return $traverse($type); - } - if ( - $isObject->maybe() - || !$type instanceof TypeWithClassName - || $objectManager === null - ) { - $mixedFound = true; - - return new MixedType(); - } - - /** @var class-string $className */ - $className = $type->getClassName(); - if (!$objectManager->getMetadataFactory()->hasMetadataFor($className)) { - return $traverse($type); - } - - $mixedFound = true; - - return new MixedType(); - } - ); - - return $mixedFound ? null : $queryResultType; - } - private function getSimpleObjectHydratedReturnType(Type $queryResultType): ?Type { if ((new ObjectWithoutClassType())->isSuperTypeOf($queryResultType)->yes()) { diff --git a/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php b/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php index 818c3869..ef638cad 100644 --- a/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php @@ -28,10 +28,6 @@ final class QueryResultDynamicReturnTypeExtension implements DynamicMethodReturn 'getSingleResult' => 0, ]; - private const METHOD_HYDRATION_MODE = [ - 'getArrayResult' => AbstractQuery::HYDRATE_ARRAY, - ]; - /** @var ObjectMetadataResolver */ private $objectMetadataResolver; @@ -54,8 +50,7 @@ public function getClass(): string public function isMethodSupported(MethodReflection $methodReflection): bool { - return isset(self::METHOD_HYDRATION_MODE_ARG[$methodReflection->getName()]) - || isset(self::METHOD_HYDRATION_MODE[$methodReflection->getName()]); + return isset(self::METHOD_HYDRATION_MODE_ARG[$methodReflection->getName()]); } public function getTypeFromMethodCall( @@ -66,25 +61,23 @@ public function getTypeFromMethodCall( { $methodName = $methodReflection->getName(); - if (isset(self::METHOD_HYDRATION_MODE[$methodName])) { - $hydrationMode = new ConstantIntegerType(self::METHOD_HYDRATION_MODE[$methodName]); - } elseif (isset(self::METHOD_HYDRATION_MODE_ARG[$methodName])) { - $argIndex = self::METHOD_HYDRATION_MODE_ARG[$methodName]; - $args = $methodCall->getArgs(); - - if (isset($args[$argIndex])) { - $hydrationMode = $scope->getType($args[$argIndex]->value); - } else { - $parametersAcceptor = ParametersAcceptorSelector::selectSingle( - $methodReflection->getVariants() - ); - $parameter = $parametersAcceptor->getParameters()[$argIndex]; - $hydrationMode = $parameter->getDefaultValue() ?? new NullType(); - } - } else { + if (!isset(self::METHOD_HYDRATION_MODE_ARG[$methodName])) { throw new ShouldNotHappenException(); } + $argIndex = self::METHOD_HYDRATION_MODE_ARG[$methodName]; + $args = $methodCall->getArgs(); + + if (isset($args[$argIndex])) { + $hydrationMode = $scope->getType($args[$argIndex]->value); + } else { + $parametersAcceptor = ParametersAcceptorSelector::selectSingle( + $methodReflection->getVariants() + ); + $parameter = $parametersAcceptor->getParameters()[$argIndex]; + $hydrationMode = $parameter->getDefaultValue() ?? new NullType(); + } + $queryType = $scope->getType($methodCall->var); if (!$hydrationMode instanceof ConstantIntegerType) { diff --git a/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php b/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php index de3bf93b..f78b81a4 100644 --- a/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php +++ b/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php @@ -138,42 +138,6 @@ public static function getTestData(): iterable Query::HYDRATE_SIMPLEOBJECT, ]; - yield 'getResult(array), full entity' => [ - new MixedType(), - ' - SELECT s - FROM QueryResult\Entities\Simple s - ', - 'getResult', - Query::HYDRATE_ARRAY, - ]; - - yield 'getResult(array), fields' => [ - self::list(self::constantArray([ - [new ConstantStringType('decimalColumn'), self::numericString()], - [new ConstantStringType('floatColumn'), new FloatType()], - ])), - ' - SELECT s.decimalColumn, s.floatColumn - FROM QueryResult\Entities\Simple s - ', - 'getResult', - Query::HYDRATE_ARRAY, - ]; - - yield 'getResult(array), expressions' => [ - self::list(self::constantArray([ - [new ConstantStringType('decimalColumn'), self::floatOrIntOrStringified()], - [new ConstantStringType('floatColumn'), self::floatOrStringified()], - ])), - ' - SELECT -s.decimalColumn as decimalColumn, -s.floatColumn as floatColumn - FROM QueryResult\Entities\Simple s - ', - 'getResult', - Query::HYDRATE_ARRAY, - ]; - yield 'getResult(object), fields' => [ self::list(self::constantArray([ [new ConstantStringType('decimalColumn'), self::numericString()], @@ -246,16 +210,6 @@ public static function getTestData(): iterable Query::HYDRATE_SIMPLEOBJECT, ]; - yield 'toIterable(array), full entity' => [ - new MixedType(), - ' - SELECT s - FROM QueryResult\Entities\Simple s - ', - 'toIterable', - Query::HYDRATE_ARRAY, - ]; - yield 'getArrayResult(), full entity' => [ new MixedType(), ' @@ -265,30 +219,6 @@ public static function getTestData(): iterable 'getArrayResult', ]; - yield 'getArrayResult(), fields' => [ - self::list(self::constantArray([ - [new ConstantStringType('decimalColumn'), self::numericString()], - [new ConstantStringType('floatColumn'), new FloatType()], - ])), - ' - SELECT s.decimalColumn, s.floatColumn - FROM QueryResult\Entities\Simple s - ', - 'getArrayResult', - ]; - - yield 'getArrayResult(), expressions' => [ - self::list(self::constantArray([ - [new ConstantStringType('decimalColumn'), self::floatOrIntOrStringified()], - [new ConstantStringType('floatColumn'), self::floatOrStringified()], - ])), - ' - SELECT -s.decimalColumn as decimalColumn, -s.floatColumn as floatColumn - FROM QueryResult\Entities\Simple s - ', - 'getArrayResult', - ]; - yield 'getResult(single_scalar), decimal field' => [ new MixedType(), ' diff --git a/tests/Type/Doctrine/data/QueryResult/queryResult.php b/tests/Type/Doctrine/data/QueryResult/queryResult.php index 46734609..de4cc5bf 100644 --- a/tests/Type/Doctrine/data/QueryResult/queryResult.php +++ b/tests/Type/Doctrine/data/QueryResult/queryResult.php @@ -188,41 +188,6 @@ public function testReturnTypeOfQueryMethodsWithExplicitArrayHydrationMode(Entit 'mixed', $query->getOneOrNullResult(AbstractQuery::HYDRATE_ARRAY) ); - - - $query = $em->createQuery(' - SELECT m.intColumn, m.stringNullColumn, m.datetimeColumn - FROM QueryResult\Entities\Many m - '); - - assertType( - 'list', - $query->getResult(AbstractQuery::HYDRATE_ARRAY) - ); - assertType( - 'list', - $query->getArrayResult() - ); - assertType( - 'list', - $query->execute(null, AbstractQuery::HYDRATE_ARRAY) - ); - assertType( - 'list', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_ARRAY) - ); - assertType( - 'list', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_ARRAY) - ); - assertType( - 'array{intColumn: int, stringNullColumn: string|null, datetimeColumn: DateTime}', - $query->getSingleResult(AbstractQuery::HYDRATE_ARRAY) - ); - assertType( - 'array{intColumn: int, stringNullColumn: string|null, datetimeColumn: DateTime}|null', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_ARRAY) - ); }