Completed
Push — master ( b209b1...84fcc2 )
by Peter
05:42
created

YamlIndentDataFactory   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 295
Duplicated Lines 0 %

Test Coverage

Coverage 99.21%

Importance

Changes 7
Bugs 3 Features 0
Metric Value
wmc 50
eloc 125
c 7
b 3
f 0
dl 0
loc 295
ccs 125
cts 126
cp 0.9921
rs 8.4

4 Methods

Rating   Name   Duplication   Size   Complexity  
A belongLineToArray() 0 22 5
A getCorrectLineForArrayWithKeyAndValue() 0 35 4
D getCountOfParentsForLine() 0 82 23
D getRightFileLines() 0 111 18

How to fix   Complexity   

Complex Class

Complex classes like YamlIndentDataFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use YamlIndentDataFactory, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace YamlStandards\Model\YamlIndent;
6
7
use YamlStandards\Model\Component\YamlService;
8
9
class YamlIndentDataFactory
10
{
11
    /**
12
     * @param string[] $fileLines
13
     * @param int $key
14
     * @param int $countOfIndents
15
     * @param string $fileLine current checked line in loop
16
     * @param bool $isCommentLine
17
     * @return string
18
     */
19 9
    public function getRightFileLines(array $fileLines, int $key, int $countOfIndents, string $fileLine, bool $isCommentLine = false): string
20
    {
21 9
        if (YamlService::isLineComment($fileLines[$key])) {
22 6
            $key++;
23 6
            return $this->getRightFileLines($fileLines, $key, $countOfIndents, $fileLine, true);
24
        }
25
26 9
        $line = $fileLines[$key];
27 9
        $trimmedLine = trim($line);
28 9
        $countOfRowIndents = YamlService::rowIndentsOf($line);
29 9
        $explodedLine = explode(':', $line);
30
31
        // empty line
32 9
        if ($trimmedLine === '') {
33 9
            $fileRows = array_keys($fileLines);
34 9
            $lastFileRow = end($fileRows);
35
            /* set comment line indents by next non-empty line, e.g
36
                (empty line)
37
                # comment line
38
                (empty line)
39
                foo: bar
40
            */
41 9
            if ($isCommentLine && $lastFileRow !== $key) {
42 3
                $key++;
43 3
                return $this->getRightFileLines($fileLines, $key, $countOfIndents, $fileLine, true);
44
            }
45
46 9
            $correctIndents = YamlService::createCorrectIndentsByCountOfIndents(0);
47 9
            $trimmedFileLine = trim($fileLine);
48
49 9
            return $correctIndents . $trimmedFileLine;
50
        }
51
52
        // the highest parent
53 9
        if ($countOfRowIndents === 0) {
54
            // line is directive
55 9
            if (YamlService::hasLineThreeDashesOnStartOfLine($trimmedLine)) {
56 6
                $correctIndents = YamlService::createCorrectIndentsByCountOfIndents($countOfRowIndents);
57 6
                $trimmedFileLine = trim($fileLine);
58
59 6
                return $correctIndents . $trimmedFileLine;
60
            }
61
62
            // parent start as array, e.g. "- foo: bar"
63
            // skip comment line because we want result after this condition
64 9
            if ($isCommentLine === false && YamlService::isLineStartOfArrayWithKeyAndValue($trimmedLine)) {
65 2
                return $this->getCorrectLineForArrayWithKeyAndValue($line, $fileLines, $key, $countOfIndents, $fileLine, $isCommentLine);
66
            }
67
68 9
            $correctIndents = YamlService::createCorrectIndentsByCountOfIndents($countOfRowIndents);
69 9
            $trimmedFileLine = trim($fileLine);
70
71 9
            return $correctIndents . $trimmedFileLine;
72
        }
73
74
        // line start of array, e.g. "- foo: bar" or "- foo" or "- { foo: bar }"
75 9
        if (YamlService::isLineStartOfArrayWithKeyAndValue($trimmedLine)) {
76 9
            return $this->getCorrectLineForArrayWithKeyAndValue($line, $fileLines, $key, $countOfIndents, $fileLine, $isCommentLine);
77
        }
78
79
        // children of array, description over name of function
80 9
        if ($this->belongLineToArray($fileLines, $key)) {
81 6
            $countOfParents = $this->getCountOfParentsForLine($fileLines, $key);
82 6
            $correctIndents = YamlService::createCorrectIndentsByCountOfIndents($countOfParents * $countOfIndents);
83 6
            $trimmedFileLine = trim($fileLine);
84
85 6
            return $correctIndents . $trimmedFileLine;
86
        }
87
88
        // line without ':', e.g. array or string
89 9
        if (array_key_exists(1, $explodedLine) === false) {
90
            // is multidimensional array?
91 9
            if ($trimmedLine === '-') {
92 6
                $countOfParents = $this->getCountOfParentsForLine($fileLines, $key);
93
94 6
                $correctIndents = YamlService::createCorrectIndentsByCountOfIndents($countOfParents * $countOfIndents);
95 6
                $trimmedFileLine = trim($fileLine);
96
97 6
                return $correctIndents . $trimmedFileLine;
98
            }
99
100
            // is array or string?
101 6
            $countOfParents = $this->getCountOfParentsForLine($fileLines, $key);
102 6
            $correctIndents = YamlService::createCorrectIndentsByCountOfIndents($countOfParents * $countOfIndents);
103 6
            $trimmedFileLine = trim($fileLine);
104
105 6
            return $correctIndents . $trimmedFileLine;
106
        }
107
108 9
        $lineValue = $explodedLine[1];
109 9
        $trimmedLineValue = trim($lineValue);
110
111
        // parent, not comment line
112 9
        if ($isCommentLine === false && ($trimmedLineValue === '' || YamlService::isValueReuseVariable($trimmedLineValue))) {
113
            // fix situation when key is without value and is not parent, e.g.: "   foo:"
114 9
            $nextLine = array_key_exists($key + 1, $fileLines) ? $fileLines[$key + 1] : '';
115 9
            if (YamlService::rowIndentsOf($nextLine) > $countOfRowIndents) {
116 9
                $countOfParents = $this->getCountOfParentsForLine($fileLines, $key);
117
118 9
                $correctIndents = YamlService::createCorrectIndentsByCountOfIndents($countOfParents * $countOfIndents);
119 9
                $trimmedFileLine = trim($fileLine);
120
121 9
                return $correctIndents . $trimmedFileLine;
122
            }
123
        }
124
125 9
        $countOfParents = $this->getCountOfParentsForLine($fileLines, $key);
126 9
        $correctIndents = YamlService::createCorrectIndentsByCountOfIndents($countOfParents * $countOfIndents);
127 9
        $trimmedFileLine = trim($fileLine);
128
129 9
        return $correctIndents . $trimmedFileLine;
130
    }
131
132
    /**
133
     * Belong line to children of array, e.g.
134
     * - foo: bar
135
     *   baz: qux
136
     *   quux: quuz
137
     *   etc.: etc.
138
     *
139
     * @param string[] $fileLines
140
     * @param int $key
141
     * @return bool
142
     */
143 9
    private function belongLineToArray(array $fileLines, int $key): bool
144
    {
145 9
        while ($key >= 0) {
146 9
            $line = $fileLines[$key];
147 9
            $key--;
148 9
            $prevLine = $fileLines[$key];
149 9
            $trimmedPrevLine = trim($prevLine);
150
151 9
            if (YamlService::hasLineDashOnStartOfLine($trimmedPrevLine)) {
152 9
                $prevLine = preg_replace('/-/', ' ', $prevLine, 1); // replace '-' for space
153
            }
154
155 9
            if (YamlService::rowIndentsOf($prevLine) === YamlService::rowIndentsOf($line)) {
156 9
                if (YamlService::isLineStartOfArrayWithKeyAndValue($trimmedPrevLine)) {
157 9
                    return true;
158
                }
159
            } else {
160 9
                break;
161
            }
162
        }
163
164 9
        return false;
165
    }
166
167
    /**
168
     * line start of array, e.g. "- foo: bar" or "- foo" or "- { foo: bar }"
169
     *
170
     * @param string $line
171
     * @param string[] $fileLines
172
     * @param int $key
173
     * @param int $countOfIndents
174
     * @param string $fileLine current checked line in loop
175
     * @param bool $isCommentLine
176
     * @return string
177
     */
178 9
    private function getCorrectLineForArrayWithKeyAndValue(string $line, array $fileLines, int $key, int $countOfIndents, string $fileLine, bool $isCommentLine): string
179
    {
180 9
        $lineWithReplacedDashToSpace = preg_replace('/-/', ' ', $line, 1);
181 9
        $trimmedLineWithoutDash = trim($lineWithReplacedDashToSpace);
182
183 9
        $countOfParents = $this->getCountOfParentsForLine($fileLines, $key);
184 9
        $correctIndentsOnStartOfLine = YamlService::createCorrectIndentsByCountOfIndents($countOfParents * $countOfIndents);
185
186 9
        $trimmedFileLine = trim($fileLine);
187 9
        if ($isCommentLine) {
188 6
            return $correctIndentsOnStartOfLine . $trimmedFileLine;
189
        }
190
191
        // solution "- { foo: bar }"
192 9
        if (YamlService::isCurlyBracketInStartOfString($trimmedLineWithoutDash)) {
193 6
            $correctIndentsBetweenDashAndBracket = YamlService::createCorrectIndentsByCountOfIndents(1);
194
195 6
            return $correctIndentsOnStartOfLine . '-' . $correctIndentsBetweenDashAndBracket . $trimmedLineWithoutDash;
196
        }
197
198
        // solution "- foo" (single value of an array)
199 7
        if (YamlService::isKeyInStartOfString($trimmedLineWithoutDash) === false) {
200 4
            $correctIndentsBetweenDashAndKey = YamlService::createCorrectIndentsByCountOfIndents(1);
201
202 4
            return $correctIndentsOnStartOfLine . '-' . $correctIndentsBetweenDashAndKey . $trimmedLineWithoutDash;
203
        }
204
205
        /**
206
         * solution for one or more values in array
207
         * "- foo: bar"
208
         * "  baz: qux"
209
         */
210 6
        $correctIndentsBetweenDashAndKey = YamlService::createCorrectIndentsByCountOfIndents($countOfIndents - 1); // 1 space is dash, dash is as indent
211
212 6
        return $correctIndentsOnStartOfLine . '-' . $correctIndentsBetweenDashAndKey . $trimmedLineWithoutDash;
213
    }
214
215
    /**
216
     * Go back until deepest parent and count them
217
     *
218
     * @param string[] $fileLines
219
     * @param int $key
220
     * @return int
221
     */
222 9
    private function getCountOfParentsForLine(array $fileLines, int $key): int
223
    {
224 9
        $countOfParents = 0;
225 9
        $line = $fileLines[$key];
226 9
        $originalLine = $line;
227 9
        $countOfRowIndents = YamlService::rowIndentsOf($line);
228 9
        $trimmedLine = trim($line);
229 9
        $isArrayLine = YamlService::hasLineDashOnStartOfLine($trimmedLine);
230
231 9
        while ($key > 0) {
232 9
            $key--;
233 9
            $prevLine = $fileLines[$key];
234 9
            $trimmedPrevLine = trim($prevLine);
235 9
            $isPrevLineArrayLine = YamlService::hasLineDashOnStartOfLine($trimmedPrevLine);
236 9
            $countOfPrevRowIndents = YamlService::rowIndentsOf($prevLine);
237
238
            // ignore comment line and empty line
239 9
            if ($trimmedPrevLine === '' || YamlService::isLineComment($prevLine)) {
240 6
                continue;
241
            }
242
243
            if (/* is start of array in array, e.g.
244
                   foo:
245
                     - bar:
246
                       - 'any text'
247
                */
248 9
                ($isArrayLine && $countOfPrevRowIndents < $countOfRowIndents && $isPrevLineArrayLine) ||
249
                /* is start of array, e.g.
250
                   foo:
251
                     - bar: baz
252
                */
253 9
                ($isArrayLine && $countOfPrevRowIndents <= $countOfRowIndents && $isPrevLineArrayLine === false) ||
254
                /* is classic hierarchy, e.g.
255
                   foo:
256
                     bar: baz
257
                */
258 9
                ($isArrayLine === false && $countOfPrevRowIndents < $countOfRowIndents)
259
            ) {
260 9
                $line = $fileLines[$key];
261 9
                $countOfRowIndents = YamlService::rowIndentsOf($line);
262 9
                $trimmedLine = trim($line);
263 9
                $isArrayLine = YamlService::hasLineDashOnStartOfLine($trimmedLine);
264
265 9
                $countOfParents++;
266
267
                /* nested hierarchy in array fix, eg.
268
                   - foo:
269
                       nested: value
270
                     bar: baz
271
                */
272 9
                if ($isArrayLine && YamlService::isLineOpeningAnArray($trimmedLine) && YamlService::keyIndentsOf($originalLine) > YamlService::keyIndentsOf($line)) {
273 3
                    $countOfParents++;
274
                }
275
            }
276
277
            // if line has zero counts of indents then it's highest parent and should be ended
278 9
            if ($countOfRowIndents === 0) {
279
                // find parent if line belong to array, if it exists then add one parent to count of parents variable
280 9
                if (YamlService::isLineStartOfArrayWithKeyAndValue($trimmedLine)) {
281 2
                    while ($key > 0) {
282 2
                        $key--;
283 2
                        $prevLine = $fileLines[$key];
284 2
                        $trimmedPrevLine = trim($prevLine);
285 2
                        if ($trimmedPrevLine === '' || YamlService::isLineComment($prevLine)) {
286
                            continue;
287
                        }
288
289 2
                        $countOfRowIndents = YamlService::rowIndentsOf($prevLine);
290 2
                        $explodedPrevLine = explode(':', $prevLine);
291 2
                        if ($countOfRowIndents === 0 && array_key_exists(1, $explodedPrevLine) && trim($explodedPrevLine[1]) === '') {
292 2
                            $countOfParents++;
293
294 2
                            break;
295
                        }
296
                    }
297
                }
298
299 9
                break;
300
            }
301
        }
302
303 9
        return $countOfParents;
304
    }
305
}
306