Passed
Push — trunk ( 95cc21...bc3fdd )
by Christian
12:22 queued 15s
created

RuleAreasFlagNotAllowedRule::processNode()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 46
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 23
c 1
b 0
f 0
nc 10
nop 2
dl 0
loc 46
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\DevOps\StaticAnalyze\PHPStan\Rules;
4
5
use PhpParser\Node;
6
use PhpParser\Node\Expr\MethodCall;
7
use PhpParser\Node\Identifier;
8
use PHPStan\Analyser\Scope;
0 ignored issues
show
Bug introduced by
The type PHPStan\Analyser\Scope was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use PHPStan\Reflection\ReflectionProvider;
0 ignored issues
show
Bug introduced by
The type PHPStan\Reflection\ReflectionProvider was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use PHPStan\Rules\Rule;
0 ignored issues
show
Bug introduced by
The type PHPStan\Rules\Rule was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use PHPStan\Rules\RuleError;
0 ignored issues
show
Bug introduced by
The type PHPStan\Rules\RuleError was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use PHPUnit\Framework\TestCase;
13
use Shopware\Core\Content\Rule\RuleDefinition;
14
use Shopware\Core\Framework\DataAbstractionLayer\Field\AssociationField;
15
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\RuleAreas;
16
17
/**
18
 * @implements Rule<MethodCall>
19
 *
20
 * @internal
21
 */
22
class RuleAreasFlagNotAllowedRule implements Rule
23
{
24
    private ReflectionProvider $reflectionProvider;
25
26
    public function __construct(ReflectionProvider $reflectionProvider)
27
    {
28
        $this->reflectionProvider = $reflectionProvider;
29
    }
30
31
    public function getNodeType(): string
32
    {
33
        return MethodCall::class;
34
    }
35
36
    /**
37
     * @param MethodCall $node
38
     *
39
     * @return array<array-key, RuleError|string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, RuleError|string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, RuleError|string>.
Loading history...
40
     */
41
    public function processNode(Node $node, Scope $scope): array
42
    {
43
        if ($this->isTestClass($scope)) {
44
            return [];
45
        }
46
47
        if (!$node->name instanceof Identifier) {
0 ignored issues
show
Bug introduced by
Accessing name on the interface PhpParser\Node suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
48
            return [];
49
        }
50
51
        if ((string) $node->name !== 'addFlags') {
52
            return [];
53
        }
54
55
        $class = $scope->getClassReflection();
56
57
        if ($class === null) {
58
            return [];
59
        }
60
61
        foreach ($node->getArgs() as $arg) {
0 ignored issues
show
Bug introduced by
The method getArgs() does not exist on PhpParser\Node. It seems like you code against a sub-type of PhpParser\Node such as PhpParser\Node\Expr\CallLike. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

61
        foreach ($node->/** @scrutinizer ignore-call */ getArgs() as $arg) {
Loading history...
62
            if ($this->resolveClassName($arg->value) !== RuleAreas::class) {
63
                continue;
64
            }
65
66
            if ($class->getName() !== RuleDefinition::class) {
67
                return [
68
                    'RuleAreas flag may only be added within the scope of RuleDefinition',
69
                ];
70
            }
71
72
            $fieldClassName = $this->resolveClassName($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...
73
74
            if (!$fieldClassName || !$this->reflectionProvider->hasClass($fieldClassName)) {
75
                continue;
76
            }
77
78
            $mockedClass = $this->reflectionProvider->getClass($fieldClassName);
79
            if (!$mockedClass->isSubclassOf(AssociationField::class)) {
80
                return [
81
                    'RuleAreas flag may only be added on instances of AssociationField',
82
                ];
83
            }
84
        }
85
86
        return [];
87
    }
88
89
    private function resolveClassName(Node $node): ?string
90
    {
91
        switch (true) {
92
            case $node instanceof Node\Expr\New_:
93
                if ($node->class instanceof Node\Name) {
94
                    return (string) $node->class;
95
                }
96
97
                return null;
98
            default:
99
                return null;
100
        }
101
    }
102
103
    private function isTestClass(Scope $node): bool
104
    {
105
        if ($node->getClassReflection() === null) {
106
            return false;
107
        }
108
109
        $namespace = $node->getClassReflection()->getName();
110
111
        if (!\str_contains($namespace, 'Shopware\\Tests\\Unit\\') && !\str_contains($namespace, 'Shopware\\Tests\\Migration\\')) {
112
            return false;
113
        }
114
115
        if ($node->getClassReflection()->getParentClass() === null) {
116
            return false;
117
        }
118
119
        return $node->getClassReflection()->getParentClass()->getName() === TestCase::class;
120
    }
121
}
122