Skip to content

Commit 43c6132

Browse files
committed
Leverage custom object type for county entity queries
1 parent 9242eb0 commit 43c6132

File tree

4 files changed

+63
-29
lines changed

4 files changed

+63
-29
lines changed

extension.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ services:
4444
class: mglaman\PHPStanDrupal\Type\DrupalClassResolverDynamicReturnTypeExtension
4545
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
4646
-
47-
class: mglaman\PHPStanDrupal\Type\EntityQueryDynamicReturnTypeExtension
47+
class: mglaman\PHPStanDrupal\Type\EntityQuery\EntityQueryDynamicReturnTypeExtension
4848
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
4949
-
5050
class: mglaman\PHPStanDrupal\Type\DrupalClassResolverDynamicStaticReturnTypeExtension
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace mglaman\PHPStanDrupal\Type\EntityQuery;
4+
5+
use PHPStan\Type\ObjectType;
6+
7+
/**
8+
* Type used to represent an entity query instance as count query.
9+
*/
10+
final class EntityQueryCountType extends ObjectType
11+
{
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<?php declare(strict_types=1);
22

3-
namespace mglaman\PHPStanDrupal\Type;
3+
namespace mglaman\PHPStanDrupal\Type\EntityQuery;
44

55
use Drupal\Core\Entity\Query\QueryInterface;
66
use PhpParser\Node\Expr\MethodCall;
7-
use PhpParser\Node\Identifier;
87
use PHPStan\Analyser\Scope;
98
use PHPStan\Reflection\MethodReflection;
109
use PHPStan\Reflection\ParametersAcceptorSelector;
@@ -25,7 +24,10 @@ public function getClass(): string
2524

2625
public function isMethodSupported(MethodReflection $methodReflection): bool
2726
{
28-
return $methodReflection->getName() === 'execute';
27+
return in_array($methodReflection->getName(), [
28+
'count',
29+
'execute',
30+
], true);
2931
}
3032

3133
public function getTypeFromMethodCall(
@@ -34,28 +36,31 @@ public function getTypeFromMethodCall(
3436
Scope $scope
3537
): Type {
3638
$defaultReturnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
37-
38-
$queryBuilderType = new ObjectType(QueryInterface::class);
39-
$var = $methodCall->var;
40-
while ($var instanceof MethodCall) {
41-
$varType = $scope->getType($var->var);
42-
if (!$queryBuilderType->isSuperTypeOf($varType)->yes()) {
43-
return new ArrayType(new IntegerType(), new StringType());
44-
}
45-
46-
$nameObject = $var->name;
47-
if (!($nameObject instanceof Identifier)) {
48-
return $defaultReturnType;
39+
$varType = $scope->getType($methodCall->var);
40+
$methodName = $methodReflection->getName();
41+
if ($methodName === 'count') {
42+
if ($varType instanceof ObjectType) {
43+
return new EntityQueryCountType(
44+
$varType->getClassName(),
45+
$varType->getSubtractedType(),
46+
$varType->getClassReflection()
47+
);
4948
}
49+
return $defaultReturnType;
50+
}
5051

51-
$name = $nameObject->toString();
52-
if ($name === 'count') {
52+
if ($methodName === 'execute') {
53+
if ($varType instanceof EntityQueryCountType) {
5354
return new IntegerType();
5455
}
55-
56-
$var = $var->var;
56+
if ($varType instanceof ObjectType) {
57+
// @todo if this is a config storage, it'd string keys.
58+
// revisit after https://github.com/mglaman/phpstan-drupal/pull/239
59+
// then we can check what kind of storage we have.
60+
return new ArrayType(new IntegerType(), new StringType());
61+
}
62+
return $defaultReturnType;
5763
}
58-
5964
return $defaultReturnType;
6065
}
6166
}

tests/src/Type/data/entity-query-execute.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
namespace DrupalEntity;
44

55
use function PHPStan\Testing\assertType;
6-
6+
assertType(
7+
'array<int, string>',
8+
\Drupal::entityTypeManager()->getStorage('node')->getQuery()
9+
->execute()
10+
);
711
assertType(
812
'array<int, string>',
913
\Drupal::entityTypeManager()->getStorage('node')->getQuery()
@@ -17,11 +21,23 @@
1721
->count()
1822
->execute()
1923
);
24+
assertType(
25+
'int',
26+
\Drupal::entityQuery('node')
27+
->accessCheck(TRUE)
28+
->count()
29+
->execute()
30+
);
31+
assertType(
32+
'array<int, string>',
33+
\Drupal::entityQuery('node')
34+
->accessCheck(TRUE)
35+
->execute()
36+
);
2037

21-
// @todo: find a way support these cases.
22-
//$query = \Drupal::entityTypeManager()->getStorage('node')->getQuery()
23-
// ->accessCheck(TRUE);
24-
//assertType('array<int, string>', $query->execute());
25-
//$query = \Drupal::entityTypeManager()->getStorage('node')->getQuery()
26-
// ->accessCheck(TRUE)->count();
27-
//assertType('int', $query->execute());
38+
$query = \Drupal::entityTypeManager()->getStorage('node')->getQuery()
39+
->accessCheck(TRUE);
40+
assertType('array<int, string>', $query->execute());
41+
$query = \Drupal::entityTypeManager()->getStorage('node')->getQuery()
42+
->accessCheck(TRUE)->count();
43+
assertType('int', $query->execute());

0 commit comments

Comments
 (0)