YamlParser::isStartOfArrayInArray()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 3
nc 3
nop 4
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace YamlStandards\Model\Component\Parser;
6
7
use YamlStandards\Model\Component\YamlService;
8
9
class YamlParser
10
{
11
    /**
12
     * Go back until deepest parent and count them
13
     *
14
     * @param string[] $yamlLines
15
     * @param int $key
16
     * @return int
17
     */
18 13
    public static function getCountOfParentsForLine(array $yamlLines, int $key): int
19
    {
20 13
        $countOfParents = 0;
21 13
        $line = $yamlLines[$key];
22 13
        $originalLine = $line;
23 13
        $countOfRowIndents = YamlService::rowIndentsOf($line);
24 13
        $trimmedLine = trim($line);
25 13
        $isArrayLine = YamlService::hasLineDashOnStartOfLine($trimmedLine);
26
27 13
        while ($key > 0) {
28 13
            $currentLine = $yamlLines[$key];
29 13
            $countOfCurrentRowIndents = YamlService::rowIndentsOf($currentLine);
30 13
            $key--;
31 13
            $prevLine = $yamlLines[$key];
32 13
            $trimmedPrevLine = trim($prevLine);
33 13
            $isPrevLineArrayLine = YamlService::hasLineDashOnStartOfLine($trimmedPrevLine);
34 13
            $countOfPrevRowIndents = YamlService::rowIndentsOf($prevLine);
35
36
            // ignore comment line and empty line
37 13
            if (YamlService::isLineBlank($prevLine) || YamlService::isLineComment($prevLine)) {
38 7
                continue;
39
            }
40
41 13
            if (self::isPrevLineNextParent($isArrayLine, $countOfPrevRowIndents, $countOfRowIndents, $isPrevLineArrayLine)) {
42 13
                $line = $yamlLines[$key];
43 13
                $lineWithoutDash = str_replace('-', ' ', $line);
44 13
                $countOfRowIndentsWithoutDash = YamlService::rowIndentsOf($lineWithoutDash);
45 13
                $hasPrevParentSameCountOfIndents = $countOfRowIndents === $countOfRowIndentsWithoutDash;
46 13
                $countOfRowIndents = YamlService::rowIndentsOf($line);
47 13
                $trimmedLine = trim($line);
48 13
                $isArrayLine = YamlService::hasLineDashOnStartOfLine($trimmedLine);
49
50
                /*
51
                 * array has array values at beginning and is not first element in array, e.g.
52
                 *  -  pathsToCheck:
53
                 *      - path/to/file
54
                 *
55
                 *
56
                 * subtract one parent only for line with same count of indents, e.g.
57
                 *  -   foo: bar
58
                 *      baz:
59
                 *         qux: quux ⬅
60
                 * but not for different count of indent, e.g.
61
                 *  -   foo:
62
                 *         bar:
63
                 *             baz: qux ⬅
64
                 */
65 13
                if ($isArrayLine &&
66 13
                    $countOfParents > 0 &&
67 13
                    YamlService::isLineOpeningAnArray($trimmedLine) &&
68
                    $hasPrevParentSameCountOfIndents
69
                ) {
70 4
                    $countOfParents--;
71
                }
72
73 13
                $countOfParents++;
74
75
                /**
76
                 * nested hierarchy in array fix, eg.
77
                 * - foo:
78
                 *     nested: value
79
                 *   bar: baz
80
                 */
81 13
                if ($isArrayLine && YamlService::isLineOpeningAnArray($trimmedLine) && YamlService::keyIndentsOf($originalLine) > YamlService::keyIndentsOf($line)) {
82 4
                    $countOfParents++;
83
                }
84
            }
85
86
            // if line has zero counts of indents then it's highest parent and should be ended
87 13
            if ($countOfRowIndents === 0) {
88
                /**
89
                 * find parent if line belong to array, if it exists then add one parent to count of parents variable, e.g.
90
                 * foo:
91
                 * - bar
92
                 */
93 13
                if (YamlService::isLineStartOfArrayWithKeyAndValue($trimmedLine)) {
94 4
                    while ($key >= 0) {
95 4
                        $prevLine = $yamlLines[$key];
96 4
                        $countOfPrevRowIndents = YamlService::rowIndentsOf($prevLine);
97 4
                        if (YamlService::isLineBlank($prevLine) || YamlService::isLineComment($prevLine)) {
98 3
                            $key--;
99 3
                            continue;
100
                        }
101
102
                        /**
103
                         * 'qux' is highest parent, so skip this, e.g.
104
                         * - foo:
105
                         *      bar: baz
106
                         * - qux:
107
                         *      - quux: quuz
108
                         */
109 4
                        if ($countOfPrevRowIndents > $countOfCurrentRowIndents) {
110 4
                            break;
111
                        }
112
113 4
                        if ($countOfPrevRowIndents === 0 &&
114 4
                            $countOfPrevRowIndents === $countOfCurrentRowIndents &&
115 4
                            YamlService::hasLineColon($prevLine) &&
116 4
                            YamlService::hasLineValue($prevLine) === false
117
                        ) {
118 3
                            $countOfParents++;
119
120 3
                            break;
121
                        }
122
123 4
                        $currentLine = $yamlLines[$key];
124 4
                        $countOfCurrentRowIndents = YamlService::rowIndentsOf($currentLine);
125 4
                        $key--;
126
                    }
127
                }
128
129 13
                break;
130
            }
131
        }
132
133 13
        return $countOfParents;
134
    }
135
136
    /**
137
     * @param string $pathToYamlFile
138
     * @return string[]
139
     */
140 6
    public static function getYamlParsedDataFromFile(string $pathToYamlFile): array
141
    {
142 6
        $fileContent = file_get_contents($pathToYamlFile);
143 6
        $fileContent = str_replace("\r", '', $fileContent); // remove carriage returns
144 6
        $yamlLines = explode("\n", $fileContent);
145 6
        $yamlLines = YamlService::mergeMultipleValueLinesTogether($yamlLines);
146 6
        $parentsData = [];
147
148 6
        foreach ($yamlLines as $key => $yamlLine) {
149 6
            $yamlParserLineData = new YamlParserLineData($yamlLines, $key);
150 6
            $yamlLine = YamlParserService::addBlankLineIndentsByHisParent($yamlLines, $key);
151 6
            $currentLineWithoutDash = str_replace('-', ' ', $yamlLine);
152 6
            $countOfCurrentRowIndents = YamlService::rowIndentsOf($currentLineWithoutDash);
153 6
            while ($key > 0) {
154
                /**
155
                 * don't associate blank line to previous parent too, e.g.:
156
                 *   -   foo: bar
157
                 * (blank line)⬅
158
                 *   -   baz: qux
159
                 */
160 6
                $nextLine = YamlService::getNextNonCommentAndNonBlankLine($yamlLines, $key);
161 6
                if ((YamlService::isLineBlank($yamlLines[$key]) || YamlService::isLineComment($yamlLines[$key])) &&
162 6
                    $nextLine !== null && YamlService::isLineStartOfArrayWithKeyAndValue(trim($nextLine)) &&
163 6
                    YamlService::rowIndentsOf($nextLine) === 0) {
164 2
                    break;
165
                }
166
167 6
                $key--;
168 6
                $prevLine = $yamlLines[$key];
169 6
                $prevLineWithoutDash = str_replace('-', ' ', $prevLine);
170 6
                $countOfPrevRowIndents = YamlService::rowIndentsOf($prevLineWithoutDash);
171
172
                // ignore comment line and empty line
173 6
                if (YamlService::isLineBlank($prevLine) || YamlService::isLineComment($prevLine)) {
174 6
                    continue;
175
                }
176
177 6
                if ($countOfPrevRowIndents <= $countOfCurrentRowIndents) {
178 6
                    if ($countOfPrevRowIndents < $countOfCurrentRowIndents) {
179 6
                        $yamlParserLineData->addLineKey($yamlLines, $key);
180
                    }
181 6
                    $yamlParserLineData->addArrayKeyWithValueToSeparatedArray($yamlLines, $key);
182
183 6
                    $countOfCurrentRowIndents = $countOfPrevRowIndents; // it's parent, so we want to only higher from him
184
                }
185
186 6
                if ($countOfCurrentRowIndents === 0) {
187 6
                    break;
188
                }
189
            }
190
191 6
            $parentsData[] = $yamlParserLineData->getPathToLineGradually();
192
        }
193
194 6
        $allParentsData = array_merge_recursive(...$parentsData); // add all data to one big array
195
196 6
        return $allParentsData;
197
    }
198
199
    /**
200
     * @param bool $isArrayLine
201
     * @param int $countOfPrevRowIndents
202
     * @param int $countOfRowIndents
203
     * @param bool $isPrevLineArrayLine
204
     * @return bool
205
     */
206 14
    private static function isPrevLineNextParent(bool $isArrayLine, int $countOfPrevRowIndents, int $countOfRowIndents, bool $isPrevLineArrayLine): bool
207
    {
208 14
        return self::isClassicHierarchy($isArrayLine, $countOfPrevRowIndents, $countOfRowIndents) ||
209 14
            self::isStartOfArray($isArrayLine, $countOfPrevRowIndents, $countOfRowIndents, $isPrevLineArrayLine) ||
210 14
            self::isStartOfArrayInArray($isArrayLine, $countOfPrevRowIndents, $countOfRowIndents, $isPrevLineArrayLine);
211
    }
212
213
    /**
214
     * @param bool $isArrayLine
215
     * @param int $countOfPrevRowIndents
216
     * @param int $countOfRowIndents
217
     * @return bool
218
     *
219
     * @example
220
     * foo:
221
     *     bar: baz
222
     */
223 15
    private static function isClassicHierarchy(bool $isArrayLine, int $countOfPrevRowIndents, int $countOfRowIndents): bool
224
    {
225 15
        return $isArrayLine === false && $countOfPrevRowIndents < $countOfRowIndents;
226
    }
227
228
    /**
229
     * @param bool $isArrayLine
230
     * @param int $countOfPrevRowIndents
231
     * @param int $countOfRowIndents
232
     * @param bool $isPrevLineArrayLine
233
     * @return bool
234
     *
235
     * @example
236
     * foo:
237
     *     - bar: baz
238
     */
239 15
    private static function isStartOfArray(bool $isArrayLine, int $countOfPrevRowIndents, int $countOfRowIndents, bool $isPrevLineArrayLine): bool
240
    {
241 15
        return $isArrayLine && $countOfPrevRowIndents <= $countOfRowIndents && $isPrevLineArrayLine === false;
242
    }
243
244
    /**
245
     * @param bool $isArrayLine
246
     * @param int $countOfPrevRowIndents
247
     * @param int $countOfRowIndents
248
     * @param bool $isPrevLineArrayLine
249
     * @return bool
250
     *
251
     * @example
252
     * foo:
253
     *     - bar:
254
     *         - 'any text'
255
     */
256 15
    private static function isStartOfArrayInArray(bool $isArrayLine, int $countOfPrevRowIndents, int $countOfRowIndents, bool $isPrevLineArrayLine): bool
257
    {
258 15
        return $isArrayLine && $countOfPrevRowIndents < $countOfRowIndents && $isPrevLineArrayLine;
259
    }
260
}
261