From c54ce9b5f67efb96830e4086c9d7c2d8b74a4e4d Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Thu, 27 Jun 2024 11:27:32 +0200 Subject: [PATCH] Revert result inference for scalar method --- .../QueryResultDynamicReturnTypeExtension.php | 89 ------ .../Doctrine/data/QueryResult/queryResult.php | 270 ------------------ 2 files changed, 359 deletions(-) diff --git a/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php b/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php index f0633a93..54345e7f 100644 --- a/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php @@ -25,7 +25,6 @@ use PHPStan\Type\TypeUtils; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\VoidType; -use function count; final class QueryResultDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { @@ -42,9 +41,6 @@ final class QueryResultDynamicReturnTypeExtension implements DynamicMethodReturn private const METHOD_HYDRATION_MODE = [ 'getArrayResult' => AbstractQuery::HYDRATE_ARRAY, - 'getScalarResult' => AbstractQuery::HYDRATE_SCALAR, - 'getSingleColumnResult' => AbstractQuery::HYDRATE_SCALAR_COLUMN, - 'getSingleScalarResult' => AbstractQuery::HYDRATE_SINGLE_SCALAR, ]; /** @var ObjectMetadataResolver */ @@ -130,26 +126,15 @@ private function getMethodReturnTypeForHydrationMode( return null; } - $singleResult = false; switch ($hydrationMode->getValue()) { case AbstractQuery::HYDRATE_OBJECT: break; case AbstractQuery::HYDRATE_ARRAY: $queryResultType = $this->getArrayHydratedReturnType($queryResultType); break; - case AbstractQuery::HYDRATE_SCALAR: - $queryResultType = $this->getScalarHydratedReturnType($queryResultType); - break; - case AbstractQuery::HYDRATE_SINGLE_SCALAR: - $singleResult = true; - $queryResultType = $this->getSingleScalarHydratedReturnType($queryResultType); - break; case AbstractQuery::HYDRATE_SIMPLEOBJECT: $queryResultType = $this->getSimpleObjectHydratedReturnType($queryResultType); break; - case AbstractQuery::HYDRATE_SCALAR_COLUMN: - $queryResultType = $this->getScalarColumnHydratedReturnType($queryResultType); - break; default: return null; } @@ -174,10 +159,6 @@ private function getMethodReturnTypeForHydrationMode( $queryResultType ); default: - if ($singleResult) { - return $queryResultType; - } - if ($queryKeyType->isNull()->yes()) { return AccessoryArrayListType::intersectWith(new ArrayType( new IntegerType(), @@ -235,36 +216,6 @@ static function (Type $type, callable $traverse) use ($objectManager, &$mixedFou return $mixedFound ? null : $queryResultType; } - /** - * When we're scalar-hydrating object, we're not sure of the shape of the array. - * We could return `new ArrayTyp(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/453#issuecomment-1895415544 - */ - private function getScalarHydratedReturnType(Type $queryResultType): ?Type - { - if (!$queryResultType->isArray()->yes()) { - return null; - } - - foreach ($queryResultType->getArrays() as $arrayType) { - $itemType = $arrayType->getItemType(); - - if ( - !(new ObjectWithoutClassType())->isSuperTypeOf($itemType)->no() - || !$itemType->isArray()->no() - ) { - // We could return `new ArrayTyp(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/453#issuecomment-1895415544 - return null; - } - } - - return $queryResultType; - } - private function getSimpleObjectHydratedReturnType(Type $queryResultType): ?Type { if ((new ObjectWithoutClassType())->isSuperTypeOf($queryResultType)->yes()) { @@ -274,44 +225,4 @@ private function getSimpleObjectHydratedReturnType(Type $queryResultType): ?Type return null; } - private function getSingleScalarHydratedReturnType(Type $queryResultType): ?Type - { - $queryResultType = $this->getScalarHydratedReturnType($queryResultType); - if ($queryResultType === null || !$queryResultType->isConstantArray()->yes()) { - return null; - } - - $types = []; - foreach ($queryResultType->getConstantArrays() as $constantArrayType) { - $values = $constantArrayType->getValueTypes(); - if (count($values) !== 1) { - return null; - } - - $types[] = $constantArrayType->getFirstIterableValueType(); - } - - return TypeCombinator::union(...$types); - } - - private function getScalarColumnHydratedReturnType(Type $queryResultType): ?Type - { - $queryResultType = $this->getScalarHydratedReturnType($queryResultType); - if ($queryResultType === null || !$queryResultType->isConstantArray()->yes()) { - return null; - } - - $types = []; - foreach ($queryResultType->getConstantArrays() as $constantArrayType) { - $values = $constantArrayType->getValueTypes(); - if (count($values) !== 1) { - return null; - } - - $types[] = $constantArrayType->getFirstIterableValueType(); - } - - return TypeCombinator::union(...$types); - } - } diff --git a/tests/Type/Doctrine/data/QueryResult/queryResult.php b/tests/Type/Doctrine/data/QueryResult/queryResult.php index 8721d898..46734609 100644 --- a/tests/Type/Doctrine/data/QueryResult/queryResult.php +++ b/tests/Type/Doctrine/data/QueryResult/queryResult.php @@ -226,196 +226,6 @@ public function testReturnTypeOfQueryMethodsWithExplicitArrayHydrationMode(Entit } - /** - * Test that we properly infer the return type of Query methods with explicit hydration mode of HYDRATE_SCALAR - */ - public function testReturnTypeOfQueryMethodsWithExplicitScalarHydrationMode(EntityManagerInterface $em): void - { - $query = $em->createQuery(' - SELECT m - FROM QueryResult\Entities\Many m - '); - - assertType( - 'mixed', - $query->getResult(AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'array', - $query->getScalarResult() - ); - assertType( - 'iterable', - $query->toIterable([], AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'mixed', - $query->execute(null, AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'mixed', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'mixed', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'mixed', - $query->getSingleResult(AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'mixed', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR) - ); - - $query = $em->createQuery(' - SELECT m.intColumn, m.stringNullColumn - FROM QueryResult\Entities\Many m - '); - - assertType( - 'list', - $query->getResult(AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'list', - $query->getScalarResult() - ); - assertType( - 'list', - $query->execute(null, AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'list', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'list', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'array{intColumn: int, stringNullColumn: string|null}', - $query->getSingleResult(AbstractQuery::HYDRATE_SCALAR) - ); - assertType( - 'array{intColumn: int, stringNullColumn: string|null}|null', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR) - ); - } - - /** - * Test that we properly infer the return type of Query methods with explicit hydration mode of HYDRATE_SCALAR - */ - public function testReturnTypeOfQueryMethodsWithExplicitSingleScalarHydrationMode(EntityManagerInterface $em): void - { - $query = $em->createQuery(' - SELECT m - FROM QueryResult\Entities\Many m - '); - - assertType( - 'mixed', - $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'bool|float|int|string|null', - $query->getSingleScalarResult() - ); - assertType( - 'iterable', - $query->toIterable([], AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'mixed', - $query->execute(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'mixed', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'mixed', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'mixed', - $query->getSingleResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'mixed', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - - $query = $em->createQuery(' - SELECT m.intColumn - FROM QueryResult\Entities\Many m - '); - - assertType( - 'int', - $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int', - $query->getSingleScalarResult() - ); - assertType( - 'int', - $query->execute(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int', - $query->getSingleResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int|null', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - - $query = $em->createQuery(' - SELECT COUNT(m.id) - FROM QueryResult\Entities\Many m - '); - - assertType( - 'int<0, max>', - $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int<0, max>', - $query->getSingleScalarResult() - ); - assertType( - 'int<0, max>', - $query->execute(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int<0, max>', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int<0, max>', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int<0, max>', - $query->getSingleResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - assertType( - 'int<0, max>|null', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_SINGLE_SCALAR) - ); - } - /** * Test that we properly infer the return type of Query methods with explicit hydration mode of HYDRATE_SIMPLEOBJECT * @@ -488,86 +298,6 @@ public function testReturnTypeOfQueryMethodsWithExplicitSimpleObjectHydrationMod ); } - /** - * Test that we properly infer the return type of Query methods with explicit hydration mode of HYDRATE_SCALAR_COLUMN - * - * We are never able to infer the return type here - */ - public function testReturnTypeOfQueryMethodsWithExplicitScalarColumnHydrationMode(EntityManagerInterface $em): void - { - $query = $em->createQuery(' - SELECT m - FROM QueryResult\Entities\Many m - '); - - assertType( - 'mixed', - $query->getResult(AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'array', - $query->getSingleColumnResult() - ); - assertType( - 'iterable', - $query->toIterable([], AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'mixed', - $query->execute(null, AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'mixed', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'mixed', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'mixed', - $query->getSingleResult(AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'mixed', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - - $query = $em->createQuery(' - SELECT m.intColumn - FROM QueryResult\Entities\Many m - '); - - assertType( - 'list', - $query->getResult(AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'list', - $query->getSingleColumnResult() - ); - assertType( - 'list', - $query->execute(null, AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'list', - $query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'list', - $query->executeUsingQueryCache(null, AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'int', - $query->getSingleResult(AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - assertType( - 'int|null', - $query->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR_COLUMN) - ); - } - /** * Test that we properly infer the return type of Query methods with explicit hydration mode that is not a constant value *