Skip to content

Commit a77ca90

Browse files
brambaudmglaman
authored andcommitted
Try a workaround to infer the type of the entity storage when it has been type hinted
1 parent d636610 commit a77ca90

File tree

2 files changed

+76
-19
lines changed

2 files changed

+76
-19
lines changed

src/Type/EntityStorage/EntityStorageDynamicReturnTypeExtension.php

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use PHPStan\Type\IntegerType;
1717
use PHPStan\Type\ObjectType;
1818
use PHPStan\Type\StringType;
19+
use PHPStan\Type\Type;
1920
use PHPStan\Type\TypeCombinator;
2021

2122
class EntityStorageDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
@@ -60,6 +61,18 @@ public function getTypeFromMethodCall(
6061
$callerType = $scope->getType($methodCall->var);
6162

6263
if (!$callerType instanceof EntityStorageType) {
64+
if (!$callerType instanceof ObjectType) {
65+
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
66+
}
67+
68+
// Workaround because cannot figure out why the caller type is not an EntityStorageType
69+
// when it has been type hinted.
70+
// Instead, we try to infer the type, i.e. ContentEntityStorageType or ConfigEntityStorageType, here.
71+
// @todo: we should definitively look for other cases that getQuery.
72+
if ($methodReflection->getName() === 'getQuery') {
73+
return $this->getReturnTypeForGetQueryMethod($methodReflection, EntityStorageHelper::getTypeFromStorageObjectType($callerType));
74+
}
75+
6376
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
6477
}
6578

@@ -79,27 +92,32 @@ public function getTypeFromMethodCall(
7992
return new ArrayType(new IntegerType(), $type);
8093
}
8194
if ($methodReflection->getName() === 'getQuery') {
82-
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
83-
if (!$returnType instanceof ObjectType) {
84-
return $returnType;
85-
}
86-
if ($callerType instanceof ContentEntityStorageType) {
87-
return new ContentEntityQueryType(
88-
$returnType->getClassName(),
89-
$returnType->getSubtractedType(),
90-
$returnType->getClassReflection()
91-
);
92-
}
93-
if ($callerType instanceof ConfigEntityStorageType) {
94-
return new ConfigEntityQueryType(
95-
$returnType->getClassName(),
96-
$returnType->getSubtractedType(),
97-
$returnType->getClassReflection()
98-
);
99-
}
100-
return $returnType;
95+
return $this->getReturnTypeForGetQueryMethod($methodReflection, $callerType);
10196
}
10297

10398
return $type;
10499
}
100+
101+
private function getReturnTypeForGetQueryMethod(MethodReflection $methodReflection, ?Type $entityStorageType): Type
102+
{
103+
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
104+
if (!$returnType instanceof ObjectType) {
105+
return $returnType;
106+
}
107+
if ($entityStorageType instanceof ContentEntityStorageType) {
108+
return new ContentEntityQueryType(
109+
$returnType->getClassName(),
110+
$returnType->getSubtractedType(),
111+
$returnType->getClassReflection()
112+
);
113+
}
114+
if ($entityStorageType instanceof ConfigEntityStorageType) {
115+
return new ConfigEntityQueryType(
116+
$returnType->getClassName(),
117+
$returnType->getSubtractedType(),
118+
$returnType->getClassReflection()
119+
);
120+
}
121+
return $returnType;
122+
}
105123
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace mglaman\PHPStanDrupal\Type\EntityStorage;
6+
7+
use Drupal\Core\Config\Entity\ConfigEntityStorage;
8+
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
9+
use Drupal\Core\Entity\ContentEntityStorageInterface;
10+
use Drupal\Core\Entity\EntityStorageInterface;
11+
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
12+
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
13+
use PHPStan\Type\ObjectType;
14+
15+
final class EntityStorageHelper
16+
{
17+
public static function getTypeFromStorageObjectType(ObjectType $classType): ?EntityStorageType
18+
{
19+
if ((new ObjectType(ConfigEntityStorageInterface::class))->isSuperTypeOf($classType)->yes()) {
20+
$storageClassName = ConfigEntityStorage::class;
21+
} elseif ((new ObjectType(SqlEntityStorageInterface::class))->isSuperTypeOf($classType)->yes()) {
22+
$storageClassName = SqlContentEntityStorage::class;
23+
} else {
24+
return null;
25+
}
26+
27+
$storageType = new ObjectType($storageClassName);
28+
if ((new ObjectType(EntityStorageInterface::class))->isSuperTypeOf($storageType)->no()) {
29+
return null;
30+
}
31+
if ((new ObjectType(ConfigEntityStorageInterface::class))->isSuperTypeOf($storageType)->yes()) {
32+
return new ConfigEntityStorageType('', $storageClassName);
33+
}
34+
if ((new ObjectType(ContentEntityStorageInterface::class))->isSuperTypeOf($storageType)->yes()) {
35+
return new ContentEntityStorageType('', $storageClassName);
36+
}
37+
return new EntityStorageType('', $storageClassName);
38+
}
39+
}

0 commit comments

Comments
 (0)