Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
89 / 89 |
|
100.00% |
11 / 11 |
CRAP | |
100.00% |
1 / 1 |
| ArraySimple | |
100.00% |
89 / 89 |
|
100.00% |
11 / 11 |
33 | |
100.00% |
1 / 1 |
| extractKeys | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| revert | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
4 | |||
| convert | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
| value | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
5 | |||
| keys | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getKeys | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
5 | |||
| addChild | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
| getParentKey | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
| getChildKey | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
| files | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
5 | |||
| filesWalker | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
| 1 | <?php declare(strict_types=1); |
| 2 | /* |
| 3 | * This file is part of Aplus Framework Helpers Library. |
| 4 | * |
| 5 | * (c) Natan Felles <natanfelles@gmail.com> |
| 6 | * |
| 7 | * For the full copyright and license information, please view the LICENSE |
| 8 | * file that was distributed with this source code. |
| 9 | */ |
| 10 | namespace Framework\Helpers; |
| 11 | |
| 12 | use JetBrains\PhpStorm\Pure; |
| 13 | |
| 14 | /** |
| 15 | * Class ArraySimple. |
| 16 | * |
| 17 | * Contains methods to work with PHP arrays using "simple keys" (strings with |
| 18 | * square brackets). |
| 19 | * |
| 20 | * Simple key format example: `parent[child1][child2]`. |
| 21 | * |
| 22 | * `user[country][state]` gets 'rs' in |
| 23 | * `array('user' => ['country' => ['state' => 'rs']])` |
| 24 | * |
| 25 | * @see https://www.php.net/manual/en/language.types.array.php |
| 26 | * |
| 27 | * @package helpers |
| 28 | */ |
| 29 | class ArraySimple |
| 30 | { |
| 31 | /** |
| 32 | * @param string $simpleKey |
| 33 | * |
| 34 | * @return array<int,string> |
| 35 | */ |
| 36 | protected static function extractKeys(string $simpleKey) : array |
| 37 | { |
| 38 | \preg_match_all('#\[(.*?)\]#', $simpleKey, $matches); |
| 39 | return $matches[1] ?? []; |
| 40 | } |
| 41 | |
| 42 | /** |
| 43 | * Reverts an associative array of simple keys to an native array. |
| 44 | * |
| 45 | * @param array<mixed> $arraySimple An array with simple keys |
| 46 | * |
| 47 | * @return array<string,mixed> An array with their corresponding values |
| 48 | */ |
| 49 | public static function revert(array $arraySimple) : array |
| 50 | { |
| 51 | $array = []; |
| 52 | foreach ($arraySimple as $simpleKey => $value) { |
| 53 | $simpleKey = (string) $simpleKey; |
| 54 | $parentKey = static::getParentKey($simpleKey); |
| 55 | if ($parentKey === null) { |
| 56 | $array[$simpleKey] = \is_array($value) |
| 57 | ? static::revert($value) |
| 58 | : $value; |
| 59 | continue; |
| 60 | } |
| 61 | $parent = []; |
| 62 | static::addChild( |
| 63 | $parent, |
| 64 | \array_merge([$parentKey], static::extractKeys($simpleKey)), |
| 65 | $value |
| 66 | ); |
| 67 | $array = \array_replace_recursive($array, $parent); |
| 68 | } |
| 69 | return $array; |
| 70 | } |
| 71 | |
| 72 | /** |
| 73 | * Converts an array to an associative array with simple keys. |
| 74 | * |
| 75 | * @param array<mixed> $array Array to be converted |
| 76 | * |
| 77 | * @return array<string,mixed> An associative array with the simple keys as |
| 78 | * keys and their corresponding values |
| 79 | */ |
| 80 | public static function convert(array $array) : array |
| 81 | { |
| 82 | $array = static::revert($array); |
| 83 | $data = []; |
| 84 | foreach (static::keys($array) as $key) { |
| 85 | $data[$key] = static::value($key, $array); |
| 86 | } |
| 87 | return $data; |
| 88 | } |
| 89 | |
| 90 | /** |
| 91 | * Gets the value of an array item through a simple key. |
| 92 | * |
| 93 | * @param string $simpleKey A string in the simple key format |
| 94 | * @param array<mixed> $array The array to search in |
| 95 | * |
| 96 | * @return mixed The item value or null if not found |
| 97 | */ |
| 98 | public static function value(string $simpleKey, array $array) : mixed |
| 99 | { |
| 100 | $array = static::revert($array); |
| 101 | $parentKey = static::getParentKey($simpleKey); |
| 102 | if ($parentKey === null) { |
| 103 | return $array[$simpleKey] ?? null; |
| 104 | } |
| 105 | $value = $array[$parentKey] ?? null; |
| 106 | foreach (static::extractKeys($simpleKey) as $key) { |
| 107 | if ( ! (\is_array($value) && \array_key_exists($key, $value))) { |
| 108 | return null; |
| 109 | } |
| 110 | $value = $value[$key]; |
| 111 | } |
| 112 | return $value; |
| 113 | } |
| 114 | |
| 115 | /** |
| 116 | * Gets the keys of an array in the simple keys format. |
| 117 | * |
| 118 | * @param array<mixed> $array The array to get the simple keys |
| 119 | * |
| 120 | * @return array<int,string> An indexed array containing the simple keys as |
| 121 | * values |
| 122 | */ |
| 123 | #[Pure] |
| 124 | public static function keys(array $array) : array |
| 125 | { |
| 126 | return static::getKeys($array); |
| 127 | } |
| 128 | |
| 129 | /** |
| 130 | * @param array<mixed> $array |
| 131 | * @param string $childKey |
| 132 | * |
| 133 | * @return array<int,string> |
| 134 | */ |
| 135 | #[Pure] |
| 136 | protected static function getKeys(array $array, string $childKey = '') : array |
| 137 | { |
| 138 | $allKeys = []; |
| 139 | foreach ($array as $key => $value) { |
| 140 | $key = (string) $key; |
| 141 | if (\is_array($value)) { |
| 142 | $allKeys = $childKey === '' |
| 143 | ? \array_merge($allKeys, static::getKeys($value, $key)) |
| 144 | : \array_merge( |
| 145 | $allKeys, |
| 146 | static::getKeys($value, $childKey . static::getChildKey($key)) |
| 147 | ); |
| 148 | continue; |
| 149 | } |
| 150 | $allKeys[] = $childKey === '' |
| 151 | ? $key |
| 152 | : $childKey . static::getChildKey($key); |
| 153 | } |
| 154 | return $allKeys; |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * @param array<int,string> $parent |
| 159 | * @param array<int,string> $childs |
| 160 | * @param mixed $value |
| 161 | */ |
| 162 | protected static function addChild(array &$parent, array $childs, mixed $value) : void |
| 163 | { |
| 164 | $key = \array_shift($childs); |
| 165 | $key = (string) $key; |
| 166 | $parent[$key] = []; |
| 167 | if ($childs === []) { |
| 168 | $parent[$key] = $value; |
| 169 | return; |
| 170 | } |
| 171 | static::addChild($parent[$key], $childs, $value); |
| 172 | } |
| 173 | |
| 174 | #[Pure] |
| 175 | protected static function getParentKey(string $key) : ?string |
| 176 | { |
| 177 | $posOpen = \strpos($key, '['); |
| 178 | $posClose = $posOpen ? \strpos($key, ']', $posOpen) : false; |
| 179 | if ($posClose === false) { |
| 180 | return null; |
| 181 | } |
| 182 | return \substr($key, 0, $posOpen); // @phpstan-ignore-line |
| 183 | } |
| 184 | |
| 185 | #[Pure] |
| 186 | protected static function getChildKey(string $key) : string |
| 187 | { |
| 188 | $parentKey = static::getParentKey($key); |
| 189 | if ($parentKey === null) { |
| 190 | return '[' . $key . ']'; |
| 191 | } |
| 192 | $key = \explode('[', $key, 2); |
| 193 | $key = '[' . $key[0] . '][' . $key[1]; |
| 194 | return $key; |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * Get $_FILES in a re-organized way. |
| 199 | * |
| 200 | * NOTE: Do not use file input names as `name`, `type`, `tmp_name`, `error`, |
| 201 | * `full_path` and `size` to avoid overwrite of arrays. |
| 202 | * |
| 203 | * @return array<string,mixed> An array ready to be used with |
| 204 | * {@see ArraySimple::value()} |
| 205 | */ |
| 206 | #[Pure] |
| 207 | public static function files() : array |
| 208 | { |
| 209 | $files = []; |
| 210 | foreach ($_FILES as $name => $values) { |
| 211 | if ( ! isset($files[$name])) { |
| 212 | $files[$name] = []; |
| 213 | } |
| 214 | if ( ! \is_array($values['error'])) { |
| 215 | $files[$name] = $values; |
| 216 | continue; |
| 217 | } |
| 218 | foreach ($values as $infoKey => $subArray) { |
| 219 | $files[$name] = \array_replace_recursive( |
| 220 | $files[$name], |
| 221 | static::filesWalker($subArray, $infoKey) |
| 222 | ); |
| 223 | } |
| 224 | } |
| 225 | return $files; |
| 226 | } |
| 227 | |
| 228 | /** |
| 229 | * @see https://stackoverflow.com/a/33261775/6027968 |
| 230 | * |
| 231 | * @param array<mixed> $array |
| 232 | * @param string $infoKey |
| 233 | * |
| 234 | * @return array<string,mixed> |
| 235 | */ |
| 236 | #[Pure] |
| 237 | protected static function filesWalker(array $array, string $infoKey) : array |
| 238 | { |
| 239 | $return = []; |
| 240 | foreach ($array as $key => $value) { |
| 241 | $key = (string) $key; |
| 242 | if (\is_array($value)) { |
| 243 | $return[$key] = static::filesWalker($value, $infoKey); |
| 244 | continue; |
| 245 | } |
| 246 | $return[$key][$infoKey] = $value; |
| 247 | } |
| 248 | return $return; |
| 249 | } |
| 250 | } |