Skip to content

Commit

Permalink
Create container dynamic mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
akondas committed Mar 6, 2018
1 parent 48eb542 commit 5167c2c
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 318 deletions.
16 changes: 13 additions & 3 deletions extension.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
services:
-
class: Proget\PHPStan\Yii2\Reflection\BaseYiiMethodsClassReflectionExtension
tags:
- phpstan.broker.methodsClassReflectionExtension
class: Proget\PHPStan\Yii2\Type\ContainerDynamicMethodReturnTypeExtension
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]

- Proget\PHPStan\Yii2\ServiceMap(%yii2.config_path%)
parameters:
ignoreErrors:
- '#Access to an undefined property yii\\db\\ActiveRecord#'
- '#Call to an undefined method yii\\db\\ActiveRecord#'
- '#Call to an undefined method yii\\console\\Request#'
- '#Access to an undefined property yii\\console\\Request#'
- '#Call to an undefined method yii\\console\\Response#'
- '#Access to an undefined property yii\\console\\Response#'
- '#Method yii\\db\\ActiveQuery\:\:with\(\) invoked with#'
68 changes: 0 additions & 68 deletions src/Reflection/BaseYiiMethodsClassReflectionExtension.php

This file was deleted.

109 changes: 0 additions & 109 deletions src/Reflection/YiiMethodReflection.php

This file was deleted.

79 changes: 0 additions & 79 deletions src/Reflection/YiiParameterReflection.php

This file was deleted.

44 changes: 44 additions & 0 deletions src/ServiceMap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);


namespace Proget\PHPStan\Yii2;


use PhpParser\Node;

final class ServiceMap
{
/**
* @var string[]
*/
private $services = [];

public function __construct(string $configPath)
{
if(!file_exists($configPath)) {
throw new \InvalidArgumentException(sprintf('Provided config path %s must exist', $configPath));
}
$config = require $configPath;
foreach ($config['container']['singletons'] as $id => $service) {
if(is_callable($service)) {
$reflection = new \ReflectionFunction($service);
if(!$reflection->hasReturnType()) {
throw new \RuntimeException(sprintf('Please provide return type for %s service closure', $id));
}
$this->services[$id] = $reflection->getReturnType()->getName();
} else {
$this->services[$id] = $service['class'] ?? $service[0]['class'];
}
}
}

public function getServiceClassFromNode(Node $node): ?string
{
if($node instanceof Node\Scalar\String_ && isset($this->services[$node->value])) {
return $this->services[$node->value];
}

return null;
}
}
51 changes: 51 additions & 0 deletions src/Type/ContainerDynamicMethodReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);


namespace Proget\PHPStan\Yii2\Type;


use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use Proget\PHPStan\Yii2\ServiceMap;

final class ContainerDynamicMethodReturnTypeExtension implements DynamicMethodReturnTypeExtension
{
/**
* @var ServiceMap
*/
private $serviceMap;

public function __construct(ServiceMap $serviceMap)
{
$this->serviceMap = $serviceMap;
}

public function getClass(): string
{
return 'yii\di\Container';
}

public function isMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === 'get';
}

public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
{
if(isset($methodCall->args[0]) && $methodCall->args[0] instanceof Arg) {
$serviceClass = $this->serviceMap->getServiceClassFromNode($methodCall->args[0]->value);
if($serviceClass !== null) {
return new ObjectType($serviceClass);
}
}

return $methodReflection->getReturnType();
}

}
Loading

0 comments on commit 5167c2c

Please sign in to comment.