Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix return type of QueryInterface::execute() #163

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have now updated the second type to be a list: b56227c

Do we then need changes to the DynamicReturnTypeExtension in this PR?

*/
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
Loading