nulib-base/php/src/output/std/AbstractMessenger.php

298 lines
10 KiB
PHP

<?php
namespace nulib\output\std;
use Exception;
use nulib\A;
use nulib\cl;
use nulib\exceptions;
use nulib\ExceptionShadow;
use Throwable;
abstract class AbstractMessenger implements _IMessenger {
const ADD_DATE = false;
const SHOW_IDS = false;
protected static function verifix_level($level, int $max_level=self::MAX_LEVEL): int {
if (!in_array($level, self::VALID_LEVELS, true)) {
$level = cl::get(self::LEVEL_MAP, $level, $level);
}
if (!in_array($level, self::VALID_LEVELS, true)) {
throw new Exception("$level: invalid level");
}
if ($level > $max_level) {
throw new Exception("$level: level not allowed here");
}
return $level;
}
/** @var StdOutput la sortie standard */
protected StdOutput $out;
/** @var int level par défaut dans lequel les messages sont affichés */
protected int $defaultLevel;
/** @var int level minimum que doivent avoir les messages pour être affichés */
protected int $minLevel;
/** @var bool faut-il ajouter la date à chaque ligne? */
protected bool $addDate;
/** @var string format de la date */
protected string $dateFormat;
/** @var bool faut-il afficher les ids (p=id t=id a=id) */
protected bool $showIds;
/** @var ?string identifiant de ce messenger, à ajouter à chaque ligne */
protected ?string $id;
protected int $lastTitleId = 1;
protected abstract function title__getId(): ?int;
protected int $lastActionId = 1;
protected abstract function action__getId(): ?int;
protected function getLinePrefix(): ?string {
$linePrefix = null;
if ($this->addDate) {
$date = date_create()->format($this->dateFormat);
$linePrefix .= "$date ";
}
if ($this->showIds) {
if ($this->id !== null) $linePrefix .= "p=$this->id ";
$titleId = $this->title__getId();
if ($titleId !== null) $linePrefix .= "t=$titleId ";
$actionId = $this->action__getId();
if ($actionId !== null) $linePrefix .= "a=$actionId ";
}
return $linePrefix;
}
protected function decrLevel(int $level, int $amount=-1): int {
$level += $amount;
if ($level < self::MIN_LEVEL) $level = self::MIN_LEVEL;
return $level;
}
protected function checkLevel(?int &$level): bool {
if ($level === null) $level = $this->defaultLevel;
elseif ($level < 0) $level = $this->decrLevel($this->defaultLevel, $level);
return $level >= $this->minLevel;
}
protected function _printTitle(
int $level, string $type, ?string $linePrefix, int $indentLevel,
StdOutput $out, $content
): void {
$prefixes = self::GENERIC_PREFIXES[$level][$type];
if ($prefixes[0]) $out->print();
$content = cl::with($content);
if ($out->isColor()) {
$before = $prefixes[2];
$prefix = $prefixes[3];
$prefix2 = $prefix !== null? "$prefix ": null;
$suffix = $prefixes[4];
$suffix2 = $suffix !== null? " $suffix": null;
$after = $prefixes[5];
$lines = $out->getLines(false, ...$content);
$maxlen = 0;
foreach ($lines as &$content) {
$line = $out->filterColors($content);
$len = mb_strlen($line);
if ($len > $maxlen) $maxlen = $len;
$content = [$content, $len];
}; unset($content);
if ($before !== null) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $prefix, substr($before, 1), str_repeat($before[0], $maxlen), $suffix);
}
foreach ($lines as [$content, $len]) {
if ($linePrefix !== null) $out->write($linePrefix);
$padding = $len < $maxlen? str_repeat(" ", $maxlen - $len): null;
$out->iprint($indentLevel, $prefix2, $content, $padding, $suffix2);
}
if ($after !== null) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $prefix, substr($after, 1), str_repeat($after[0], $maxlen), $suffix);
}
} else {
$prefix = $prefixes[1];
if ($prefix !== null) $prefix .= " ";
$prefix2 = str_repeat(" ", mb_strlen($prefix));
$lines = $out->getLines(false, ...$content);
foreach ($lines as $content) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $prefix, $content);
$prefix = $prefix2;
}
}
}
protected abstract function action__flush(bool $endAction=false, ?int $overrideLevel=null): void;
protected function _printAction(
int $level, ?string $linePrefix, int $indentLevel,
StdOutput $out,
bool $printContent, $content,
bool $printResult, ?bool $rsuccess, $rcontent
): void {
$color = $out->isColor();
if ($rsuccess === true) $type = "success";
elseif ($rsuccess === false) $type = "failure";
else $type = "done";
$rprefixes = self::RESULT_PREFIXES[$type];
if ($color) {
$rprefix = $rprefixes[1];
$rprefix2 = null;
if ($rprefix !== null) {
$rprefix .= " ";
$rprefix2 = $out->filterColors($out->filterContent($rprefix));
$rprefix2 = str_repeat(" ", mb_strlen($rprefix2));
}
} else {
$rprefix = $rprefixes[0];
if ($rprefix !== null) $rprefix .= " ";
$rprefix2 = str_repeat(" ", mb_strlen($rprefix));
}
if ($printContent && $printResult) {
A::ensure_array($content);
if ($rcontent) {
$content[] = ": ";
$content[] = $rcontent;
}
$lines = $out->getLines(false, ...$content);
foreach ($lines as $content) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $rprefix, $content);
$rprefix = $rprefix2;
}
} elseif ($printContent) {
$prefixes = self::GENERIC_PREFIXES[$level]["step"];
if ($color) {
$prefix = $prefixes[1];
if ($prefix !== null) $prefix .= " ";
$prefix2 = $out->filterColors($out->filterContent($prefix));
$prefix2 = str_repeat(" ", mb_strlen($prefix2));
$suffix = $prefixes[2];
} else {
$prefix = $prefixes[0];
if ($prefix !== null) $prefix .= " ";
$prefix2 = str_repeat(" ", mb_strlen($prefix));
$suffix = null;
}
A::ensure_array($content);
$content[] = ":";
$lines = $out->getLines(false, ...$content);
foreach ($lines as $content) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $prefix, $content, $suffix);
$prefix = $prefix2;
}
} elseif ($printResult) {
if (!$rcontent) {
if ($type === "success") $rcontent = $color? "succès": "";
elseif ($type === "failure") $rcontent = $color? "échec": "";
elseif ($type === "done") $rcontent = "fait";
}
$rprefix = " $rprefix";
$rprefix2 = " $rprefix2";
$lines = $out->getLines(false, $rcontent);
foreach ($lines as $rcontent) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $rprefix, $rcontent);
$rprefix = $rprefix2;
}
}
}
protected function _printGeneric(
int $level, string $type, ?string $linePrefix, int $indentLevel,
StdOutput $out, $content
): void {
$prefixes = self::GENERIC_PREFIXES[$level][$type];
$content = cl::with($content);
if ($out->isColor()) {
$prefix = $prefixes[1];
$prefix2 = null;
if ($prefix !== null) {
$prefix .= " ";
$prefix2 = $out->filterColors($out->filterContent($prefix));
$prefix2 = str_repeat(" ", mb_strlen($prefix2));
}
$suffix = $prefixes[2];
$lines = $out->getLines(false, ...$content);
foreach ($lines as $content) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $prefix, $content, $suffix);
$prefix = $prefix2;
}
} else {
$prefix = $prefixes[0];
if ($prefix !== null) $prefix .= " ";
$prefix2 = str_repeat(" ", mb_strlen($prefix));
$lines = $out->getLines(false, ...$content);
foreach ($lines as $content) {
if ($linePrefix !== null) $out->write($linePrefix);
$out->iprint($indentLevel, $prefix, $content);
$prefix = $prefix2;
}
}
}
protected function _printGenericOrException(
?int $level, string $type, int $indentLevel,
StdOutput $out, $content
): void {
$linePrefix = $this->getLinePrefix();
# si $content contient des exceptions, les afficher avec un level moindre
$exceptions = null;
if (is_array($content)) {
$valueContent = null;
foreach ($content as $value) {
if ($value instanceof Throwable || $value instanceof ExceptionShadow) {
$exceptions[] = $value;
} else {
$valueContent[] = $value;
}
}
if ($valueContent === null) $content = null;
elseif (count($valueContent) == 1) $content = $valueContent[0];
else $content = $valueContent;
} elseif ($content instanceof Throwable || $content instanceof ExceptionShadow) {
$exceptions[] = $content;
$content = null;
}
$flushActions = true;
$showContent = $this->checkLevel($level);
if ($content !== null && $showContent) {
$this->action__flush(); $flushActions = false;
$this->_printGeneric($level, $type, $linePrefix, $indentLevel, $out, $content);
}
if ($exceptions !== null) {
$level1 = $this->decrLevel($level);
$showTraceback = $this->checkLevel($level1);
foreach ($exceptions as $exception) {
# tout d'abord message
$message = exceptions::get_message($exception);
if ($showContent) {
if ($flushActions) { $this->action__flush(); $flushActions = false; }
$this->_printGeneric($level, $type, $linePrefix, $indentLevel, $out, $message);
}
# puis summary et traceback
if ($showTraceback) {
if ($flushActions) { $this->action__flush(); $flushActions = false; }
$summary = exceptions::get_summary($exception, false);
$this->_printGeneric($level1, $type, $linePrefix, $indentLevel, $out, $summary);
$traceback = exceptions::get_traceback($exception);
$this->_printGeneric($level1, $type, $linePrefix, $indentLevel, $out, $traceback);
}
}
}
}
}