nur-sery/nur_src/b/UserException.php

139 lines
3.9 KiB
PHP

<?php
namespace nur\b;
use Exception;
use nur\md;
use Throwable;
/**
* Class UserException: une exception qui peut contenir deux messages: un
* message utilisateur, et un message technique, destiné à l'exploitant
*/
class UserException extends Exception {
/** @param Throwable|ExceptionShadow $e */
static function get_user_message($e): ?string {
if ($e instanceof self) return $e->getUserMessage();
else return null;
}
/** @param Throwable|ExceptionShadow $e */
static function get_tech_message($e): ?string {
if ($e instanceof self) return $e->getTechMessage();
else return $e->getMessage();
}
/** @param Throwable|ExceptionShadow $e */
static function get_message($e): ?string {
$message = null;
if ($e instanceof self) {
if ($message === null) $message = $e->getTechMessage();
if ($message === null) $message = $e->getUserMessage();
}
if ($message === null) $message = $e->getMessage();
return $message;
}
/** @param Throwable|ExceptionShadow $e */
static final function get_user_summary($e): string {
$parts = [];
$first = true;
while ($e !== null) {
$message = self::get_user_message($e);
if (!$message) $message = "(no message)";
if ($first) $first = false;
else $parts[] = "caused by ";
$parts[] = get_class($e) . ": " . $message;
$e = $e->getPrevious();
}
return implode(", ", $parts);
}
/** @param Throwable|ExceptionShadow $e */
static final function get_tech_summary($e): string {
$parts = [];
$first = true;
while ($e !== null) {
$message = self::get_tech_message($e);
if (!$message) $message = "(no message)";
if ($first) $first = false;
else $parts[] = "caused by ";
$parts[] = get_class($e) . ": " . $message;
$e = $e->getPrevious();
}
return implode(", ", $parts);
}
/** @param Throwable|ExceptionShadow $e */
static final function get_summary($e): string {
$parts = [];
$first = true;
while ($e !== null) {
$message = self::get_message($e);
if (!$message) $message = "(no message)";
if ($first) $first = false;
else $parts[] = "caused by ";
if ($e instanceof ExceptionShadow) $class = $e->getClass();
else $class = get_class($e);
$parts[] = "$class: $message";
$e = $e->getPrevious();
}
return implode(", ", $parts);
}
/** @param Throwable|ExceptionShadow $e */
static final function get_traceback($e): string {
$tbs = [];
$previous = false;
while ($e !== null) {
if (!$previous) {
$efile = $e->getFile();
$eline = $e->getLine();
$tbs[] = "at $efile($eline)";
} else {
$tbs[] = "~~ caused by: " . self::get_summary($e);
}
$tbs[] = $e->getTraceAsString();
$e = $e->getPrevious();
$previous = true;
#XXX il faudrait ne pas réinclure les lignes communes aux exceptions qui
# ont déjà été affichées
}
return implode("\n", $tbs);
}
const SCHEMA = [
"user" => [null, null, "message utilisateur"],
"tech" => [null, null, "message technique"],
];
const USER_MESSAGE = null;
const TECH_MESSAGE = null;
function __construct($message, $code=0, ?Throwable $previous=null) {
md::ensure_schema($message, self::SCHEMA);
$user_message = $message["user"];
if ($user_message === null) $user_message = static::USER_MESSAGE;
$this->userMessage = $user_message;
$tech_message = $message["tech"];
if ($tech_message === null) $tech_message = static::TECH_MESSAGE;
if ($tech_message === null) $tech_message = $previous;
$this->techMessage = $tech_message;
$message = $tech_message;
if ($message === null) $message = $user_message;
parent::__construct($message, $code, $previous);
}
protected $userMessage;
function getUserMessage(): ?string {
return $this->userMessage;
}
protected $techMessage;
function getTechMessage(): ?string {
return $this->techMessage;
}
}