Test Failed
Push — feature/add-phpstan-rules ( 26ac25 )
by Dave
10:33
created

__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 6
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GacelaPhpstan\Rules;
6
7
use Gacela\Framework\AbstractFacade;
8
use PhpParser\Node;
9
use PHPStan\Analyser\Scope;
10
use PHPStan\Rules\Rule;
11
use PHPStan\Rules\RuleErrorBuilder;
12
use PHPStan\Type\ObjectType;
13
14
/** @implements Rule<\PhpParser\Node\Expr\MethodCall> */
15
final class EnforceModuleBoundariesForMethodCallRule implements Rule
16
{
17
    private ModuleComparator $moduleComparator;
18
    private ExcludedNamespaceChecker $excludedNamespaceChecker;
19
20
    public function __construct(
21
        ModuleComparator $moduleComparator,
22
        ExcludedNamespaceChecker $excludedNamespaceChecker
23
    ) {
24
        $this->moduleComparator = $moduleComparator;
25
        $this->excludedNamespaceChecker = $excludedNamespaceChecker;
26
    }
27
28
    public function getNodeType(): string
29
    {
30
        return Node\Expr\MethodCall::class;
31
    }
32
33
    /**
34
     * @param \PhpParser\Node\Expr\MethodCall $node
35
     */
36
    public function processNode(Node $node, Scope $scope): array
37
    {
38
        // 1. Is the object we are calling a facade? If yes then exit.
39
        $type = $scope->getType($node->var);
0 ignored issues
show
Bug introduced by
Accessing var on the interface PhpParser\Node suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
40
        $facadeObjectType = new ObjectType(AbstractFacade::class);
41
        if ($facadeObjectType->isSuperTypeOf($type)->yes()) {
42
            return [];
43
        }
44
45
        // 2. Is this a call to code in the same module. If yes then exit.
46
        // 3. Or is this a call to code in an excluded namespace. If yes then exit.
47
        $namespaceOfCallingCode = $scope->getNamespace();
48
        foreach ($type->getReferencedClasses() as $referencedClass) {
49
            if ($this->moduleComparator->isSameModule($namespaceOfCallingCode, $referencedClass)) {
50
                return [];
51
            }
52
53
            if ($this->excludedNamespaceChecker->isExcludedNamespace($referencedClass)) {
54
                return [];
55
            }
56
        }
57
58
        // 4. Raise an error.
59
        return [
60
            RuleErrorBuilder::message('Method call to a different module is not allowed.')->build(),
61
        ];
62
    }
63
}
64