diff --git a/php/src/A.php b/php/src/A.php index 1f4b630..253592b 100644 --- a/php/src/A.php +++ b/php/src/A.php @@ -1,6 +1,7 @@ + * $array = ["first", "second"] + * A::ensure_assoc($array, ["a", "b"]); + * // returns ["a" => "first", "b" => "second"] + * + */ + static final function ensure_assoc(?array &$array, array $keys, ?array $params=null): void { + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + $index = 0; + foreach ($keys as $key) { + if ($prefix !== null || $suffix !== null) { + $destKey = "$prefix$key$suffix"; + } else { + # préserver les clés numériques + $destKey = $key; + } + if ($array !== null && array_key_exists($destKey, $array)) continue; + while (in_array($index, $keys, true)) { + $index++; + } + if ($array !== null && array_key_exists($index, $array)) { + $array[$destKey] = $array[$index]; + unset($array[$index]); + $index++; + } + } + } + + /** + * s'assurer que $array contient toutes les clés de $defaults, avec la valeur + * par défaut le cas échéant + * + * $missings est un tableau indiquant des valeurs qui si elles sont dans + * $array, signifie que la clé correspondante doit être considérée comme + * inexistante (et donc remplacée par la valeur de $defaults) + */ + static final function ensure_keys(?array &$array, array $defaults, ?array $missings=null, ?array $params=null): void { + $keys = array_keys($defaults); + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + foreach ($keys as $key) { + $destKey = "$prefix$key$suffix"; + $haveMissing = $missings !== null && array_key_exists($key, $missings); + if ($array === null || !array_key_exists($destKey, $array)) { + $array[$destKey] = $defaults[$key]; + } elseif ($haveMissing && $array[$destKey] === $missings[$key]) { + $array[$destKey] = $defaults[$key]; + } + } + } + + /** + * supprimer dans $array les clés dont les valeurs correspondent au tableau + * $missings + */ + static final function delete_missings(?array &$array, array $missings, ?array $params=null): void { + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + foreach ($missings as $key => $missing) { + $destKey = "$prefix$key$suffix"; + if (array_key_exists($destKey, $array) && $array[$destKey] === $missing) { + unset($array[$destKey]); + } + } + } + + /** + * s'assurer que les clés dans $array sont dans le même ordre que dans $keys + * + * les clés supplémentaires sont poussées à la fin du tableau + */ + static final function ensure_order(?array &$array, array $keys, ?array $params=null): void { + if ($array === null) return; + + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + if ($prefix !== null || $suffix !== null) { + foreach ($keys as &$key) { + $key = "$prefix$key$suffix"; + }; unset($key); + } + + $destKeys = array_keys($array); + $keyCount = count($keys); + if (array_slice($destKeys, 0, $keyCount) === $keys) { + # si le tableau a déjà les bonnes clés dans le bon ordre, rien à faire + return; + } + + $ordered = []; + foreach ($keys as $key) { + if (array_key_exists($key, $array)) { + $ordered[$key] = $array[$key]; + unset($array[$key]); + } + } + $preserveKeys = $params["preserve_keys"] ?? false; + if ($preserveKeys) $array = cl::merge2($ordered, $array); + else $array = array_merge($ordered, $array); + } } diff --git a/php/src/cl.php b/php/src/cl.php index 78dcb9b..2c2bac1 100644 --- a/php/src/cl.php +++ b/php/src/cl.php @@ -398,15 +398,86 @@ class cl { ############################################################################# - static final function map($func, ?iterable $array): array { - $result = []; - if ($array !== null) { - $func = func::with($func); - foreach ($array as $key => $value) { - $result[$key] = $func->invoke([$value, $key]); + /** + * tester si $array satisfait les conditions de $filter + * - $filter est un scalaire, le transformer en [$filter] + * - sinon $filter doit être un tableau de scalaires + * + * les règles des conditions sont les suivantes: + * - une valeur séquentielle $key est équivalente à la valeur associative + * $key => true + * - une valeur associative $key => bool indique que la clé correspondante ne + * doit pas (resp. doit) exister selon que bool vaut false (resp. true) + * - une valeur associative $key => $value indique que la clé correspondante + * doit exiter avec la valeur spécifiée + */ + static final function filter(?array $array, $filter): bool { + if ($filter === null) return false; + if (!is_array($filter)) $filter = [$filter]; + if (!$filter) return false; + + $index = 0; + foreach ($filter as $key => $value) { + if ($key === $index) { + $index++; + if ($array === null) return false; + if (!array_key_exists($value, $array)) return false; + } elseif (is_bool($value)) { + if ($value) { + if ($array === null || !array_key_exists($key, $array)) return false; + } else { + if ($array !== null && array_key_exists($key, $array)) return false; + } + } else { + if ($array === null) return false; + if (!array_key_exists($key, $array)) return false; + if ($array[$key] !== $value) return false; } } - return $result; + return true; + } + + /** + * mapper le tableau source $array selon les règles suivantes illustrées dans + * l'exemple suivant: + * si + * $map = ["a", "b" => "x", "c" => function() { return "y"; }, "d" => null] + * alors retourner le tableau + * ["a" => $array["a"], "b" => $array["x"], "c" => "y", "d" => null] + * + * si une fonction est utilisée, sa signature est + * function(mixed $value, string|int $key, ?array $array) + */ + static function map(?array $array, ?array $map): ?array { + if ($map === null) return $array; + $index = 0; + $mapped = []; + foreach ($map as $key => $value) { + if ($key === $index) { + $index++; + if ($value === null) $mapped[] = null; + else $mapped[$value] = cl::get($array, $value); + } elseif (is_callable($value)) { + $func = func::with($value); + $value = cl::get($array, $key); + $mapped[$key] = $func->invoke([$value, $key, $array]); + } else { + if ($value === null) $mapped[$key] = null; + else $mapped[$key] = cl::get($array, $value); + } + } + return $mapped; + } + + static final function mapf(?iterable $items, $func): array { + $mapped = []; + if ($items !== null) { + $func = func::with($func); + foreach ($items as $key => $item) { + $mapped[$key] = $func->invoke([$item, $key, $items]); + } + } + return $mapped; } #############################################################################