This commit is contained in:
Bastian Allgeier
2020-07-07 12:40:13 +02:00
parent 5f025ac2c2
commit f79d2e960c
176 changed files with 10532 additions and 5343 deletions

View File

@@ -81,29 +81,38 @@ class A
return $array[$key];
}
// support dot notation
// extract data from nested array structures using the dot notation
if (strpos($key, '.') !== false) {
$keys = explode('.', $key);
$firstKey = array_shift($keys);
// if the input array also uses dot notation, try to find a subset of the $keys
if (isset($array[$firstKey]) === false) {
$currentKey = $firstKey;
while ($innerKey = array_shift($keys)) {
$currentKey = $currentKey . '.' . $innerKey;
$currentKey .= '.' . $innerKey;
if (isset($array[$currentKey]) === true && is_array($array[$currentKey])) {
// the element needs to exist and also needs to be an array; otherwise
// we cannot find the remaining keys within it (invalid array structure)
if (isset($array[$currentKey]) === true && is_array($array[$currentKey]) === true) {
// $keys only holds the remaining keys that have not been shifted off yet
return static::get($array[$currentKey], implode('.', $keys), $default);
}
}
// searching through the full chain of keys wasn't successful
return $default;
}
// if the input array uses a completely nested structure,
// recursively progress layer by layer
if (is_array($array[$firstKey]) === true) {
return static::get($array[$firstKey], implode('.', $keys), $default);
}
// the $firstKey element was found, but isn't an array, so we cannot
// find the remaining keys within it (invalid array structure)
return $default;
}
@@ -410,6 +419,89 @@ class A
return $missing;
}
/**
* Normalizes an array into a nested form by converting
* dot notation in keys to nested structures
*
* @param array $array
* @param array $ignore List of keys in dot notation that should
* not be converted to a nested structure
* @return array
*/
public static function nest(array $array, array $ignore = []): array
{
// convert a simple ignore list to a nested $key => true array
if (isset($ignore[0]) === true) {
$ignore = array_map(function () {
return true;
}, array_flip($ignore));
$ignore = A::nest($ignore);
}
$result = [];
foreach ($array as $fullKey => $value) {
// extract the first part of a multi-level key, keep the others
$subKeys = explode('.', $fullKey);
$key = array_shift($subKeys);
// skip the magic for ignored keys
if (isset($ignore[$key]) === true && $ignore[$key] === true) {
$result[$fullKey] = $value;
continue;
}
// untangle elements where the key uses dot notation
if (count($subKeys) > 0) {
$value = static::nestByKeys($value, $subKeys);
}
// now recursively do the same for each array level if needed
if (is_array($value) === true) {
$value = static::nest($value, $ignore[$key] ?? []);
}
// merge arrays with previous results if necessary
// (needed when the same keys are used both with and without dot notation)
if (
isset($result[$key]) === true &&
is_array($result[$key]) === true &&
is_array($value) === true
) {
$result[$key] = array_replace_recursive($result[$key], $value);
} else {
$result[$key] = $value;
}
}
return $result;
}
/**
* Recursively creates a nested array from a set of keys
* with a key on each level
*
* @param mixed $value Arbitrary value that will end up at the bottom of the tree
* @param array $keys List of keys to use sorted from the topmost level
* @return array|mixed Nested array or (if `$keys` is empty) the input `$value`
*/
public static function nestByKeys($value, array $keys)
{
// shift off the first key from the list
$firstKey = array_shift($keys);
// stop further recursion if there are no more keys
if ($firstKey === null) {
return $value;
}
// return one level of the output tree, recurse further
return [
$firstKey => static::nestByKeys($value, $keys)
];
}
/**
* Sorts a multi-dimensional array by a certain column
*