Skip to content

Commit 5167c2c

Browse files
committed
Create container dynamic mapping
1 parent 48eb542 commit 5167c2c

File tree

7 files changed

+108
-318
lines changed

7 files changed

+108
-318
lines changed

extension.neon

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
services:
22
-
3-
class: Proget\PHPStan\Yii2\Reflection\BaseYiiMethodsClassReflectionExtension
4-
tags:
5-
- phpstan.broker.methodsClassReflectionExtension
3+
class: Proget\PHPStan\Yii2\Type\ContainerDynamicMethodReturnTypeExtension
4+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
5+
6+
- Proget\PHPStan\Yii2\ServiceMap(%yii2.config_path%)
7+
parameters:
8+
ignoreErrors:
9+
- '#Access to an undefined property yii\\db\\ActiveRecord#'
10+
- '#Call to an undefined method yii\\db\\ActiveRecord#'
11+
- '#Call to an undefined method yii\\console\\Request#'
12+
- '#Access to an undefined property yii\\console\\Request#'
13+
- '#Call to an undefined method yii\\console\\Response#'
14+
- '#Access to an undefined property yii\\console\\Response#'
15+
- '#Method yii\\db\\ActiveQuery\:\:with\(\) invoked with#'

src/Reflection/BaseYiiMethodsClassReflectionExtension.php

Lines changed: 0 additions & 68 deletions
This file was deleted.

src/Reflection/YiiMethodReflection.php

Lines changed: 0 additions & 109 deletions
This file was deleted.

src/Reflection/YiiParameterReflection.php

Lines changed: 0 additions & 79 deletions
This file was deleted.

src/ServiceMap.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
5+
namespace Proget\PHPStan\Yii2;
6+
7+
8+
use PhpParser\Node;
9+
10+
final class ServiceMap
11+
{
12+
/**
13+
* @var string[]
14+
*/
15+
private $services = [];
16+
17+
public function __construct(string $configPath)
18+
{
19+
if(!file_exists($configPath)) {
20+
throw new \InvalidArgumentException(sprintf('Provided config path %s must exist', $configPath));
21+
}
22+
$config = require $configPath;
23+
foreach ($config['container']['singletons'] as $id => $service) {
24+
if(is_callable($service)) {
25+
$reflection = new \ReflectionFunction($service);
26+
if(!$reflection->hasReturnType()) {
27+
throw new \RuntimeException(sprintf('Please provide return type for %s service closure', $id));
28+
}
29+
$this->services[$id] = $reflection->getReturnType()->getName();
30+
} else {
31+
$this->services[$id] = $service['class'] ?? $service[0]['class'];
32+
}
33+
}
34+
}
35+
36+
public function getServiceClassFromNode(Node $node): ?string
37+
{
38+
if($node instanceof Node\Scalar\String_ && isset($this->services[$node->value])) {
39+
return $this->services[$node->value];
40+
}
41+
42+
return null;
43+
}
44+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
5+
namespace Proget\PHPStan\Yii2\Type;
6+
7+
8+
use PhpParser\Node\Arg;
9+
use PhpParser\Node\Expr\MethodCall;
10+
use PHPStan\Analyser\Scope;
11+
use PHPStan\Reflection\MethodReflection;
12+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
13+
use PHPStan\Type\ObjectType;
14+
use PHPStan\Type\Type;
15+
use Proget\PHPStan\Yii2\ServiceMap;
16+
17+
final class ContainerDynamicMethodReturnTypeExtension implements DynamicMethodReturnTypeExtension
18+
{
19+
/**
20+
* @var ServiceMap
21+
*/
22+
private $serviceMap;
23+
24+
public function __construct(ServiceMap $serviceMap)
25+
{
26+
$this->serviceMap = $serviceMap;
27+
}
28+
29+
public function getClass(): string
30+
{
31+
return 'yii\di\Container';
32+
}
33+
34+
public function isMethodSupported(MethodReflection $methodReflection): bool
35+
{
36+
return $methodReflection->getName() === 'get';
37+
}
38+
39+
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
40+
{
41+
if(isset($methodCall->args[0]) && $methodCall->args[0] instanceof Arg) {
42+
$serviceClass = $this->serviceMap->getServiceClassFromNode($methodCall->args[0]->value);
43+
if($serviceClass !== null) {
44+
return new ObjectType($serviceClass);
45+
}
46+
}
47+
48+
return $methodReflection->getReturnType();
49+
}
50+
51+
}

0 commit comments

Comments
 (0)