nur-sery/nur_src/c.php

150 lines
4.5 KiB
PHP

<?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 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 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);
}
}