Skip to content

Commit 5fe2128

Browse files
authored
Entity county query use non-negative-int for execute return type (#919)
fixes #909
1 parent 2574aac commit 5fe2128

File tree

6 files changed

+85
-14
lines changed

6 files changed

+85
-14
lines changed

src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtension.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PHPStan\Reflection\ParametersAcceptorSelector;
1010
use PHPStan\Type\ArrayType;
1111
use PHPStan\Type\DynamicMethodReturnTypeExtension;
12+
use PHPStan\Type\IntegerRangeType;
1213
use PHPStan\Type\IntegerType;
1314
use PHPStan\Type\ObjectType;
1415
use PHPStan\Type\StringType;
@@ -63,7 +64,7 @@ public function getTypeFromMethodCall(
6364
}
6465
if ($varType->isCount()) {
6566
return $varType->hasAccessCheck()
66-
? new IntegerType()
67+
? IntegerRangeType::createAllGreaterThanOrEqualTo(0)
6768
: new EntityQueryExecuteWithoutAccessCheckCountType();
6869
}
6970
if ($varType instanceof ConfigEntityQueryType) {

src/Type/EntityQuery/EntityQueryExecuteWithoutAccessCheckCountType.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,23 @@
44

55
namespace mglaman\PHPStanDrupal\Type\EntityQuery;
66

7+
use PHPStan\Type\IntegerRangeType;
78
use PHPStan\Type\IntegerType;
9+
use PHPStan\Type\Type;
10+
use PHPStan\Type\VerbosityLevel;
811

912
final class EntityQueryExecuteWithoutAccessCheckCountType extends IntegerType
1013
{
14+
private Type $rangeType;
1115

16+
public function __construct()
17+
{
18+
parent::__construct();
19+
$this->rangeType = IntegerRangeType::createAllGreaterThanOrEqualTo(0);
20+
}
21+
22+
public function describe(VerbosityLevel $level): string
23+
{
24+
return $this->rangeType->describe($level);
25+
}
1226
}

tests/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public static function dataFileAsserts(): iterable
1616
yield from self::gatherAssertTypes(__DIR__ . '/../data/entity-query-execute.php');
1717
yield from self::gatherAssertTypes(__DIR__ . '/../data/bug-355-entity-query.php');
1818
yield from self::gatherAssertTypes(__DIR__ . '/../data/bug-522.php');
19+
yield from self::gatherAssertTypes(__DIR__ . '/../data/bug-909.php');
1920

2021
}
2122

tests/src/Type/data/bug-355-entity-query.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
->accessCheck(TRUE);
1818
assertType('array<int, string>', $query->execute());
1919
assertType(
20-
'int',
20+
'int<0, max>',
2121
$typedNodeStorage->getQuery()
2222
->accessCheck(TRUE)
2323
->count()
@@ -26,7 +26,7 @@
2626
$query = $typedNodeStorage->getQuery()
2727
->accessCheck(TRUE)
2828
->count();
29-
assertType('int', $query->execute());
29+
assertType('int<0, max>', $query->execute());
3030

3131
/** @var \Drupal\node\NodeStorageInterface $anotherTypedNodeStorage */
3232
$anotherTypedNodeStorage = \Drupal::entityTypeManager()->getStorage('node');
@@ -40,7 +40,7 @@
4040
->accessCheck(TRUE);
4141
assertType('array<int, string>', $query->execute());
4242
assertType(
43-
'int',
43+
'int<0, max>',
4444
$anotherTypedNodeStorage->getQuery()
4545
->accessCheck(TRUE)
4646
->count()
@@ -49,7 +49,7 @@
4949
$query = $anotherTypedNodeStorage->getQuery()
5050
->accessCheck(TRUE)
5151
->count();
52-
assertType('int', $query->execute());
52+
assertType('int<0, max>', $query->execute());
5353

5454
$instanceOfNodeStorage = \Drupal::entityTypeManager()->getStorage('node');
5555
if ($instanceOfNodeStorage instanceof NodeStorage) {
@@ -63,7 +63,7 @@
6363
->accessCheck(TRUE);
6464
assertType('array<int, string>', $query->execute());
6565
assertType(
66-
'int',
66+
'int<0, max>',
6767
$instanceOfNodeStorage->getQuery()
6868
->accessCheck(TRUE)
6969
->count()
@@ -72,5 +72,5 @@
7272
$query = $instanceOfNodeStorage->getQuery()
7373
->accessCheck(TRUE)
7474
->count();
75-
assertType('int', $query->execute());
75+
assertType('int<0, max>', $query->execute());
7676
}

tests/src/Type/data/bug-909.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace DrupalEntity;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
// Test case from issue #909: Entity query count() should return non-negative-int
8+
// Currently this fails because PHPStan returns 'int' instead of 'int<0, max>'
9+
assertType(
10+
'int<0, max>',
11+
\Drupal::entityTypeManager()
12+
->getStorage('example')
13+
->getQuery()
14+
->accessCheck()
15+
->count()
16+
->execute()
17+
);
18+
19+
// Additional test cases to ensure consistency across different entity query patterns
20+
assertType(
21+
'int<0, max>',
22+
\Drupal::entityTypeManager()
23+
->getStorage('node')
24+
->getQuery()
25+
->accessCheck(TRUE)
26+
->count()
27+
->execute()
28+
);
29+
30+
assertType(
31+
'int<0, max>',
32+
\Drupal::entityQuery('node')
33+
->accessCheck(TRUE)
34+
->count()
35+
->execute()
36+
);
37+
38+
assertType(
39+
'int<0, max>',
40+
\Drupal::entityQuery('block')
41+
->count()
42+
->execute()
43+
);
44+
45+
// Test with additional conditions - should still return non-negative-int
46+
assertType(
47+
'int<0, max>',
48+
\Drupal::entityTypeManager()
49+
->getStorage('node')
50+
->getQuery()
51+
->count()
52+
->condition('status', 1)
53+
->accessCheck(TRUE)
54+
->execute()
55+
);

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@
1515
->execute()
1616
);
1717
assertType(
18-
'int',
18+
'int<0, max>',
1919
\Drupal::entityTypeManager()->getStorage('node')->getQuery()
2020
->accessCheck(TRUE)
2121
->count()
2222
->execute()
2323
);
2424
assertType(
25-
'int',
25+
'int<0, max>',
2626
\Drupal::entityTypeManager()->getStorage('node')->getQuery()
2727
->count()
2828
->condition('foo', 'bar')
2929
->accessCheck(TRUE)
3030
->execute()
3131
);
3232
assertType(
33-
'int',
33+
'int<0, max>',
3434
\Drupal::entityQuery('node')
3535
->accessCheck(TRUE)
3636
->count()
@@ -48,7 +48,7 @@
4848
assertType('array<int, string>', $query->execute());
4949
$query = \Drupal::entityTypeManager()->getStorage('node')->getQuery()
5050
->accessCheck(TRUE)->count();
51-
assertType('int', $query->execute());
51+
assertType('int<0, max>', $query->execute());
5252

5353
assertType(
5454
'array<string, string>',
@@ -62,14 +62,14 @@
6262
->execute()
6363
);
6464
assertType(
65-
'int',
65+
'int<0, max>',
6666
\Drupal::entityTypeManager()->getStorage('block')->getQuery()
6767
->accessCheck(TRUE)
6868
->count()
6969
->execute()
7070
);
7171
assertType(
72-
'int',
72+
'int<0, max>',
7373
\Drupal::entityQuery('block')
7474
->accessCheck(TRUE)
7575
->count()
@@ -87,4 +87,4 @@
8787
assertType('array<string, string>', $query->execute());
8888
$query = \Drupal::entityTypeManager()->getStorage('block')->getQuery()
8989
->accessCheck(TRUE)->count();
90-
assertType('int', $query->execute());
90+
assertType('int<0, max>', $query->execute());

0 commit comments

Comments
 (0)