diff --git a/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtension.php b/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtension.php index c543e86c..e2cebad9 100644 --- a/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtension.php +++ b/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtension.php @@ -9,6 +9,7 @@ use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\ArrayType; use PHPStan\Type\DynamicMethodReturnTypeExtension; +use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntegerType; use PHPStan\Type\ObjectType; use PHPStan\Type\StringType; @@ -63,7 +64,7 @@ public function getTypeFromMethodCall( } if ($varType->isCount()) { return $varType->hasAccessCheck() - ? new IntegerType() + ? IntegerRangeType::createAllGreaterThanOrEqualTo(0) : new EntityQueryExecuteWithoutAccessCheckCountType(); } if ($varType instanceof ConfigEntityQueryType) { diff --git a/src/Type/EntityQuery/EntityQueryExecuteWithoutAccessCheckCountType.php b/src/Type/EntityQuery/EntityQueryExecuteWithoutAccessCheckCountType.php index 8c42c5ea..de5d4688 100644 --- a/src/Type/EntityQuery/EntityQueryExecuteWithoutAccessCheckCountType.php +++ b/src/Type/EntityQuery/EntityQueryExecuteWithoutAccessCheckCountType.php @@ -4,9 +4,23 @@ namespace mglaman\PHPStanDrupal\Type\EntityQuery; +use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntegerType; +use PHPStan\Type\Type; +use PHPStan\Type\VerbosityLevel; final class EntityQueryExecuteWithoutAccessCheckCountType extends IntegerType { + private Type $rangeType; + public function __construct() + { + parent::__construct(); + $this->rangeType = IntegerRangeType::createAllGreaterThanOrEqualTo(0); + } + + public function describe(VerbosityLevel $level): string + { + return $this->rangeType->describe($level); + } } diff --git a/tests/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtensionTest.php b/tests/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtensionTest.php index 10117ebc..8d2086c1 100644 --- a/tests/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtensionTest.php +++ b/tests/src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtensionTest.php @@ -16,6 +16,7 @@ public static function dataFileAsserts(): iterable yield from self::gatherAssertTypes(__DIR__ . '/../data/entity-query-execute.php'); yield from self::gatherAssertTypes(__DIR__ . '/../data/bug-355-entity-query.php'); yield from self::gatherAssertTypes(__DIR__ . '/../data/bug-522.php'); + yield from self::gatherAssertTypes(__DIR__ . '/../data/bug-909.php'); } diff --git a/tests/src/Type/data/bug-355-entity-query.php b/tests/src/Type/data/bug-355-entity-query.php index f435519d..01297a37 100644 --- a/tests/src/Type/data/bug-355-entity-query.php +++ b/tests/src/Type/data/bug-355-entity-query.php @@ -17,7 +17,7 @@ ->accessCheck(TRUE); assertType('array', $query->execute()); assertType( - 'int', + 'int<0, max>', $typedNodeStorage->getQuery() ->accessCheck(TRUE) ->count() @@ -26,7 +26,7 @@ $query = $typedNodeStorage->getQuery() ->accessCheck(TRUE) ->count(); -assertType('int', $query->execute()); +assertType('int<0, max>', $query->execute()); /** @var \Drupal\node\NodeStorageInterface $anotherTypedNodeStorage */ $anotherTypedNodeStorage = \Drupal::entityTypeManager()->getStorage('node'); @@ -40,7 +40,7 @@ ->accessCheck(TRUE); assertType('array', $query->execute()); assertType( - 'int', + 'int<0, max>', $anotherTypedNodeStorage->getQuery() ->accessCheck(TRUE) ->count() @@ -49,7 +49,7 @@ $query = $anotherTypedNodeStorage->getQuery() ->accessCheck(TRUE) ->count(); -assertType('int', $query->execute()); +assertType('int<0, max>', $query->execute()); $instanceOfNodeStorage = \Drupal::entityTypeManager()->getStorage('node'); if ($instanceOfNodeStorage instanceof NodeStorage) { @@ -63,7 +63,7 @@ ->accessCheck(TRUE); assertType('array', $query->execute()); assertType( - 'int', + 'int<0, max>', $instanceOfNodeStorage->getQuery() ->accessCheck(TRUE) ->count() @@ -72,5 +72,5 @@ $query = $instanceOfNodeStorage->getQuery() ->accessCheck(TRUE) ->count(); - assertType('int', $query->execute()); + assertType('int<0, max>', $query->execute()); } diff --git a/tests/src/Type/data/bug-909.php b/tests/src/Type/data/bug-909.php new file mode 100644 index 00000000..1fc7e473 --- /dev/null +++ b/tests/src/Type/data/bug-909.php @@ -0,0 +1,55 @@ +' +assertType( + 'int<0, max>', + \Drupal::entityTypeManager() + ->getStorage('example') + ->getQuery() + ->accessCheck() + ->count() + ->execute() +); + +// Additional test cases to ensure consistency across different entity query patterns +assertType( + 'int<0, max>', + \Drupal::entityTypeManager() + ->getStorage('node') + ->getQuery() + ->accessCheck(TRUE) + ->count() + ->execute() +); + +assertType( + 'int<0, max>', + \Drupal::entityQuery('node') + ->accessCheck(TRUE) + ->count() + ->execute() +); + +assertType( + 'int<0, max>', + \Drupal::entityQuery('block') + ->count() + ->execute() +); + +// Test with additional conditions - should still return non-negative-int +assertType( + 'int<0, max>', + \Drupal::entityTypeManager() + ->getStorage('node') + ->getQuery() + ->count() + ->condition('status', 1) + ->accessCheck(TRUE) + ->execute() +); \ No newline at end of file diff --git a/tests/src/Type/data/entity-query-execute.php b/tests/src/Type/data/entity-query-execute.php index ce9a89f0..b828d28d 100644 --- a/tests/src/Type/data/entity-query-execute.php +++ b/tests/src/Type/data/entity-query-execute.php @@ -15,14 +15,14 @@ ->execute() ); assertType( - 'int', + 'int<0, max>', \Drupal::entityTypeManager()->getStorage('node')->getQuery() ->accessCheck(TRUE) ->count() ->execute() ); assertType( - 'int', + 'int<0, max>', \Drupal::entityTypeManager()->getStorage('node')->getQuery() ->count() ->condition('foo', 'bar') @@ -30,7 +30,7 @@ ->execute() ); assertType( - 'int', + 'int<0, max>', \Drupal::entityQuery('node') ->accessCheck(TRUE) ->count() @@ -48,7 +48,7 @@ assertType('array', $query->execute()); $query = \Drupal::entityTypeManager()->getStorage('node')->getQuery() ->accessCheck(TRUE)->count(); -assertType('int', $query->execute()); +assertType('int<0, max>', $query->execute()); assertType( 'array', @@ -62,14 +62,14 @@ ->execute() ); assertType( - 'int', + 'int<0, max>', \Drupal::entityTypeManager()->getStorage('block')->getQuery() ->accessCheck(TRUE) ->count() ->execute() ); assertType( - 'int', + 'int<0, max>', \Drupal::entityQuery('block') ->accessCheck(TRUE) ->count() @@ -87,4 +87,4 @@ assertType('array', $query->execute()); $query = \Drupal::entityTypeManager()->getStorage('block')->getQuery() ->accessCheck(TRUE)->count(); -assertType('int', $query->execute()); +assertType('int<0, max>', $query->execute());