flatten($value, $flattenValue); } return $value; } /** * Fusionner une valeur dans des valeurs précédentes. * * Cette méthode considère la fusion avec les valeurs null et false comme des * NOPs: retourner toujours la valeur originale. * * Sinon, transformer la valeur précédente et la nouvelle valeur en tableaux * puis fusionner les deux. */ protected function mergeValueMerge($value, $pvalue, bool $flattenValue) { if (base::z($pvalue)) { # ne pas chercher à merger si $pvalue est null ou false # remplacer par $value return $value; } elseif (base::z($value)) { # ne pas chercher à merger si $value est null ou false # garder $pvalue return $pvalue; } else { if (!is_array($pvalue)) $pvalue = A::with($pvalue); if (!is_array($value)) { $value = A::with($value); } elseif ($flattenValue) { $this->flatten($value, $flattenValue); } return array_merge($pvalue, $value); } } /** * Fusionner une valeur dans des valeurs précédentes. * * Cette méthode considère la fusion avec la valeur false comme un NOP: * retourner toujours la valeur originale. * * Par contre, la valeur null remplace la valeur précédente et permet de * recommencer à zéro. * * Sinon, transformer la valeur précédente et la nouvelle valeur en tableaux * puis fusionner les deux. */ protected function mergeValueMerge2($value, $pvalue, bool $flattenValue) { if (base::z($pvalue)) { # ne pas chercher à merger si $pvalue est null ou false # (remplacer par $value) return $value; } elseif ($value === null) { # null annule la valeur précédente (remplacer par $value) return $value; } elseif ($value === false) { # false laisse en place la valeur précédente (garder $pvalue) return $pvalue; } else { if (!is_array($pvalue)) $pvalue = A::with($pvalue); if (!is_array($value)) { $value = A::with($value); } elseif ($flattenValue) { $this->flatten($value, $flattenValue); } return array_merge($pvalue, $value); } } protected function mergeValue($value, $pvalue, bool $flattenValue) { return $this->mergeValueMerge($value, $pvalue, $flattenValue); } /** * Applatir le tableau $array. * * Pour chaque élément avec une clé séquentielle: * - si c'est un tableau, l'applatir puis rajouter ses éléments tels quels au résultat * - sinon ajouter l'élément tel quel * * Pour chaque élément avec une clé associative: * - si la valeur n'existe pas déjà, elle est rajoutée telle quelle * - sinon, la valeur est fusionnée avec la valeur précédente avec la * fonction {@link mergeValue()} * * @param $array * @param bool $flattenValue */ function flatten(&$array, bool $flattenValue=true): void { A::ensure_array($array); # vérifier d'abord si on peut éviter de reconstruire un nouvel objet $only_scalars = true; foreach ($array as $value) { if (is_array($value)) { $only_scalars = false; break; } } if ($only_scalars) return; # puis applatir le tableau $parts = []; $index = 0; foreach ($array as $key => $value) { if ($key === $index) { # valeurs séquentielles $index++; if (is_array($value)) { $this->flatten($value, $flattenValue); $index2 = 0; foreach ($value as $key2 => $value2) { if ($key2 === $index2) { # sequentiel $index2++; $parts[] = $value2; } else { if (array_key_exists($key2, $parts)) { $pvalue2 = $parts[$key2]; $value2 = $this->mergeValue($value2, $pvalue2, $flattenValue); } $parts[$key2] = $value2; } } } else { $parts[] = $value; } } else { # valeurs associatives if (array_key_exists($key, $parts)) { $pvalue = $parts[$key]; $value = $this->mergeValue($value, $pvalue, $flattenValue); } $parts[$key] = $value; } } $array = $parts; } }