Skip to content

Commit

Permalink
Fix return type of QueryInterface::execute()
Browse files Browse the repository at this point in the history
The execute mehtod has a boolean argument that
defines if a raw result should be returned.
This means that no object mapping is done but
an array containing the result values is returned.

It is now also supported to not just pass constant
boolean values but a variable containing a boolean
to the execute function. In this case it's not clear
if a raw result or objects should be returned
so we do now return a union type containing both.
  • Loading branch information
sascha-egerer committed May 22, 2024
1 parent a7549f5 commit 5bd227d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 15 deletions.
20 changes: 15 additions & 5 deletions src/Type/QueryInterfaceDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use SaschaEgerer\PhpstanTypo3\Helpers\Typo3ClassNamingUtilityTrait;
use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
Expand Down Expand Up @@ -45,7 +48,6 @@ public function getTypeFromMethodCall(
$argument = $methodCall->getArgs()[0] ?? null;

$classReflection = $scope->getClassReflection();

$queryType = $scope->getType($methodCall->var);
if ($queryType instanceof GenericObjectType) {
$modelType = $queryType->getTypes();
Expand All @@ -64,15 +66,23 @@ public function getTypeFromMethodCall(
}
}

$returnType = new GenericObjectType(QueryResult::class, $modelType);
$rawReturnType = new ArrayType(new IntegerType(), new ArrayType(new StringType(), new MixedType()));

if ($argument !== null) {
$argType = $scope->getType($argument->value);

if ($classReflection !== null && $argType instanceof ConstantBooleanType && $argType->getValue() === true) {
return new ArrayType(new IntegerType(), $modelType[0]);
if ($argType instanceof ConstantBooleanType) {
if ($argType->getValue() === true) {
// A static boolean value with "true" has been given
return $rawReturnType;
}
} elseif ($argType instanceof BooleanType) {
// A variable with a boolean value has been given but we don't know it's value
return TypeCombinator::union($rawReturnType, $returnType);
}
}

return new GenericObjectType(QueryResult::class, $modelType);
return $returnType;
}

}
6 changes: 0 additions & 6 deletions stubs/QueryInterface.stub
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ namespace TYPO3\CMS\Extbase\Persistence;
*/
interface QueryInterface
{
/**
* @param bool $returnRawQueryResult
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface<ModelType>|array<string, mixed>
*/
public function execute($returnRawQueryResult = false);

/**
* @param mixed $constraint
* @return \TYPO3\CMS\Extbase\Persistence\QueryInterface<ModelType>
Expand Down
20 changes: 16 additions & 4 deletions tests/Unit/Type/data/custom-query-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,31 @@ class SomeOtherModel extends AbstractEntity
class MyModelRepository extends Repository
{

public function findBySomething(): void
public function findBySomething(bool $booleanParameter = false): void
{
/** @var QueryInterface<SomeOtherModel> $query */
$query = $this->persistenceManager->createQueryForType(SomeOtherModel::class);

$result = $query->execute();
assertType(
'TYPO3\CMS\Extbase\Persistence\QueryInterface<CustomQueryType\My\Test\Extension\Domain\Model\SomeOtherModel>',
$query
'TYPO3\CMS\Extbase\Persistence\Generic\QueryResult<CustomQueryType\My\Test\Extension\Domain\Model\SomeOtherModel>',
$result
);

$result = $query->execute(false);
assertType(
'TYPO3\CMS\Extbase\Persistence\Generic\QueryResult<CustomQueryType\My\Test\Extension\Domain\Model\SomeOtherModel>',
$result
);

$result = $query->execute($booleanParameter);
assertType(
'array<int, array<string, mixed>>|TYPO3\CMS\Extbase\Persistence\Generic\QueryResult<CustomQueryType\My\Test\Extension\Domain\Model\SomeOtherModel>',
$result
);

$rawResult = $query->execute(true);
assertType('array<int, CustomQueryType\My\Test\Extension\Domain\Model\SomeOtherModel>', $rawResult);
assertType('array<int, array<string, mixed>>', $rawResult);

$array = $result->toArray();
assertType('array<int, CustomQueryType\My\Test\Extension\Domain\Model\SomeOtherModel>', $array);
Expand Down

0 comments on commit 5bd227d

Please sign in to comment.