|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
|
4
|
|
|
|
|
5
|
|
|
namespace YamlStandards\Model\YamlAlphabetical; |
|
6
|
|
|
|
|
7
|
|
|
use YamlStandards\Model\Component\Parser\YamlParser; |
|
8
|
|
|
use YamlStandards\Model\Component\Parser\YamlParserLineData; |
|
9
|
|
|
use YamlStandards\Model\Component\YamlService; |
|
10
|
|
|
|
|
11
|
|
|
class YamlAlphabeticalDataFactory |
|
12
|
|
|
{ |
|
13
|
|
|
public const REGEX_KEY_COMMON_LINE_WITH_NUMBER_AT_END = '/' . YamlParserLineData::KEY_COMMON_LINE . '\d+$/'; |
|
14
|
|
|
public const REGEX_KEY_COMMENT_OR_EMPTY_LINE_WITH_NUMBER_AT_END = '/' . YamlParserLineData::KEY_COMMENT_OR_EMPTY_LINE . '\d+$/'; |
|
15
|
|
|
public const REGEX_KEY_DASH_WITH_NUMBER_AT_END = '/' . YamlParserLineData::KEY_DASH . '\d+$/'; |
|
16
|
|
|
public const REGEX_KEY_EMPTY_ARRAY_WITH_NUMBER_AT_END = '/' . YamlParserLineData::KEY_EMPTY_ARRAY . '\d+$/'; |
|
17
|
|
|
public const REGEX_KEY_ARRAY_WITHOUT_KEY_WITH_NUMBER_AT_END = '/^' . YamlParserLineData::KEY_ARRAY_WITHOUT_KEY . '\d+/'; |
|
18
|
|
|
public const REGEX_KEY_CURLY_BRACKETS_WITH_NUMBER_AT_END = '/' . YamlParserLineData::KEY_CURLY_BRACKETS . '\d+$/'; |
|
19
|
|
|
|
|
20
|
|
|
public const REGEX_VALUE_EMPTY_LINE = '/' . YamlParserLineData::EMPTY_LINE_DEFAULT_VALUE . '$/'; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* @var int |
|
24
|
|
|
*/ |
|
25
|
|
|
private static $index; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* @param string $pathToYamlFile |
|
29
|
|
|
* @param int $depth |
|
30
|
|
|
* @return string[] |
|
31
|
|
|
*/ |
|
32
|
6 |
|
public static function getCorrectYamlLines(string $pathToYamlFile, int $depth): array |
|
33
|
|
|
{ |
|
34
|
6 |
|
self::$index = 0; // start from 0 in every file |
|
35
|
|
|
|
|
36
|
6 |
|
$yamlArrayData = YamlParser::getYamlParsedDataFromFile($pathToYamlFile); |
|
37
|
6 |
|
$yamlArrayDataSorted = self::sortArray($yamlArrayData, $depth); |
|
38
|
|
|
|
|
39
|
6 |
|
return self::createRightSortedYamlLines($yamlArrayDataSorted); |
|
|
|
|
|
|
40
|
|
|
} |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* @param string[] $yamlArrayData |
|
44
|
|
|
* @param int $depth |
|
45
|
|
|
* @return string[] |
|
46
|
|
|
*/ |
|
47
|
6 |
|
private static function sortArray(array $yamlArrayData, int $depth): array |
|
48
|
|
|
{ |
|
49
|
6 |
|
if ($depth > 0) { |
|
50
|
6 |
|
$yamlArrayData = self::sortArrayKeyWithUnderscoresAsFirst($yamlArrayData); |
|
51
|
|
|
|
|
52
|
6 |
|
if ($depth > 1) { |
|
53
|
6 |
|
foreach ($yamlArrayData as $key => $value) { |
|
54
|
6 |
|
if (is_array($value)) { |
|
55
|
6 |
|
$yamlArrayData[$key] = self::recursiveKsort($value, $depth); |
|
56
|
|
|
} |
|
57
|
|
|
} |
|
58
|
|
|
} |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
6 |
|
return $yamlArrayData; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* @param string[] $yamlArrayData |
|
66
|
|
|
* @param int $depth |
|
67
|
|
|
* @param int $currentDepth |
|
68
|
|
|
* @return string[] |
|
69
|
|
|
*/ |
|
70
|
6 |
|
private static function recursiveKsort(array $yamlArrayData, int $depth, int $currentDepth = 1): array |
|
71
|
|
|
{ |
|
72
|
6 |
|
$yamlArrayData = self::sortArrayKeyWithUnderscoresAsFirst($yamlArrayData); |
|
73
|
6 |
|
foreach ($yamlArrayData as $key => $value) { |
|
74
|
6 |
|
if (is_array($value)) { |
|
75
|
6 |
|
if ($currentDepth <= $depth) { |
|
76
|
6 |
|
$yamlArrayData[$key] = self::recursiveKsort($value, $depth, $currentDepth + 1); |
|
77
|
|
|
} |
|
78
|
|
|
} |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
6 |
|
return $yamlArrayData; |
|
82
|
|
|
} |
|
83
|
|
|
|
|
84
|
|
|
/** |
|
85
|
|
|
* @param string[] $yamlArrayData |
|
86
|
|
|
* @return string[]|string[][] |
|
87
|
|
|
*/ |
|
88
|
6 |
|
private static function sortArrayKeyWithUnderscoresAsFirst(array $yamlArrayData): array |
|
89
|
|
|
{ |
|
90
|
6 |
|
$arrayWithUnderscoreKeys = array_filter($yamlArrayData, [YamlService::class, 'hasArrayKeyUnderscoreAsFirstCharacter'], ARRAY_FILTER_USE_KEY); |
|
91
|
6 |
|
$arrayWithOtherKeys = array_filter($yamlArrayData, [YamlService::class, 'hasNotArrayKeyUnderscoreAsFirstCharacter'], ARRAY_FILTER_USE_KEY); |
|
92
|
|
|
|
|
93
|
6 |
|
uksort($arrayWithUnderscoreKeys, ['self', 'sortArrayAlphabetical']); |
|
94
|
6 |
|
uksort($arrayWithOtherKeys, ['self', 'sortArrayAlphabetical']); |
|
95
|
|
|
|
|
96
|
6 |
|
return array_merge($arrayWithUnderscoreKeys, $arrayWithOtherKeys); |
|
97
|
|
|
} |
|
98
|
|
|
|
|
99
|
|
|
/** |
|
100
|
|
|
* @param string $key1 |
|
101
|
|
|
* @param string $key2 |
|
102
|
|
|
* @return int |
|
103
|
|
|
*/ |
|
104
|
6 |
|
private static function sortArrayAlphabetical(string $key1, string $key2): int |
|
105
|
|
|
{ |
|
106
|
|
|
// remove added text for empty line and comment line |
|
107
|
6 |
|
$key1WithoutNumberAtEnd = preg_replace(self::REGEX_KEY_COMMENT_OR_EMPTY_LINE_WITH_NUMBER_AT_END, '', $key1); |
|
108
|
6 |
|
$key2WithoutNumberAtEnd = preg_replace(self::REGEX_KEY_COMMENT_OR_EMPTY_LINE_WITH_NUMBER_AT_END, '', $key2); |
|
109
|
|
|
|
|
110
|
|
|
// add key number to end for fix situation when keys are same |
|
111
|
6 |
|
preg_match('/\d+$/', $key1WithoutNumberAtEnd, $key1NumberAtEnd); |
|
112
|
6 |
|
preg_match('/\d+$/', $key2WithoutNumberAtEnd, $key2NumberAtEnd); |
|
113
|
6 |
|
$key1NumberAtEnd = count($key1NumberAtEnd) === 0 ? 0 : reset($key1NumberAtEnd); |
|
114
|
6 |
|
$key2NumberAtEnd = count($key2NumberAtEnd) === 0 ? 0 : reset($key2NumberAtEnd); |
|
115
|
|
|
|
|
116
|
6 |
|
$key1WithoutNumberAtEnd = preg_match(self::REGEX_KEY_COMMON_LINE_WITH_NUMBER_AT_END, $key1WithoutNumberAtEnd) === 0 ? $key1WithoutNumberAtEnd : preg_replace(self::REGEX_KEY_COMMON_LINE_WITH_NUMBER_AT_END, '', $key1WithoutNumberAtEnd); |
|
117
|
6 |
|
$key1WithoutNumberAtEnd = preg_match(self::REGEX_KEY_ARRAY_WITHOUT_KEY_WITH_NUMBER_AT_END, $key1WithoutNumberAtEnd) === 0 ? $key1WithoutNumberAtEnd : preg_replace(self::REGEX_KEY_ARRAY_WITHOUT_KEY_WITH_NUMBER_AT_END, '', $key1WithoutNumberAtEnd); |
|
118
|
|
|
|
|
119
|
6 |
|
$key2WithoutNumberAtEnd = preg_match(self::REGEX_KEY_COMMON_LINE_WITH_NUMBER_AT_END, $key2WithoutNumberAtEnd) === 0 ? $key2WithoutNumberAtEnd : preg_replace(self::REGEX_KEY_COMMON_LINE_WITH_NUMBER_AT_END, '', $key2WithoutNumberAtEnd); |
|
120
|
6 |
|
$key2WithoutNumberAtEnd = preg_match(self::REGEX_KEY_ARRAY_WITHOUT_KEY_WITH_NUMBER_AT_END, $key2WithoutNumberAtEnd) === 0 ? $key2WithoutNumberAtEnd : preg_replace(self::REGEX_KEY_ARRAY_WITHOUT_KEY_WITH_NUMBER_AT_END, '', $key2WithoutNumberAtEnd); |
|
121
|
|
|
|
|
122
|
|
|
/* |
|
123
|
|
|
* add exclamation mark (!) to penultimate position in string for fix order for "dot" key scenario, e.g: |
|
124
|
|
|
* foo.bar: |
|
125
|
|
|
* foo.bar.baz: |
|
126
|
|
|
* ":" is in alphabetical higher as ".", https://s2799303.files.wordpress.com/2013/08/ascii-codes-table1.jpg |
|
127
|
|
|
*/ |
|
128
|
6 |
|
$key1WithoutNumberAtEnd = substr_replace($key1WithoutNumberAtEnd, '!', -1, 0); |
|
129
|
6 |
|
$key2WithoutNumberAtEnd = substr_replace($key2WithoutNumberAtEnd, '!', -1, 0); |
|
130
|
|
|
|
|
131
|
6 |
|
$key1WithoutNumberAtEnd .= $key1NumberAtEnd; |
|
132
|
6 |
|
$key2WithoutNumberAtEnd .= $key2NumberAtEnd; |
|
133
|
|
|
|
|
134
|
6 |
|
if ($key1WithoutNumberAtEnd === $key2WithoutNumberAtEnd) { |
|
135
|
5 |
|
return strnatcmp(trim($key2), trim($key1)); |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
6 |
|
return strnatcmp(trim($key1WithoutNumberAtEnd), trim($key2WithoutNumberAtEnd)); |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
/** |
|
142
|
|
|
* @param string[]|string[][] $sortedYamlData |
|
143
|
|
|
* @return string[] |
|
144
|
|
|
*/ |
|
145
|
6 |
|
private static function createRightSortedYamlLines(array $sortedYamlData): array |
|
146
|
|
|
{ |
|
147
|
6 |
|
$rightSortedYamlLines = []; |
|
148
|
|
|
|
|
149
|
6 |
|
foreach ($sortedYamlData as $yamlKey => $yamlValue) { |
|
150
|
6 |
|
if (is_array($yamlValue) === false && ($yamlValue === YamlParserLineData::EMPTY_LINE_DEFAULT_VALUE || YamlService::isLineComment($yamlValue))) { |
|
|
|
|
|
|
151
|
6 |
|
$rightSortedYamlLines[] = preg_match(self::REGEX_VALUE_EMPTY_LINE, $yamlValue) === 0 ? $yamlValue : preg_replace(self::REGEX_VALUE_EMPTY_LINE, '', $yamlValue); |
|
|
|
|
|
|
152
|
|
|
|
|
153
|
6 |
|
continue; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
6 |
|
$yamlKey = is_int($yamlKey) ? (string)$yamlKey : $yamlKey; |
|
157
|
6 |
|
if (preg_match(self::REGEX_KEY_COMMENT_OR_EMPTY_LINE_WITH_NUMBER_AT_END, $yamlKey) === 0 && |
|
158
|
6 |
|
preg_match(self::REGEX_KEY_EMPTY_ARRAY_WITH_NUMBER_AT_END, $yamlKey) === 0 |
|
159
|
|
|
) { |
|
160
|
6 |
|
$key = preg_match(self::REGEX_KEY_COMMON_LINE_WITH_NUMBER_AT_END, $yamlKey) === 0 ? $yamlKey : preg_replace(self::REGEX_KEY_COMMON_LINE_WITH_NUMBER_AT_END, '', $yamlKey); |
|
161
|
6 |
|
$key = preg_match(self::REGEX_KEY_DASH_WITH_NUMBER_AT_END, $key) === 0 ? $key : preg_replace(self::REGEX_KEY_DASH_WITH_NUMBER_AT_END, '-', $key); |
|
162
|
6 |
|
$key = preg_match(self::REGEX_KEY_CURLY_BRACKETS_WITH_NUMBER_AT_END, $key) === 0 ? $key : preg_replace(self::REGEX_KEY_CURLY_BRACKETS_WITH_NUMBER_AT_END, '', $key); |
|
163
|
6 |
|
$key = preg_match(self::REGEX_KEY_ARRAY_WITHOUT_KEY_WITH_NUMBER_AT_END, $key) === 0 ? $key : preg_replace(self::REGEX_KEY_ARRAY_WITHOUT_KEY_WITH_NUMBER_AT_END, '', $key); |
|
164
|
6 |
|
$value = is_array($yamlValue) ? '' : $yamlValue; |
|
165
|
6 |
|
$rightSortedYamlLines[] = $key . $value; |
|
166
|
|
|
|
|
167
|
6 |
|
self::$index++; |
|
168
|
|
|
} |
|
169
|
|
|
|
|
170
|
6 |
|
if (is_array($yamlValue)) { |
|
171
|
6 |
|
$result = self::createRightSortedYamlLines($yamlValue); |
|
172
|
6 |
|
$rightSortedYamlLines = array_merge($rightSortedYamlLines, $result); |
|
173
|
|
|
} |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
6 |
|
return $rightSortedYamlLines; |
|
|
|
|
|
|
177
|
|
|
} |
|
178
|
|
|
} |
|
179
|
|
|
|