From bee531a970d758ba3c6347b554318e6483a297e7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 14 Feb 2022 20:37:41 +0100 Subject: [PATCH 1/6] doctrine-dbal: implement union query types --- .phpstan-dba-mysqli.cache | 436 +++++++++++++++++- src/DoctrineReflection/DoctrineReflection.php | 31 ++ ...nectionQueryDynamicReturnTypeExtension.php | 15 +- .../default/config/.phpstan-dba-mysqli.cache | 58 +-- .../data/doctrine-dbal-union-result.php | 20 + 5 files changed, 499 insertions(+), 61 deletions(-) create mode 100644 tests/default/data/doctrine-dbal-union-result.php diff --git a/.phpstan-dba-mysqli.cache b/.phpstan-dba-mysqli.cache index d6fb5f19b..bbf4654aa 100644 --- a/.phpstan-dba-mysqli.cache +++ b/.phpstan-dba-mysqli.cache @@ -2591,6 +2591,112 @@ )), ), ), + 'SELECT count(*) FROM typemix WHERE c_date = \'1970-01-01\'' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'count(*)', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerType::__set_state(array( + )), + 1 => + PHPStan\Type\IntegerType::__set_state(array( + )), + ), + 'nextAutoIndex' => 1, + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'count(*)', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\IntegerType::__set_state(array( + )), + )), + ), + ), + 'SELECT count(*) FROM typemix WHERE c_datetime = \'1970-01-01\'' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'count(*)', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\IntegerType::__set_state(array( + )), + 1 => + PHPStan\Type\IntegerType::__set_state(array( + )), + ), + 'nextAutoIndex' => 1, + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'count(*)', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\IntegerType::__set_state(array( + )), + )), + ), + ), 'SELECT eladaid FROM ak' => array ( 'result' => @@ -2681,7 +2787,7 @@ array ( 'result' => array ( - 5 => + 3 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -2691,38 +2797,21 @@ 'value' => 'email', 'isClassString' => false, )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), ), 'valueTypes' => array ( 0 => PHPStan\Type\StringType::__set_state(array( )), - 1 => - PHPStan\Type\StringType::__set_state(array( - )), ), - 'nextAutoIndex' => 1, + 'nextAutoIndex' => 0, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, - )), - ), + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, )), 'itemType' => PHPStan\Type\StringType::__set_state(array( @@ -3655,6 +3744,154 @@ )), ), ), + 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE adaid = \'1\'' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\StringType::__set_state(array( + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => 0, + 'max' => 4294967295, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => 0, + 'max' => 4294967295, + )), + 4 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 5 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'nextAutoIndex' => 4, + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 4294967295, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE adaid = 1' => array ( 'result' => @@ -3803,6 +4040,13 @@ )), ), ), + 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE adaid = ?' => + array ( + 'result' => + array ( + 5 => NULL, + ), + ), 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE adaid IN(1,3)' => array ( 'result' => @@ -4099,6 +4343,154 @@ )), ), ), + 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE email = \'1970-01-01\'' => + array ( + 'result' => + array ( + 5 => + PHPStan\Type\Constant\ConstantArrayType::__set_state(array( + 'allArrays' => NULL, + 'keyTypes' => + array ( + 0 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 2 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + ), + 'valueTypes' => + array ( + 0 => + PHPStan\Type\StringType::__set_state(array( + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + 2 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => 0, + 'max' => 4294967295, + )), + 3 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => 0, + 'max' => 4294967295, + )), + 4 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 5 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 6 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + 7 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 127, + )), + ), + 'nextAutoIndex' => 4, + 'optionalKeys' => + array ( + ), + 'keyType' => + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 1, + )), + 2 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 2, + )), + 3 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 3, + )), + 4 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + 5 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + 6 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'freigabe1u1', + 'isClassString' => false, + )), + 7 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'gesperrt', + 'isClassString' => false, + )), + ), + )), + 'itemType' => + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => -128, + 'max' => 4294967295, + )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), + ), + )), + )), + ), + ), 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE email = \'test@example.org\'' => array ( 'result' => diff --git a/src/DoctrineReflection/DoctrineReflection.php b/src/DoctrineReflection/DoctrineReflection.php index f5c55144e..7aa3464f4 100644 --- a/src/DoctrineReflection/DoctrineReflection.php +++ b/src/DoctrineReflection/DoctrineReflection.php @@ -4,6 +4,7 @@ namespace staabm\PHPStanDba\DoctrineReflection; +use Doctrine\DBAL\Result; use PHPStan\Reflection\MethodReflection; use PHPStan\Type\ArrayType; use PHPStan\Type\Constant\ConstantArrayType; @@ -16,6 +17,7 @@ use PHPStan\Type\IntegerType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; +use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\QueryReflection\QueryReflector; use Traversable; @@ -107,4 +109,33 @@ public function fetchResultType(MethodReflection $methodReflection, Type $result return null; } + + /** + * @param iterable $queryStrings + * @param QueryReflector::FETCH_TYPE* $reflectionFetchType + */ + public function createGenericStatement(iterable $queryStrings, int $reflectionFetchType): ?Type + { + $genericObjects = []; + + foreach ($queryStrings as $queryString) { + $queryReflection = new QueryReflection(); + + $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); + if (null === $resultType) { + return null; + } + + $genericObjects[] = new GenericObjectType(Result::class, [$resultType]); + } + + if (\count($genericObjects) > 1) { + return TypeCombinator::union(...$genericObjects); + } + if (1 === \count($genericObjects)) { + return $genericObjects[0]; + } + + return null; + } } diff --git a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php index 2a68dff56..071b2bf3d 100644 --- a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php @@ -8,6 +8,7 @@ use Composer\Semver\VersionParser; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Result; +use PhpParser\Comment\Doc; use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; @@ -17,6 +18,7 @@ use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; +use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\QueryReflection\QueryReflector; @@ -65,16 +67,9 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method private function inferType(Expr $queryExpr, Scope $scope): ?Type { $queryReflection = new QueryReflection(); - $queryString = $queryReflection->resolveQueryString($queryExpr, $scope); - if (null === $queryString) { - return null; - } - - $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); - if ($resultType) { - return new GenericObjectType(Result::class, [$resultType]); - } + $queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope); - return null; + $doctrineReflection = new DoctrineReflection(); + return $doctrineReflection->createGenericStatement($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/tests/default/config/.phpstan-dba-mysqli.cache b/tests/default/config/.phpstan-dba-mysqli.cache index 9f9b1ce8f..d268994c7 100644 --- a/tests/default/config/.phpstan-dba-mysqli.cache +++ b/tests/default/config/.phpstan-dba-mysqli.cache @@ -1512,7 +1512,7 @@ array ( 'result' => array ( - 3 => + 5 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -1522,6 +1522,10 @@ 'value' => 'adaid', 'isClassString' => false, )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), ), 'valueTypes' => array ( @@ -1530,15 +1534,30 @@ 'min' => 0, 'max' => 4294967295, )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => 0, + 'max' => 4294967295, + )), ), - 'nextAutoIndex' => 0, + 'nextAutoIndex' => 1, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'adaid', - 'isClassString' => false, + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + ), )), 'itemType' => PHPStan\Type\IntegerRangeType::__set_state(array( @@ -1546,7 +1565,7 @@ 'max' => 4294967295, )), )), - 5 => + 3 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -1556,10 +1575,6 @@ 'value' => 'adaid', 'isClassString' => false, )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), ), 'valueTypes' => array ( @@ -1568,30 +1583,15 @@ 'min' => 0, 'max' => 4294967295, )), - 1 => - PHPStan\Type\IntegerRangeType::__set_state(array( - 'min' => 0, - 'max' => 4294967295, - )), ), - 'nextAutoIndex' => 1, + 'nextAutoIndex' => 0, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'adaid', - 'isClassString' => false, - )), - ), + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, )), 'itemType' => PHPStan\Type\IntegerRangeType::__set_state(array( diff --git a/tests/default/data/doctrine-dbal-union-result.php b/tests/default/data/doctrine-dbal-union-result.php new file mode 100644 index 000000000..99cddcc9f --- /dev/null +++ b/tests/default/data/doctrine-dbal-union-result.php @@ -0,0 +1,20 @@ +query($query); + assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $result); + } + } +} From 69382a0e89f7cdd7a07a43cf37e600807ce90f06 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 14 Feb 2022 20:50:19 +0100 Subject: [PATCH 2/6] implement prepares --- .phpstan-dba-mysqli.cache | 27 ++++++++-- src/DoctrineReflection/DoctrineReflection.php | 30 +++++++++++ ...ExecuteQueryDynamicReturnTypeExtension.php | 19 ++----- ...ctionPrepareDynamicReturnTypeExtension.php | 14 ++--- ...nectionQueryDynamicReturnTypeExtension.php | 2 +- .../default/config/.phpstan-dba-mysqli.cache | 54 +++++++++---------- .../data/doctrine-dbal-union-result.php | 16 +++++- 7 files changed, 104 insertions(+), 58 deletions(-) diff --git a/.phpstan-dba-mysqli.cache b/.phpstan-dba-mysqli.cache index bbf4654aa..2e18e8a6d 100644 --- a/.phpstan-dba-mysqli.cache +++ b/.phpstan-dba-mysqli.cache @@ -2787,7 +2787,7 @@ array ( 'result' => array ( - 3 => + 5 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -2797,21 +2797,38 @@ 'value' => 'email', 'isClassString' => false, )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), ), 'valueTypes' => array ( 0 => PHPStan\Type\StringType::__set_state(array( )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), ), - 'nextAutoIndex' => 0, + 'nextAutoIndex' => 1, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + ), )), 'itemType' => PHPStan\Type\StringType::__set_state(array( diff --git a/src/DoctrineReflection/DoctrineReflection.php b/src/DoctrineReflection/DoctrineReflection.php index 7aa3464f4..f252add40 100644 --- a/src/DoctrineReflection/DoctrineReflection.php +++ b/src/DoctrineReflection/DoctrineReflection.php @@ -5,6 +5,7 @@ namespace staabm\PHPStanDba\DoctrineReflection; use Doctrine\DBAL\Result; +use Doctrine\DBAL\Statement; use PHPStan\Reflection\MethodReflection; use PHPStan\Type\ArrayType; use PHPStan\Type\Constant\ConstantArrayType; @@ -118,6 +119,35 @@ public function createGenericStatement(iterable $queryStrings, int $reflectionFe { $genericObjects = []; + foreach ($queryStrings as $queryString) { + $queryReflection = new QueryReflection(); + + $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); + if (null === $resultType) { + return null; + } + + $genericObjects[] = new GenericObjectType(Statement::class, [$resultType]); + } + + if (\count($genericObjects) > 1) { + return TypeCombinator::union(...$genericObjects); + } + if (1 === \count($genericObjects)) { + return $genericObjects[0]; + } + + return null; + } + + /** + * @param iterable $queryStrings + * @param QueryReflector::FETCH_TYPE* $reflectionFetchType + */ + public function createGenericResult(iterable $queryStrings, int $reflectionFetchType): ?Type + { + $genericObjects = []; + foreach ($queryStrings as $queryString) { $queryReflection = new QueryReflection(); diff --git a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php index 0a20ff0fb..9f7594934 100644 --- a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php @@ -17,6 +17,7 @@ use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; +use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\QueryReflection\QueryReflector; @@ -71,25 +72,15 @@ private function inferType(Expr $queryExpr, ?Expr $paramsExpr, Scope $scope): ?T { if (null === $paramsExpr) { $queryReflection = new QueryReflection(); - $queryString = $queryReflection->resolveQueryString($queryExpr, $scope); - if (null === $queryString) { - return null; - } + $queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope); } else { $parameterTypes = $scope->getType($paramsExpr); $queryReflection = new QueryReflection(); - $queryString = $queryReflection->resolvePreparedQueryString($queryExpr, $parameterTypes, $scope); - if (null === $queryString) { - return null; - } + $queryStrings = $queryReflection->resolvePreparedQueryStrings($queryExpr, $parameterTypes, $scope); } - $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); - if ($resultType) { - return new GenericObjectType(Result::class, [$resultType]); - } - - return null; + $doctrineReflection = new DoctrineReflection(); + return $doctrineReflection->createGenericResult($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php index 4aea7302f..fc871f5d1 100644 --- a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php @@ -17,6 +17,7 @@ use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; +use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\QueryReflection\QueryReflector; @@ -65,16 +66,9 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method private function inferType(Expr $queryExpr, Scope $scope): ?Type { $queryReflection = new QueryReflection(); - $queryString = $queryReflection->resolveQueryString($queryExpr, $scope); - if (null === $queryString) { - return null; - } - - $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); - if ($resultType) { - return new GenericObjectType(Statement::class, [$resultType]); - } + $queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope); - return null; + $doctrineReflection = new DoctrineReflection(); + return $doctrineReflection->createGenericStatement($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php index 071b2bf3d..1fdc43741 100644 --- a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php @@ -70,6 +70,6 @@ private function inferType(Expr $queryExpr, Scope $scope): ?Type $queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope); $doctrineReflection = new DoctrineReflection(); - return $doctrineReflection->createGenericStatement($queryStrings, QueryReflector::FETCH_TYPE_BOTH); + return $doctrineReflection->createGenericResult($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/tests/default/config/.phpstan-dba-mysqli.cache b/tests/default/config/.phpstan-dba-mysqli.cache index d268994c7..8c671ee01 100644 --- a/tests/default/config/.phpstan-dba-mysqli.cache +++ b/tests/default/config/.phpstan-dba-mysqli.cache @@ -2585,7 +2585,7 @@ array ( 'result' => array ( - 3 => + 5 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -2595,27 +2595,44 @@ 'value' => 'email', 'isClassString' => false, )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), ), 'valueTypes' => array ( 0 => PHPStan\Type\StringType::__set_state(array( )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), ), - 'nextAutoIndex' => 0, + 'nextAutoIndex' => 1, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + ), )), 'itemType' => PHPStan\Type\StringType::__set_state(array( )), )), - 5 => + 3 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -2625,38 +2642,21 @@ 'value' => 'email', 'isClassString' => false, )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), ), 'valueTypes' => array ( 0 => PHPStan\Type\StringType::__set_state(array( )), - 1 => - PHPStan\Type\StringType::__set_state(array( - )), ), - 'nextAutoIndex' => 1, + 'nextAutoIndex' => 0, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, - )), - ), + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, )), 'itemType' => PHPStan\Type\StringType::__set_state(array( diff --git a/tests/default/data/doctrine-dbal-union-result.php b/tests/default/data/doctrine-dbal-union-result.php index 99cddcc9f..cfeabf960 100644 --- a/tests/default/data/doctrine-dbal-union-result.php +++ b/tests/default/data/doctrine-dbal-union-result.php @@ -3,11 +3,25 @@ namespace PdoUnionResult; use Doctrine\DBAL\Connection; -use mysqli; use function PHPStan\Testing\assertType; class Foo { + public function doFoo(Connection $conn) + { + $queries = ['SELECT adaid FROM ada', 'SELECT email FROM ada']; + + foreach ($queries as $query) { + $stmt = $conn->prepare($query); + assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $stmt); + + $result = $stmt->executeQuery([]); + assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $result); + $result = $stmt->execute([]); + assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $result); + } + } + public function doBar(Connection $conn) { $queries = ['SELECT adaid FROM ada', 'SELECT email FROM ada']; From e6277671fb046110ddc790c1cce5ef9b092a4db0 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 14 Feb 2022 21:04:07 +0100 Subject: [PATCH 3/6] refactor --- src/DoctrineReflection/DoctrineReflection.php | 39 +++++++++++++++++-- ...nectionFetchDynamicReturnTypeExtension.php | 29 +++----------- ...ctrineResultDynamicReturnTypeExtension.php | 2 +- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/DoctrineReflection/DoctrineReflection.php b/src/DoctrineReflection/DoctrineReflection.php index f252add40..25da763a6 100644 --- a/src/DoctrineReflection/DoctrineReflection.php +++ b/src/DoctrineReflection/DoctrineReflection.php @@ -24,7 +24,7 @@ final class DoctrineReflection { - public function fetchResultType(MethodReflection $methodReflection, Type $resultRowType): ?Type + public function reduceResultType(MethodReflection $methodReflection, Type $resultRowType): ?Type { $usedMethod = strtolower($methodReflection->getName()); @@ -122,7 +122,7 @@ public function createGenericStatement(iterable $queryStrings, int $reflectionFe foreach ($queryStrings as $queryString) { $queryReflection = new QueryReflection(); - $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); + $resultType = $queryReflection->getResultType($queryString, $reflectionFetchType); if (null === $resultType) { return null; } @@ -151,7 +151,7 @@ public function createGenericResult(iterable $queryStrings, int $reflectionFetch foreach ($queryStrings as $queryString) { $queryReflection = new QueryReflection(); - $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); + $resultType = $queryReflection->getResultType($queryString, $reflectionFetchType); if (null === $resultType) { return null; } @@ -168,4 +168,37 @@ public function createGenericResult(iterable $queryStrings, int $reflectionFetch return null; } + + /** + * @param iterable $queryStrings + */ + public function createFetchType(iterable $queryStrings, MethodReflection $methodReflection): ?Type + { + $queryReflection = new QueryReflection(); + + $fetchTypes = []; + foreach ($queryStrings as $queryString) { + $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); + + if ($resultType === null) { + return null; + } + + $fetchResultType = $this->reduceResultType($methodReflection, $resultType); + if (null === $fetchResultType) { + return null; + } + + $fetchTypes[] = $fetchResultType; + } + + if (\count($fetchTypes) > 1) { + return TypeCombinator::union(...$fetchTypes); + } + if (1 === \count($fetchTypes)) { + return $fetchTypes[0]; + } + + return null; + } } diff --git a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php index 0db7386e8..49dc01e7d 100644 --- a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php @@ -82,33 +82,16 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method private function inferType(MethodReflection $methodReflection, Expr $queryExpr, ?Expr $paramsExpr, Scope $scope): ?Type { + $queryReflection = new QueryReflection(); + $doctrineReflection = new DoctrineReflection(); + if (null === $paramsExpr) { - $queryReflection = new QueryReflection(); - $queryString = $queryReflection->resolveQueryString($queryExpr, $scope); - if (null === $queryString) { - return null; - } + $queryString = $queryReflection->resolveQueryStrings($queryExpr, $scope); } else { $parameterTypes = $scope->getType($paramsExpr); - - $queryReflection = new QueryReflection(); - $queryString = $queryReflection->resolvePreparedQueryString($queryExpr, $parameterTypes, $scope); - if (null === $queryString) { - return null; - } - } - - $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); - - if ($resultType) { - $doctrineReflection = new DoctrineReflection(); - $fetchResultType = $doctrineReflection->fetchResultType($methodReflection, $resultType); - - if (null !== $fetchResultType) { - return $fetchResultType; - } + $queryString = $queryReflection->resolvePreparedQueryStrings($queryExpr, $parameterTypes, $scope); } - return null; + return $doctrineReflection->createFetchType($queryString, $methodReflection); } } diff --git a/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php b/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php index 549ac5f6f..4561f1c83 100644 --- a/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php @@ -82,7 +82,7 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method } $doctrineReflection = new DoctrineReflection(); - $fetchResultType = $doctrineReflection->fetchResultType($methodReflection, $resultRowType); + $fetchResultType = $doctrineReflection->reduceResultType($methodReflection, $resultRowType); if (null !== $fetchResultType) { return $fetchResultType; } From 6a05f8d9c62bf8e005cc7887286ea1fabc28ff1d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 14 Feb 2022 21:09:31 +0100 Subject: [PATCH 4/6] fix --- src/DoctrineReflection/DoctrineReflection.php | 6 +++--- ...nnectionExecuteQueryDynamicReturnTypeExtension.php | 3 +-- ...trineConnectionFetchDynamicReturnTypeExtension.php | 1 - ...ineConnectionPrepareDynamicReturnTypeExtension.php | 3 +-- ...trineConnectionQueryDynamicReturnTypeExtension.php | 4 +--- tests/default/data/doctrine-dbal-union-result.php | 11 +++++++---- tests/rules/config/.phpstan-dba-mysqli.cache | 2 +- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/DoctrineReflection/DoctrineReflection.php b/src/DoctrineReflection/DoctrineReflection.php index 25da763a6..f8074c94c 100644 --- a/src/DoctrineReflection/DoctrineReflection.php +++ b/src/DoctrineReflection/DoctrineReflection.php @@ -112,7 +112,7 @@ public function reduceResultType(MethodReflection $methodReflection, Type $resul } /** - * @param iterable $queryStrings + * @param iterable $queryStrings * @param QueryReflector::FETCH_TYPE* $reflectionFetchType */ public function createGenericStatement(iterable $queryStrings, int $reflectionFetchType): ?Type @@ -141,7 +141,7 @@ public function createGenericStatement(iterable $queryStrings, int $reflectionFe } /** - * @param iterable $queryStrings + * @param iterable $queryStrings * @param QueryReflector::FETCH_TYPE* $reflectionFetchType */ public function createGenericResult(iterable $queryStrings, int $reflectionFetchType): ?Type @@ -180,7 +180,7 @@ public function createFetchType(iterable $queryStrings, MethodReflection $method foreach ($queryStrings as $queryString) { $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); - if ($resultType === null) { + if (null === $resultType) { return null; } diff --git a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php index 9f7594934..27d15ff45 100644 --- a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php @@ -7,14 +7,12 @@ use Composer\InstalledVersions; use Composer\Semver\VersionParser; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Result; use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\DynamicMethodReturnTypeExtension; -use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; @@ -81,6 +79,7 @@ private function inferType(Expr $queryExpr, ?Expr $paramsExpr, Scope $scope): ?T } $doctrineReflection = new DoctrineReflection(); + return $doctrineReflection->createGenericResult($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php index 49dc01e7d..5e758fb3c 100644 --- a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php @@ -17,7 +17,6 @@ use PHPStan\Type\Type; use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; use staabm\PHPStanDba\QueryReflection\QueryReflection; -use staabm\PHPStanDba\QueryReflection\QueryReflector; final class DoctrineConnectionFetchDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { diff --git a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php index fc871f5d1..86f278640 100644 --- a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php @@ -7,14 +7,12 @@ use Composer\InstalledVersions; use Composer\Semver\VersionParser; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Statement; use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\DynamicMethodReturnTypeExtension; -use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; @@ -69,6 +67,7 @@ private function inferType(Expr $queryExpr, Scope $scope): ?Type $queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope); $doctrineReflection = new DoctrineReflection(); + return $doctrineReflection->createGenericStatement($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php index 1fdc43741..70ae54cb3 100644 --- a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php @@ -7,15 +7,12 @@ use Composer\InstalledVersions; use Composer\Semver\VersionParser; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Result; -use PhpParser\Comment\Doc; use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\DynamicMethodReturnTypeExtension; -use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; @@ -70,6 +67,7 @@ private function inferType(Expr $queryExpr, Scope $scope): ?Type $queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope); $doctrineReflection = new DoctrineReflection(); + return $doctrineReflection->createGenericResult($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/tests/default/data/doctrine-dbal-union-result.php b/tests/default/data/doctrine-dbal-union-result.php index cfeabf960..2b9ad88a7 100644 --- a/tests/default/data/doctrine-dbal-union-result.php +++ b/tests/default/data/doctrine-dbal-union-result.php @@ -13,12 +13,15 @@ public function doFoo(Connection $conn) foreach ($queries as $query) { $stmt = $conn->prepare($query); - assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $stmt); + assertType('Doctrine\DBAL\Statement, 0: int<0, 4294967295>}>|Doctrine\DBAL\Statement', $stmt); $result = $stmt->executeQuery([]); - assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $result); + assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>', $result); $result = $stmt->execute([]); - assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $result); + assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>', $result); + + $fetch = $result->fetchOne(); + assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>', $fetch); } } @@ -28,7 +31,7 @@ public function doBar(Connection $conn) foreach ($queries as $query) { $result = $conn->query($query); - assertType('Doctrine\DBAL\Result, 3: int<-128, 127>}>', $result); + assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>|Doctrine\DBAL\Result', $result); } } } diff --git a/tests/rules/config/.phpstan-dba-mysqli.cache b/tests/rules/config/.phpstan-dba-mysqli.cache index 4fd72dad7..e8565ec04 100644 --- a/tests/rules/config/.phpstan-dba-mysqli.cache +++ b/tests/rules/config/.phpstan-dba-mysqli.cache @@ -972,7 +972,7 @@ array ( 'result' => array ( - 5 => NULL, + 3 => NULL, ), ), 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE gesperrt=1' => From 4d906b6f67edfe1f9685e6201be94e036f7af812 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 14 Feb 2022 21:20:06 +0100 Subject: [PATCH 5/6] fix --- ...atementExecuteDynamicReturnTypeExtension.php | 17 +++++------------ .../default/data/doctrine-dbal-union-result.php | 10 ++++++---- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php b/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php index cbad59598..614c3d21f 100644 --- a/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php @@ -6,7 +6,6 @@ use Composer\InstalledVersions; use Composer\Semver\VersionParser; -use Doctrine\DBAL\Result; use Doctrine\DBAL\Statement; use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; @@ -14,8 +13,8 @@ use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\DynamicMethodReturnTypeExtension; -use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\Type; +use staabm\PHPStanDba\DoctrineReflection\DoctrineReflection; use staabm\PHPStanDba\PdoReflection\PdoStatementReflection; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\QueryReflection\QueryReflector; @@ -60,6 +59,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method private function inferType(MethodReflection $methodReflection, MethodCall $methodCall, Expr $paramsExpr, Scope $scope): ?Type { + $doctrineReflection = new DoctrineReflection(); + $parameterTypes = $scope->getType($paramsExpr); $stmtReflection = new PdoStatementReflection(); @@ -69,16 +70,8 @@ private function inferType(MethodReflection $methodReflection, MethodCall $metho } $queryReflection = new QueryReflection(); - $queryString = $queryReflection->resolvePreparedQueryString($queryExpr, $parameterTypes, $scope); - if (null === $queryString) { - return null; - } - - $resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_BOTH); - if ($resultType) { - return new GenericObjectType(Result::class, [$resultType]); - } + $queryStrings = $queryReflection->resolvePreparedQueryStrings($queryExpr, $parameterTypes, $scope); - return null; + return $doctrineReflection->createGenericResult($queryStrings, QueryReflector::FETCH_TYPE_BOTH); } } diff --git a/tests/default/data/doctrine-dbal-union-result.php b/tests/default/data/doctrine-dbal-union-result.php index 2b9ad88a7..b4d98e5d8 100644 --- a/tests/default/data/doctrine-dbal-union-result.php +++ b/tests/default/data/doctrine-dbal-union-result.php @@ -16,12 +16,14 @@ public function doFoo(Connection $conn) assertType('Doctrine\DBAL\Statement, 0: int<0, 4294967295>}>|Doctrine\DBAL\Statement', $stmt); $result = $stmt->executeQuery([]); - assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>', $result); + assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>|Doctrine\DBAL\Result', $result); + $result = $stmt->execute([]); - assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>', $result); + assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>|Doctrine\DBAL\Result', $result); - $fetch = $result->fetchOne(); - assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>', $fetch); + // XXX todo + // $fetch = $result->fetchOne(); + // assertType('Doctrine\DBAL\Result, 0: int<0, 4294967295>}>', $fetch); } } From d7a1d539133d387067b8ec8bc4ea3a7a4c47b24d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 14 Feb 2022 21:21:44 +0100 Subject: [PATCH 6/6] record --- tests/default/config/.phpstan-dba-pdo.cache | 112 ++++++++++---------- tests/rules/config/.phpstan-dba-pdo.cache | 2 +- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/tests/default/config/.phpstan-dba-pdo.cache b/tests/default/config/.phpstan-dba-pdo.cache index 1a0fedadf..3b507a686 100644 --- a/tests/default/config/.phpstan-dba-pdo.cache +++ b/tests/default/config/.phpstan-dba-pdo.cache @@ -1512,7 +1512,7 @@ array ( 'result' => array ( - 3 => + 5 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -1522,6 +1522,10 @@ 'value' => 'adaid', 'isClassString' => false, )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), ), 'valueTypes' => array ( @@ -1530,15 +1534,30 @@ 'min' => 0, 'max' => 4294967295, )), + 1 => + PHPStan\Type\IntegerRangeType::__set_state(array( + 'min' => 0, + 'max' => 4294967295, + )), ), - 'nextAutoIndex' => 0, + 'nextAutoIndex' => 1, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'adaid', - 'isClassString' => false, + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, + )), + ), )), 'itemType' => PHPStan\Type\IntegerRangeType::__set_state(array( @@ -1546,7 +1565,7 @@ 'max' => 4294967295, )), )), - 5 => + 3 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -1556,10 +1575,6 @@ 'value' => 'adaid', 'isClassString' => false, )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), ), 'valueTypes' => array ( @@ -1568,30 +1583,15 @@ 'min' => 0, 'max' => 4294967295, )), - 1 => - PHPStan\Type\IntegerRangeType::__set_state(array( - 'min' => 0, - 'max' => 4294967295, - )), ), - 'nextAutoIndex' => 1, + 'nextAutoIndex' => 0, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'adaid', - 'isClassString' => false, - )), - ), + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'adaid', + 'isClassString' => false, )), 'itemType' => PHPStan\Type\IntegerRangeType::__set_state(array( @@ -2585,7 +2585,7 @@ array ( 'result' => array ( - 3 => + 5 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -2595,27 +2595,44 @@ 'value' => 'email', 'isClassString' => false, )), + 1 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), ), 'valueTypes' => array ( 0 => PHPStan\Type\StringType::__set_state(array( )), + 1 => + PHPStan\Type\StringType::__set_state(array( + )), ), - 'nextAutoIndex' => 0, + 'nextAutoIndex' => 1, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, + PHPStan\Type\UnionType::__set_state(array( + 'types' => + array ( + 0 => + PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( + 'value' => 0, + )), + 1 => + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, + )), + ), )), 'itemType' => PHPStan\Type\StringType::__set_state(array( )), )), - 5 => + 3 => PHPStan\Type\Constant\ConstantArrayType::__set_state(array( 'allArrays' => NULL, 'keyTypes' => @@ -2625,38 +2642,21 @@ 'value' => 'email', 'isClassString' => false, )), - 1 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), ), 'valueTypes' => array ( 0 => PHPStan\Type\StringType::__set_state(array( )), - 1 => - PHPStan\Type\StringType::__set_state(array( - )), ), - 'nextAutoIndex' => 1, + 'nextAutoIndex' => 0, 'optionalKeys' => array ( ), 'keyType' => - PHPStan\Type\UnionType::__set_state(array( - 'types' => - array ( - 0 => - PHPStan\Type\Constant\ConstantIntegerType::__set_state(array( - 'value' => 0, - )), - 1 => - PHPStan\Type\Constant\ConstantStringType::__set_state(array( - 'value' => 'email', - 'isClassString' => false, - )), - ), + PHPStan\Type\Constant\ConstantStringType::__set_state(array( + 'value' => 'email', + 'isClassString' => false, )), 'itemType' => PHPStan\Type\StringType::__set_state(array( diff --git a/tests/rules/config/.phpstan-dba-pdo.cache b/tests/rules/config/.phpstan-dba-pdo.cache index e8565ec04..4fd72dad7 100644 --- a/tests/rules/config/.phpstan-dba-pdo.cache +++ b/tests/rules/config/.phpstan-dba-pdo.cache @@ -972,7 +972,7 @@ array ( 'result' => array ( - 3 => NULL, + 5 => NULL, ), ), 'SELECT email, adaid, gesperrt, freigabe1u1 FROM ada WHERE gesperrt=1' =>