Skip to content

Commit

Permalink
Do not infer getArrayResult for now
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jun 30, 2024
1 parent 66d6943 commit 6051e97
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 175 deletions.
48 changes: 0 additions & 48 deletions src/Type/Doctrine/HydrationModeReturnTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()) {
Expand Down
37 changes: 15 additions & 22 deletions src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ final class QueryResultDynamicReturnTypeExtension implements DynamicMethodReturn
'getSingleResult' => 0,
];

private const METHOD_HYDRATION_MODE = [
'getArrayResult' => AbstractQuery::HYDRATE_ARRAY,
];

/** @var ObjectMetadataResolver */
private $objectMetadataResolver;

Expand All @@ -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(
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()],
Expand Down Expand Up @@ -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(),
'
Expand All @@ -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(),
'
Expand Down
35 changes: 0 additions & 35 deletions tests/Type/Doctrine/data/QueryResult/queryResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<array{intColumn: int, stringNullColumn: string|null, datetimeColumn: DateTime}>',
$query->getResult(AbstractQuery::HYDRATE_ARRAY)
);
assertType(
'list<array{intColumn: int, stringNullColumn: string|null, datetimeColumn: DateTime}>',
$query->getArrayResult()
);
assertType(
'list<array{intColumn: int, stringNullColumn: string|null, datetimeColumn: DateTime}>',
$query->execute(null, AbstractQuery::HYDRATE_ARRAY)
);
assertType(
'list<array{intColumn: int, stringNullColumn: string|null, datetimeColumn: DateTime}>',
$query->executeIgnoreQueryCache(null, AbstractQuery::HYDRATE_ARRAY)
);
assertType(
'list<array{intColumn: int, stringNullColumn: string|null, datetimeColumn: DateTime}>',
$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)
);
}


Expand Down

0 comments on commit 6051e97

Please sign in to comment.