PHPMixin::parse()   C
last analyzed

Complexity

Conditions 16
Paths 29

Size

Total Lines 61
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 45
CRAP Score 16

Importance

Changes 0
Metric Value
eloc 44
dl 0
loc 61
ccs 45
cts 45
cp 1
rs 5.5666
c 0
b 0
f 0
cc 16
nc 29
nop 1
crap 16

How to fix   Long Method    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
/**
8
 * PHPMixin provides the ability to safely inject nodes into PHP source code using given macro function.
9
 */
10
final class PHPMixin
11
{
12
    private array $blocks = [];
13
14 14
    public function __construct(
15
        private readonly array $tokens,
16
        string $func,
17
    ) {
18 14
        $this->parse($func);
19
    }
20
21 14
    public function compile(): string
22
    {
23 14
        $replace = [];
24
25 14
        foreach ($this->blocks as $block) {
26 14
            for ($i = $block['start']; $i <= $block['end']; $i++) {
27 14
                $replace[$i] = '';
28
            }
29
30 14
            $replace[$block['start']] = $block['value'];
31
        }
32
33 14
        $result = '';
34 14
        foreach ($this->tokens as $position => $token) {
35 14
            if (\array_key_exists($position, $replace)) {
36 14
                $result .= $replace[$position];
37 14
                continue;
38
            }
39
40 14
            if (\is_string($token)) {
41 14
                $result .= $token;
42 14
                continue;
43
            }
44
45 14
            $result .= $token[1];
46
        }
47
48 14
        return $result;
49
    }
50
51
    /**
52
     * Compiles the PHP blocks (with replacements) but excludes the php open, close tag and echo function.
53
     */
54 1
    public function trimBody(): string
55
    {
56 1
        $replace = [];
57
58 1
        foreach ($this->blocks as $block) {
59
            for ($i = $block['start']; $i <= $block['end']; ++$i) {
60
                $replace[$i] = '';
61
            }
62
63
            $replace[$block['start']] = $block['value'];
64
        }
65
66 1
        $result = '';
67 1
        foreach ($this->tokens as $position => $token) {
68 1
            if (\array_key_exists($position, $replace)) {
69
                $result .= $replace[$position];
70
                continue;
71
            }
72
73 1
            if (\is_string($token)) {
74
                $result .= $token;
75
                continue;
76
            }
77
78 1
            if (\in_array($token[0], [T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG, T_ECHO])) {
79 1
                continue;
80
            }
81
82 1
            $result .= $token[1];
83
        }
84
85 1
        return \rtrim(\trim($result), ';');
86
    }
87
88
    /**
89
     * Get macros detected in PHP code and their default values (if any).
90
     */
91 1
    public function getBlocks(): array
92
    {
93 1
        $result = [];
94 1
        foreach ($this->blocks as $name => $macro) {
95 1
            $result[$name] = $macro['value'];
96
        }
97
98 1
        return $result;
99
    }
100
101 14
    public function has(string $block): bool
102
    {
103 14
        return isset($this->blocks[$block]);
104
    }
105
106 12
    public function set(string $block, string $value): void
107
    {
108 12
        if (!isset($this->blocks[$block])) {
109
            return;
110
        }
111
112 12
        $this->blocks[$block]['value'] = $value;
113
    }
114
115 14
    private function parse(string $func): void
116
    {
117 14
        $level = 0;
118 14
        $start = $name = $value = null;
119 14
        foreach ($this->tokens as $position => $token) {
120 14
            if (!\is_array($token)) {
121 14
                $token = [$token, $token, 0];
122
            }
123
124 14
            switch ($token[0]) {
125 14
                case '(':
126 14
                    if ($start !== null) {
127 14
                        $level++;
128 14
                        $value .= $token[1];
129
                    }
130 14
                    break;
131 14
                case ')':
132 14
                    if ($start === null) {
133 14
                        break;
134
                    }
135
136 14
                    $level--;
137 14
                    $value .= $token[1];
138 14
                    if ($level === 0) {
139 14
                        $this->blocks[$name] = [
140 14
                            'start' => $start,
141 14
                            'value' => \trim($value),
142 14
                            'end'   => $position,
143 14
                        ];
144
145
                        // reset
146 14
                        $start = $name = $value = null;
147
                    }
148 14
                    break;
149 14
                case T_STRING:
150 14
                    if ($token[1] === $func) {
151 14
                        $start = $position;
152 14
                        $value = $token[1];
153 14
                        break;
154
                    }
155
156 11
                    if ($start !== null) {
157 1
                        $value .= $token[1];
158
                    }
159 11
                    break;
160 14
                case T_CONSTANT_ENCAPSED_STRING:
161 14
                    if ($start === null) {
162 14
                        break;
163
                    }
164
165 14
                    if ($name === null) {
166 14
                        $name = \stripcslashes(\substr((string) $token[1], 1, -1));
167
                    }
168 14
                    $value .= $token[1];
169 14
                    break;
170 14
                case ',':
171 12
                    $value .= $token[1];
172 12
                    break;
173
                default:
174 14
                    if ($start !== null) {
175 6
                        $value .= $token[1];
176
                    }
177
            }
178
        }
179
    }
180
}
181