<?php namespace nur; use nur\b\ui\IContent; use nur\b\ui\IPrintable; /** * Class c: gestion de contenu iterable, {@link IPrintable}, {@link IContent} * * @see co */ class c { /** * quoter $vs si c'est un scalaire non nul. * retourner null si $vs vaut null ou false. * sinon retourner le tableau tel quel */ static final function qnz($vs): ?iterable { if ($vs === null || $vs === false) return null; elseif ($vs instanceof IPrintable) return [$vs]; elseif ($vs instanceof IContent) return [$vs]; elseif (is_iterable($vs)) return $vs; else return [htmlspecialchars(strval($vs))]; } /** * quoter $vs si c'est un scalaire. sinon retourner le tableau tel quel * * NB: cette méthode est accessible via la fonction globale {@link q()} */ static final function q($vs): iterable { if ($vs === null || $vs === false) return []; elseif ($vs instanceof IPrintable) return [$vs]; elseif ($vs instanceof IContent) return [$vs]; elseif (is_iterable($vs)) return $vs; else return [htmlspecialchars(strval($vs))]; } /** retourner un tableau pour $vs sans le quoter si c'est un scalaire */ static final function nq($vs): iterable { if ($vs === null || $vs === false) return []; elseif ($vs instanceof IPrintable) return [$vs]; elseif ($vs instanceof IContent) return [$vs]; elseif (is_iterable($vs)) return $vs; else return [strval($vs)]; } /** * s'assurer que la valeur est une chaine si elle n'est pas nulle et que ce * n'est pas déjà une instance de {@link IPrintable} ou {@link IContent} */ private static final function _strval($value) { if ($value === null) { #NOP } elseif ($value instanceof IPrintable) { #NOP } elseif ($value instanceof IContent) { #NOP } else $value = strval($value); return $value; } /** fusionner deux valeurs */ private static final function _merge($pvalue, $value) { if (!$pvalue) { # prendre $value if (!is_iterable($value)) $value = self::_strval($value); return $value; } elseif (!$value) { # garder $pvalue return $pvalue; } else { if (!is_iterable($value)) $value = self::_strval($value); return array_merge(A::with($pvalue), A::with($value)); } } /** * Applatir le tableau $values * * - [a, [b]] devient [a, b] * - [a => x, [a => y]] devient [a => [x, y]] * * si $recursive==true, alors * - [a => [x, [y]]] devient [a => [x, y]] */ static final function flatten(?iterable $values, bool $recursive=true): array { $flattened = []; if ($values !== null) { $index = 0; foreach ($values as $key => $value) { if ($key === $index) { # valeurs séquentielles # elles ne sont jamais quotées $index++; if (is_iterable($value)) { $value = self::flatten($value); $index2 = 0; foreach ($value as $key2 => $value2) { if ($key2 === $index2) { # sequentiel $index2++; $flattened[] = $value2; } else { if (array_key_exists($key2, $flattened)) { $pvalue2 = $flattened[$key2]; $value2 = self::_merge($pvalue2, $value2); } $flattened[$key2] = $value2; } } } else { $flattened[] = self::_strval($value); } } else { # valeurs associatives # la valeur est quotée si elle n'est pas dans un tableau if (array_key_exists($key, $flattened)) { $value = self::_merge($flattened[$key], $value); } if ($recursive && is_array($value)) { $value = self::flatten($value, true); } $flattened[$key] = $value; } } } return $flattened; } /** méthode de convenance pour quoter puis applatir $vs */ static final function fq($vs): array { return self::flatten(self::q($vs)); } /** retourner la chaine correspondant au tableau $vs applati */ static final function string(iterable $vs): string { $pieces = []; foreach (c::flatten($vs) as $v) { if ($v instanceof IContent) { $pieces[] = self::string($v->getContent()); } elseif ($v instanceof IPrintable) { ob_start(null, 0, PHP_OUTPUT_HANDLER_STDFLAGS ^ PHP_OUTPUT_HANDLER_FLUSHABLE); $v->print(); $pieces[] = ob_get_clean(); } else { $pieces[] = $v; } } return implode("", $pieces); } }