Skip to content

Commit

Permalink
doctrine-dbal might return list
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Nov 26, 2024
1 parent b32c279 commit ed5fe01
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
38 changes: 35 additions & 3 deletions src/DoctrineReflection/DoctrineReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace staabm\PHPStanDba\DoctrineReflection;

use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\Accessory\AccessoryArrayListType;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantBooleanType;
Expand Down Expand Up @@ -43,6 +44,7 @@ public function reduceResultType(MethodReflection $methodReflection, Type $resul

$usedMethod = strtolower($methodReflection->getName());

$returnsList = false;
switch ($usedMethod) {
case 'fetchallkeyvalue':
case 'iteratekeyvalue':
Expand All @@ -52,16 +54,25 @@ public function reduceResultType(MethodReflection $methodReflection, Type $resul
$fetchType = QueryReflector::FETCH_TYPE_ONE;
break;
case 'fetchfirstcolumn':
$returnsList = true;
$fetchType = QueryReflector::FETCH_TYPE_FIRST_COL;
break;
case 'iteratecolumn':
$fetchType = QueryReflector::FETCH_TYPE_FIRST_COL;
break;
case 'fetchnumeric':
case 'fetchallnumeric':
$returnsList = true;
$fetchType = QueryReflector::FETCH_TYPE_NUMERIC;
break;
case 'iteratenumeric':
$fetchType = QueryReflector::FETCH_TYPE_NUMERIC;
break;
case 'fetchassociative':
case 'fetchallassociative':
$returnsList = true;
$fetchType = QueryReflector::FETCH_TYPE_ASSOC;
break;
case 'fetchassociative':
case 'iterateassociative':
$fetchType = QueryReflector::FETCH_TYPE_ASSOC;
break;
Expand Down Expand Up @@ -99,7 +110,14 @@ public function reduceResultType(MethodReflection $methodReflection, Type $resul
return new GenericObjectType(Traversable::class, [new IntegerType(), $valueTypes[$i]]);
}

return new ArrayType(IntegerRangeType::fromInterval(0, null), $valueTypes[$i]);
$arrayType = new ArrayType(IntegerRangeType::fromInterval(0, null), $valueTypes[$i]);
if ($returnsList) {
return TypeCombinator::intersect(
$arrayType,
new AccessoryArrayListType()
);
}
return $arrayType;
}

if (QueryReflector::FETCH_TYPE_NUMERIC === $fetchType && $keyType->isInteger()->yes()) {
Expand All @@ -116,7 +134,21 @@ public function reduceResultType(MethodReflection $methodReflection, Type $resul
}

if (\in_array($usedMethod, ['fetchallnumeric', 'fetchallassociative'], true)) {
return new ArrayType(IntegerRangeType::fromInterval(0, null), $resultType);
$arrayType = new ArrayType(IntegerRangeType::fromInterval(0, null), $resultType);
if ($returnsList) {
return TypeCombinator::intersect(
$arrayType,
new AccessoryArrayListType()
);
}
return $arrayType;
}

if ($returnsList) {
$resultType = TypeCombinator::intersect(
$resultType,
new AccessoryArrayListType()
);
}

// false is returned if no rows are found.
Expand Down
18 changes: 9 additions & 9 deletions tests/default/data/doctrine-dbal.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ public function foo(Connection $conn)
assertType('array{string, int<-32768, 32767>}|false', $fetch);

$fetch = $result->fetchFirstColumn();
assertType('array<int<0, max>, string>', $fetch);
assertType('list<string>', $fetch);

$fetch = $result->fetchAssociative();
assertType('array{email: string, adaid: int<-32768, 32767>}|false', $fetch);

$fetch = $result->fetchAllNumeric();
assertType('array<int<0, max>, array{string, int<-32768, 32767>}>', $fetch);
assertType('list<array{string, int<-32768, 32767>}>', $fetch);

$fetch = $result->fetchAllAssociative();
assertType('array<int<0, max>, array{email: string, adaid: int<-32768, 32767>}>', $fetch);
assertType('list<array{email: string, adaid: int<-32768, 32767>}>', $fetch);

$fetch = $result->fetchAllKeyValue();
assertType('array<string, int<-32768, 32767>>', $fetch);
Expand Down Expand Up @@ -155,33 +155,33 @@ public function fetchFirstColumn(Connection $conn)
{
$query = 'SELECT email, adaid FROM ada WHERE adaid = ?';
$fetchResult = $conn->fetchFirstColumn($query, [1]);
assertType('array<int<0, max>, string>', $fetchResult);
assertType('list<string>', $fetchResult);

$query = 'SELECT email, adaid FROM ada';
$fetchResult = $conn->fetchFirstColumn($query);
assertType('array<int<0, max>, string>', $fetchResult);
assertType('list<string>', $fetchResult);
}

public function fetchAllNumeric(Connection $conn)
{
$query = 'SELECT email, adaid FROM ada WHERE adaid = ?';
$fetchResult = $conn->fetchAllNumeric($query, [1]);
assertType('array<int<0, max>, array{string, int<-32768, 32767>}>', $fetchResult);
assertType('list<array{string, int<-32768, 32767>}>', $fetchResult);

$query = 'SELECT email, adaid FROM ada';
$fetchResult = $conn->fetchAllNumeric($query);
assertType('array<int<0, max>, array{string, int<-32768, 32767>}>', $fetchResult);
assertType('list<array{string, int<-32768, 32767>}>', $fetchResult);
}

public function fetchAllAssociative(Connection $conn)
{
$query = 'SELECT email, adaid FROM ada WHERE adaid = ?';
$fetchResult = $conn->fetchAllAssociative($query, [1]);
assertType('array<int<0, max>, array{email: string, adaid: int<-32768, 32767>}>', $fetchResult);
assertType('list<array{email: string, adaid: int<-32768, 32767>}>', $fetchResult);

$query = 'SELECT email, adaid FROM ada';
$fetchResult = $conn->fetchAllAssociative($query);
assertType('array<int<0, max>, array{email: string, adaid: int<-32768, 32767>}>', $fetchResult);
assertType('list<array{email: string, adaid: int<-32768, 32767>}>', $fetchResult);
}

public function fetchAllKeyValue(Connection $conn)
Expand Down

0 comments on commit ed5fe01

Please sign in to comment.