Skip to content

Commit 68b7603

Browse files
authored
Resolve active record static method type by return type (proget-hq#40)
1 parent 586c8bb commit 68b7603

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

src/Type/ActiveRecordDynamicStaticMethodReturnTypeExtension.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,40 @@
88
use PhpParser\Node\Name;
99
use PHPStan\Analyser\Scope;
1010
use PHPStan\Reflection\MethodReflection;
11+
use PHPStan\Reflection\ParametersAcceptorSelector;
1112
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
1213
use PHPStan\Type\NullType;
14+
use PHPStan\Type\ObjectType;
15+
use PHPStan\Type\ThisType;
1316
use PHPStan\Type\Type;
1417
use PHPStan\Type\TypeCombinator;
18+
use PHPStan\Type\UnionType;
19+
use yii\db\ActiveQuery;
20+
use yii\db\ActiveRecord;
1521

1622
final class ActiveRecordDynamicStaticMethodReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension
1723
{
1824
public function getClass(): string
1925
{
20-
return 'yii\db\ActiveRecord';
26+
return ActiveRecord::class;
2127
}
2228

2329
public function isStaticMethodSupported(MethodReflection $methodReflection): bool
2430
{
25-
return \in_array($methodReflection->getName(), ['findOne', 'find'], true);
31+
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
32+
if ($returnType instanceof ThisType) {
33+
return true;
34+
}
35+
36+
if ($returnType instanceof UnionType) {
37+
foreach ($returnType->getTypes() as $type) {
38+
if ($type instanceof ObjectType) {
39+
return \is_a($type->getClassName(), $this->getClass(), true);
40+
}
41+
}
42+
}
43+
44+
return $returnType instanceof ObjectType && \is_a($returnType->getClassName(), ActiveQuery::class, true);
2645
}
2746

2847
public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): Type
@@ -31,8 +50,12 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection,
3150
$className = $methodCall->class;
3251
$name = $scope->resolveName($className);
3352

34-
$methodName = $methodReflection->getName();
35-
if ($methodName === 'findOne') {
53+
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
54+
if ($returnType instanceof ThisType) {
55+
return new ActiveRecordObjectType($name);
56+
}
57+
58+
if ($returnType instanceof UnionType) {
3659
return TypeCombinator::union(
3760
new NullType(),
3861
new ActiveRecordObjectType($name)

tests/Yii/MyController.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ public function actionMy(): void
2424
$flag = $record['flag'];
2525
}
2626

27+
$record = MyActiveRecord::findBySql('');
28+
if ($record = $record->one()) {
29+
$flag = $record->flag;
30+
$flag = $record['flag'];
31+
}
32+
2733
$records = MyActiveRecord::find()->asArray()->where(['flag' => \Yii::$app->request->post('flag', true)])->all();
2834
foreach ($records as $record) {
2935
$flag = $record['flag'];

0 commit comments

Comments
 (0)