Passed
Push — master ( 193bee...a6d59a )
by butschster
07:51 queued 01:37
created

InjectPHP::enterNode()   B

Complexity

Conditions 10
Paths 17

Size

Total Lines 47
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 10.0658

Importance

Changes 0
Metric Value
eloc 25
c 0
b 0
f 0
dl 0
loc 47
ccs 21
cts 23
cp 0.913
rs 7.6666
cc 10
nc 17
nop 2
crap 10.0658

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
2
3
declare(strict_types=1);
4
5
namespace Spiral\Stempler\Transform\Merge\Inject;
6
7
use Spiral\Stempler\Node\Block;
8
use Spiral\Stempler\Node\Dynamic\Output;
9
use Spiral\Stempler\Node\Mixin;
10
use Spiral\Stempler\Node\PHP;
11
use Spiral\Stempler\Node\Raw;
12
use Spiral\Stempler\Transform\BlockClaims;
13
use Spiral\Stempler\Transform\QuotedValue;
14
use Spiral\Stempler\VisitorContext;
15
use Spiral\Stempler\VisitorInterface;
16
17
/**
18
 * Injects block values into PHP source code using marco function.
19
 */
20
final class InjectPHP implements VisitorInterface
21
{
22
    // php marcos to inject values into
23
    private const PHP_MACRO_FUNCTION = 'inject';
24
25
    private const PHP_MARCO_EXISTS_FUNCTION = 'injected';
26
27 45
    public function __construct(
28
        private readonly BlockClaims $blocks
29
    ) {
30
    }
31
32 45
    public function enterNode(mixed $node, VisitorContext $ctx): mixed
33
    {
34
        if (
35
            !$node instanceof PHP
36
            || (
37 15
                !\str_contains($node->content, self::PHP_MACRO_FUNCTION)
38 45
                && !\str_contains($node->content, self::PHP_MARCO_EXISTS_FUNCTION)
39
            )
40
        ) {
41 45
            return null;
42
        }
43
44 14
        $php = new PHPMixin($node->tokens, self::PHP_MACRO_FUNCTION);
45 14
        foreach ($this->blocks->getNames() as $name) {
46 14
            $block = $this->blocks->get($name);
47
48 14
            if ($this->isReference($block)) {
49
                // resolved on later stage
50
                continue;
51
            }
52
53 14
            if ($php->has($name)) {
54 10
                $php->set($name, $this->trimPHP($this->blocks->claim($name)));
55
            }
56
        }
57
58 14
        $node->content = $php->compile();
59 14
        $node->tokens = \token_get_all($node->content);
60
61 14
        $exists = new PHPMixin($node->tokens, self::PHP_MARCO_EXISTS_FUNCTION);
62 14
        foreach ($this->blocks->getNames() as $name) {
63 14
            $block = $this->blocks->get($name);
64
65 14
            if ($this->isReference($block)) {
66
                // resolved on later stage
67
                continue;
68
            }
69
70 14
            if ($exists->has($name)) {
71 1
                $exists->set($name, 'true');
72
            }
73
        }
74
75 14
        $node->content = $exists->compile();
76 14
        $node->tokens = \token_get_all($node->content);
77
78 14
        return null;
79
    }
80
81 45
    public function leaveNode(mixed $node, VisitorContext $ctx): mixed
82
    {
83 45
        return null;
84
    }
85
86 14
    private function isReference(mixed $node): bool
87
    {
88
        switch (true) {
89 14
            case \is_array($node):
90 12
                foreach ($node as $child) {
91 12
                    if ($this->isReference($child)) {
92
                        return true;
93
                    }
94
                }
95
96 12
                return false;
97
98 14
            case $node instanceof QuotedValue:
99 12
                return $this->isReference($node->getValue());
100
101 14
            case $node instanceof Mixin:
102 12
                foreach ($node->nodes as $child) {
103 12
                    if ($this->isReference($child)) {
104
                        return true;
105
                    }
106
                }
107
108 12
                return false;
109
110 14
            case $node instanceof Block:
111
                return true;
112
        }
113
114 14
        return false;
115
    }
116
117 10
    private function trimPHP(mixed $node): string
118
    {
119
        switch (true) {
120 10
            case \is_array($node):
121 10
                $result = [];
122 10
                foreach ($node as $child) {
123 10
                    $result[] = $this->trimPHP($child);
124
                }
125
126 10
                return \implode('.', $result);
127
128 10
            case $node instanceof Mixin:
129 9
                $result = [];
130 9
                foreach ($node->nodes as $child) {
131 9
                    $result[] = $this->trimPHP($child);
132
                }
133
134 9
                return \implode('.', $result);
135
136 10
            case $node instanceof Raw:
137 5
                return $this->exportValue($node);
138
139 9
            case $node instanceof Output:
140 7
                return \trim($node->body);
0 ignored issues
show
Bug introduced by
It seems like $node->body can also be of type null; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

140
                return \trim(/** @scrutinizer ignore-type */ $node->body);
Loading history...
141
142 9
            case $node instanceof PHP:
143 2
                return $node->getContext()?->getValue(PHP::ORIGINAL_BODY)
144 2
                    ?? (new PHPMixin($node->tokens, self::PHP_MACRO_FUNCTION))->trimBody();
145
146 9
            case $node instanceof QuotedValue:
147 9
                return $this->trimPHP($node->trimValue());
148
        }
149
150
        return 'null';
151
    }
152
153 5
    private function exportValue(Raw $node): string
154
    {
155 5
        $value = $node->content;
156
        return match (true) {
157 5
            \strtolower($value) === 'true' => 'true',
158 5
            \strtolower($value) === 'false' => 'false',
159 5
            \is_float($value) || \is_numeric($value) => (string) $value,
160 5
            default => \var_export($node->content, true),
161
        };
162
    }
163
}
164