réorganiser les exceptions
This commit is contained in:
parent
cf30ff6386
commit
42992c84d4
@ -2,17 +2,16 @@
|
||||
namespace cli\pman;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\ext\json;
|
||||
use nulib\file;
|
||||
use nulib\os\path;
|
||||
use nulib\ValueException;
|
||||
|
||||
class ComposerFile {
|
||||
function __construct(string $composerFile=".", bool $ensureExists=true) {
|
||||
if (is_dir($composerFile)) $composerFile = path::join($composerFile, 'composer.json');
|
||||
if ($ensureExists && !file_exists($composerFile)) {
|
||||
$message = path::ppath($composerFile).": fichier introuvable";
|
||||
throw new ValueException($message);
|
||||
throw exceptions::invalid_value(path::ppath($composerFile), "ce fichier", "il est introuvable");
|
||||
}
|
||||
$this->composerFile = $composerFile;
|
||||
$this->load();
|
||||
|
@ -2,10 +2,10 @@
|
||||
namespace cli\pman;
|
||||
|
||||
use nulib\A;
|
||||
use nulib\exceptions;
|
||||
use nulib\ext\yaml;
|
||||
use nulib\os\path;
|
||||
use nulib\str;
|
||||
use nulib\ValueException;
|
||||
|
||||
class ComposerPmanFile {
|
||||
const NAMES = [".composer.pman", ".pman"];
|
||||
@ -29,8 +29,7 @@ class ComposerPmanFile {
|
||||
}
|
||||
}
|
||||
if ($ensureExists && !file_exists($configFile)) {
|
||||
$message = path::ppath($configFile).": fichier introuvable";
|
||||
throw new ValueException($message);
|
||||
throw exceptions::invalid_value(path::ppath($configFile), "ce fichier", "il est introuvable");
|
||||
}
|
||||
$this->configFile = $configFile;
|
||||
$this->load();
|
||||
@ -66,9 +65,7 @@ class ComposerPmanFile {
|
||||
|
||||
function getProfileConfig(string $profile, ?array $composerRequires=null, ?array $composerRequireDevs=null): array {
|
||||
$config = $this->data["composer"][$profile] ?? null;
|
||||
if ($config === null) {
|
||||
throw new ValueException("$profile: profil invalide");
|
||||
}
|
||||
if ($config === null) throw exceptions::invalid_value($profile, "ce profil");
|
||||
if ($composerRequires !== null) {
|
||||
$matchRequires = $this->data["composer"]["match_require"];
|
||||
foreach ($composerRequires as $dep => $version) {
|
||||
|
@ -1,36 +1,38 @@
|
||||
<?php
|
||||
namespace nulib;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Class AccessException: indiquer que la resource ou l'objet auquel on veut
|
||||
* accéder n'est pas accessible. il s'agit donc d'une erreur de l'utilisateur
|
||||
*/
|
||||
class AccessException extends UserException {
|
||||
class AccessException extends LogicException {
|
||||
static final function read_only(?string $dest=null, ?string $prefix=null): self {
|
||||
if ($prefix) $prefix = "$prefix: ";
|
||||
if ($dest === null) $dest = "this property";
|
||||
$message = "$dest is read-only";
|
||||
return new static($prefix.$message);
|
||||
return new static("$prefix$message");
|
||||
}
|
||||
|
||||
static final function immutable_object(?string $dest=null, ?string $prefix=null): self {
|
||||
if ($prefix) $prefix = "$prefix: ";
|
||||
if ($dest === null) $dest = "this object";
|
||||
$message = "$dest is immutable";
|
||||
return new static($prefix.$message);
|
||||
return new static("$prefix$message");
|
||||
}
|
||||
|
||||
static final function not_allowed(?string $action=null, ?string $prefix=null): self {
|
||||
if ($prefix) $prefix = "$prefix: ";
|
||||
if ($action === null) $action = "this operation";
|
||||
$message = "$action is not allowed";
|
||||
return new static($prefix.$message);
|
||||
return new static("$prefix$message");
|
||||
}
|
||||
|
||||
static final function not_accessible(?string $dest=null, ?string $prefix=null): self {
|
||||
if ($prefix) $prefix = "$prefix: ";
|
||||
if ($dest === null) $dest = "this resource";
|
||||
$message = "$dest is not accessible";
|
||||
return new static($prefix.$message);
|
||||
return new static("$prefix$message");
|
||||
}
|
||||
}
|
||||
|
@ -38,17 +38,22 @@ class ExceptionShadow {
|
||||
$this->trace = self::extract_trace($exception->getTrace());
|
||||
$previous = $exception->getPrevious();
|
||||
if ($previous !== null) $this->previous = new static($previous);
|
||||
if ($exception instanceof UserException) {
|
||||
$this->userMessage = $exception->getUserMessage();
|
||||
$this->techMessage = $exception->getTechMessage();
|
||||
} else {
|
||||
$this->userMessage = null;
|
||||
$this->techMessage = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
protected $class;
|
||||
protected string $class;
|
||||
|
||||
function getClass(): string {
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
protected $message;
|
||||
protected string $message;
|
||||
|
||||
function getMessage(): string {
|
||||
return $this->message;
|
||||
@ -61,22 +66,19 @@ class ExceptionShadow {
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
protected $file;
|
||||
protected string $file;
|
||||
|
||||
function getFile(): string {
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/** @var int */
|
||||
protected $line;
|
||||
protected int $line;
|
||||
|
||||
function getLine(): int {
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
/** @var array */
|
||||
protected $trace;
|
||||
protected array $trace;
|
||||
|
||||
function getTrace(): array {
|
||||
return $this->trace;
|
||||
@ -92,10 +94,21 @@ class ExceptionShadow {
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
/** @var ExceptionShadow */
|
||||
protected $previous;
|
||||
protected ?ExceptionShadow $previous;
|
||||
|
||||
function getPrevious(): ?ExceptionShadow {
|
||||
return $this->previous;
|
||||
}
|
||||
|
||||
protected ?array $userMessage;
|
||||
|
||||
function getUserMessage(): ?array {
|
||||
return $this->userMessage;
|
||||
}
|
||||
|
||||
protected ?array $techMessage;
|
||||
|
||||
function getTechMessage(): ?array {
|
||||
return $this->techMessage;
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ class ExitError extends Error {
|
||||
return $this->getCode() !== 0;
|
||||
}
|
||||
|
||||
/** @var ?string */
|
||||
protected $userMessage;
|
||||
protected ?string $userMessage;
|
||||
|
||||
function haveUserMessage(): bool {
|
||||
return $this->userMessage !== null;
|
||||
|
@ -12,12 +12,12 @@ class StateException extends LogicException {
|
||||
if ($method === null) $method = "this method";
|
||||
$message = "$method is not implemented";
|
||||
if ($prefix) $prefix = "$prefix: ";
|
||||
return new static($prefix.$message);
|
||||
return new static("$prefix$message");
|
||||
}
|
||||
|
||||
static final function unexpected_state(?string $suffix=null): self {
|
||||
$message = "unexpected state";
|
||||
if ($suffix) $suffix = ": $suffix";
|
||||
return new static($message.$suffix);
|
||||
return new static("$message$suffix");
|
||||
}
|
||||
}
|
||||
|
@ -1,90 +1,35 @@
|
||||
<?php
|
||||
namespace nulib;
|
||||
|
||||
use nulib\php\content\c;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class UserException: une exception qui peut en plus contenir un message
|
||||
* utilisateur
|
||||
* Class UserException: une exception qui peut contenir un message utilisateur
|
||||
* et un message technique
|
||||
*/
|
||||
class UserException extends RuntimeException {
|
||||
/** @param Throwable|ExceptionShadow $e */
|
||||
static function get_user_message($e): ?string {
|
||||
if ($e instanceof self) return $e->getUserMessage();
|
||||
else return null;
|
||||
function __construct($userMessage, $code=0, ?Throwable $previous=null) {
|
||||
$this->userMessage = $userMessage = c::resolve($userMessage);
|
||||
parent::__construct(c::to_string($userMessage), $code, $previous);
|
||||
}
|
||||
|
||||
/** @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);
|
||||
}
|
||||
protected ?array $userMessage;
|
||||
|
||||
/** @param Throwable|ExceptionShadow $e */
|
||||
static function get_message($e): ?string {
|
||||
$message = $e->getMessage();
|
||||
if (!$message && $e instanceof self) $message = $e->getUserMessage();
|
||||
return $message;
|
||||
}
|
||||
|
||||
/** @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);
|
||||
}
|
||||
|
||||
function __construct($userMessage, $techMessage=null, $code=0, ?Throwable $previous=null) {
|
||||
$this->userMessage = $userMessage;
|
||||
if ($techMessage === null) $techMessage = $userMessage;
|
||||
parent::__construct($techMessage, $code, $previous);
|
||||
}
|
||||
|
||||
/** @var ?string */
|
||||
protected $userMessage;
|
||||
|
||||
function getUserMessage(): ?string {
|
||||
function getUserMessage(): ?array {
|
||||
return $this->userMessage;
|
||||
}
|
||||
|
||||
protected ?array $techMessage = null;
|
||||
|
||||
function getTechMessage(): ?array {
|
||||
return $this->techMessage;
|
||||
}
|
||||
|
||||
function setTechMessage($techMessage): self {
|
||||
$techMessage ??= c::resolve($techMessage);
|
||||
$this->techMessage = $techMessage;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -5,72 +5,4 @@ namespace nulib;
|
||||
* Class ValueException: indiquer qu'une valeur est invalide
|
||||
*/
|
||||
class ValueException extends UserException {
|
||||
private static function value($value): string {
|
||||
if (is_object($value)) {
|
||||
return "<".get_class($value).">";
|
||||
} elseif (is_array($value)) {
|
||||
$values = $value;
|
||||
$parts = [];
|
||||
$index = 0;
|
||||
foreach ($values as $key => $value) {
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
$parts[] = self::value($value);
|
||||
} else {
|
||||
$parts[] = "$key=>".self::value($value);
|
||||
}
|
||||
}
|
||||
return "[" . implode(", ", $parts) . "]";
|
||||
} elseif (is_string($value)) {
|
||||
return $value;
|
||||
} else {
|
||||
return var_export($value, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static function message($value, ?string $message, ?string $kind, ?string $prefix, ?string $suffix): string {
|
||||
if ($kind === null) $kind = "value";
|
||||
if ($message === null) $message = "$kind$suffix";
|
||||
if ($value !== null) {
|
||||
$value = self::value($value);
|
||||
if ($prefix) $prefix = "$prefix: $value";
|
||||
else $prefix = $value;
|
||||
}
|
||||
if ($prefix) $prefix = "$prefix: ";
|
||||
return $prefix.$message;
|
||||
}
|
||||
|
||||
static final function null(?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||
return new static(self::message(null, $message, $kind, $prefix, " should not be null"));
|
||||
}
|
||||
|
||||
static final function check_null($value, ?string $kind=null, ?string $prefix=null, ?string $message=null) {
|
||||
if ($value === null) throw static::null($kind, $prefix, $message);
|
||||
return $value;
|
||||
}
|
||||
|
||||
static final function invalid_kind($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||
return new static(self::message($value, $message, $kind, $prefix, " is invalid"));
|
||||
}
|
||||
|
||||
static final function invalid_key($value, ?string $prefix=null, ?string $message=null): self {
|
||||
return self::invalid_kind($value, "key", $prefix, $message);
|
||||
}
|
||||
|
||||
static final function invalid_value($value, ?string $prefix=null, ?string $message=null): self {
|
||||
return self::invalid_kind($value, "value", $prefix, $message);
|
||||
}
|
||||
|
||||
static final function invalid_type($value, string $expected_type): self {
|
||||
return new static(self::message($value, null, "type", null, " is invalid, expected $expected_type"));
|
||||
}
|
||||
|
||||
static final function invalid_class($class, string $expected_class): self {
|
||||
if (is_object($class)) $class = get_class($class);
|
||||
return new static(self::message($class, null, "class", null, " is invalid, expected $expected_class"));
|
||||
}
|
||||
|
||||
static final function forbidden($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||
return new static(self::message($value, $message, $kind, $prefix, " is forbidden"));
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,13 @@ use nulib\A;
|
||||
use nulib\app\cli\Application;
|
||||
use nulib\app\config\ProfileManager;
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\ExitError;
|
||||
use nulib\os\path;
|
||||
use nulib\os\sh;
|
||||
use nulib\php\func;
|
||||
use nulib\ref\ref_profiles;
|
||||
use nulib\str;
|
||||
use nulib\ValueException;
|
||||
|
||||
class app {
|
||||
private static function isa_Application($app): bool {
|
||||
@ -59,7 +59,7 @@ class app {
|
||||
} elseif (is_array($app)) {
|
||||
$params = $app;
|
||||
} else {
|
||||
throw ValueException::invalid_type($app, Application::class);
|
||||
throw exceptions::invalid_type($app, "app", Application::class);
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
@ -410,7 +410,7 @@ class app {
|
||||
function fencedJoin(string $basedir, ?string ...$paths): string {
|
||||
$path = path::reljoin($basedir, ...$paths);
|
||||
if (!path::is_within($path, $basedir)) {
|
||||
throw ValueException::invalid_value($path, "path");
|
||||
throw exceptions::invalid_type($path, $kind, "path");
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ use stdClass;
|
||||
abstract class AbstractArgsParser {
|
||||
protected function notEnoughArgs(int $needed, ?string $arg=null): ArgsException {
|
||||
if ($arg !== null) $arg .= ": ";
|
||||
return new ArgsException("${arg}nécessite $needed argument(s) supplémentaires");
|
||||
$reason = $arg._exceptions::missing_value_message($needed);
|
||||
return _exceptions::missing_value(null, null, $reason);
|
||||
}
|
||||
|
||||
protected function checkEnoughArgs(?string $option, int $count): void {
|
||||
@ -15,16 +16,17 @@ abstract class AbstractArgsParser {
|
||||
|
||||
protected function tooManyArgs(int $count, int $expected, ?string $arg=null): ArgsException {
|
||||
if ($arg !== null) $arg .= ": ";
|
||||
return new ArgsException("${arg}trop d'arguments (attendu $expected, reçu $count)");
|
||||
$reason = $arg._exceptions::unexpected_value_message($count - $expected);
|
||||
return _exceptions::unexpected_value(null, null, $reason);
|
||||
}
|
||||
|
||||
protected function invalidArg(string $arg): ArgsException {
|
||||
return new ArgsException("$arg: argument invalide");
|
||||
return _exceptions::invalid_value($arg);
|
||||
}
|
||||
|
||||
protected function ambiguousArg(string $arg, array $candidates): ArgsException {
|
||||
$candidates = implode(", ", $candidates);
|
||||
return new ArgsException("$arg: argument ambigû (les valeurs possibles sont $candidates)");
|
||||
return new ArgsException("$arg: cet argument est ambigû (les valeurs possibles sont $candidates)");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,11 +147,11 @@ class Aodef {
|
||||
protected function processExtends(Aolist $argdefs): void {
|
||||
$option = $this->extends;
|
||||
if ($option === null) {
|
||||
throw ArgsException::missing("extends", "destination arg");
|
||||
throw _exceptions::null_value("extends", "il doit spécifier l'argument destination");
|
||||
}
|
||||
$dest = $argdefs->get($option);
|
||||
if ($dest === null) {
|
||||
throw ArgsException::invalid($option, "destination arg");
|
||||
throw _exceptions::invalid_value($option, "extends", "il doit spécifier un argument valide");
|
||||
}
|
||||
|
||||
if ($this->ensureArray !== null) $dest->ensureArray = $this->ensureArray;
|
||||
@ -178,7 +178,7 @@ class Aodef {
|
||||
$args = $ms[2] ?? null;
|
||||
$option = "--$name";
|
||||
} else {
|
||||
throw ArgsException::invalid($option, "long option");
|
||||
throw _exceptions::invalid_value($option, "cette option longue");
|
||||
}
|
||||
} elseif (substr($option, 0, 1) === "-") {
|
||||
$type = self::TYPE_SHORT;
|
||||
@ -187,7 +187,7 @@ class Aodef {
|
||||
$args = $ms[2] ?? null;
|
||||
$option = "-$name";
|
||||
} else {
|
||||
throw ArgsException::invalid($option, "short option");
|
||||
throw _exceptions::invalid_value($option, " cette option courte");
|
||||
}
|
||||
} else {
|
||||
$type = self::TYPE_COMMAND;
|
||||
@ -196,7 +196,7 @@ class Aodef {
|
||||
$args = null;
|
||||
$option = "$name";
|
||||
} else {
|
||||
throw ArgsException::invalid($option, "command");
|
||||
throw _exceptions::invalid_value($option, "cette commande");
|
||||
}
|
||||
}
|
||||
if ($args === ":") {
|
||||
@ -347,7 +347,7 @@ class Aodef {
|
||||
$haveNull = true;
|
||||
break;
|
||||
} else {
|
||||
throw ArgsException::invalid("$desc: $arg", "option arg");
|
||||
throw _exceptions::invalid_value("$desc: $arg", $kind, "ce n'est pas un argument valide");
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,7 +366,7 @@ class Aodef {
|
||||
$haveNull = true;
|
||||
break;
|
||||
} else {
|
||||
throw ArgsException::invalid("$desc: $arg", "option arg");
|
||||
throw _exceptions::invalid_value("$desc: $arg", $kind, "ce n'est pas un argument valide");
|
||||
}
|
||||
}
|
||||
if (!$haveOpt) $haveNull = true;
|
||||
@ -519,7 +519,7 @@ class Aodef {
|
||||
case "--set-args": $this->actionSetArgs($dest, $value); break;
|
||||
case "--set-command": $this->actionSetCommand($dest, $value); break;
|
||||
case "--show-help": $parser->actionPrintHelp($arg); break;
|
||||
default: throw ArgsException::invalid($this->action, "arg action");
|
||||
default: throw _exceptions::invalid_value($this->action, $kind, "action non supportée");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ class Aogroup extends Aolist {
|
||||
function __construct(array $defs, bool $setup=false) {
|
||||
$marker = A::pop($defs, 0);
|
||||
if ($marker !== "group") {
|
||||
throw ArgsException::invalid(null, "group");
|
||||
throw _exceptions::missing_value(null, $kind, "ce n'est pas un groupe valide");
|
||||
}
|
||||
# réordonner les clés numériques
|
||||
$defs = array_merge($defs);
|
||||
|
@ -1,20 +1,7 @@
|
||||
<?php
|
||||
namespace nulib\app\args;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nulib\UserException;
|
||||
|
||||
class ArgsException extends ValueException {
|
||||
static function missing(?string $value, string $kind): self {
|
||||
$msg = $value;
|
||||
if ($msg !== null) $msg .= ": ";
|
||||
$msg .= "missing $kind";
|
||||
throw new self($msg);
|
||||
}
|
||||
|
||||
static function invalid(?string $value, string $kind): self {
|
||||
$msg = $value;
|
||||
if ($msg !== null) $msg .= ": ";
|
||||
$msg .= "invalid $kind";
|
||||
throw new self($msg);
|
||||
}
|
||||
class ArgsException extends UserException {
|
||||
}
|
||||
|
10
php/src/app/args/_exceptions.php
Normal file
10
php/src/app/args/_exceptions.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace nulib\app\args;
|
||||
|
||||
use nulib\exceptions;
|
||||
|
||||
class _exceptions extends exceptions {
|
||||
const EXCEPTION = ArgsException::class;
|
||||
|
||||
const WORD = "masc:l'argument#s";
|
||||
}
|
@ -4,8 +4,8 @@ namespace nulib\app;
|
||||
use nulib\app\config\ConfigManager;
|
||||
use nulib\app\config\JsonConfig;
|
||||
use nulib\app\config\YamlConfig;
|
||||
use nulib\exceptions;
|
||||
use nulib\os\path;
|
||||
use nulib\ValueException;
|
||||
|
||||
/**
|
||||
* Class config: gestion de la configuration de l'application
|
||||
@ -37,7 +37,7 @@ class config {
|
||||
} elseif ($ext === ".json") {
|
||||
$config = new JsonConfig($file);
|
||||
} else {
|
||||
throw ValueException::invalid_value($file, "config file");
|
||||
throw exceptions::invalid_type($file, $kind, "config file");
|
||||
}
|
||||
self::add($config);
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ namespace nulib\app\config;
|
||||
use nulib\A;
|
||||
use nulib\app\app;
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
use ReflectionClass;
|
||||
|
||||
class ConfigManager {
|
||||
@ -93,7 +93,7 @@ class ConfigManager {
|
||||
} elseif (is_array($config)) {
|
||||
$config = new ArrayConfig($config);
|
||||
} elseif (!($config instanceof IConfig)) {
|
||||
throw ValueException::invalid_type($config, "array|IConfig");
|
||||
throw exceptions::invalid_type($config, "config", ["array", IConfig::class]);
|
||||
}
|
||||
|
||||
if (!$inProfiles) $inProfiles = [IConfig::PROFILE_ALL];
|
||||
|
2
php/src/cache/CacheFile.php
vendored
2
php/src/cache/CacheFile.php
vendored
@ -36,7 +36,7 @@ class CacheFile extends SharedFile {
|
||||
yield from $data;
|
||||
});
|
||||
} else {
|
||||
throw ValueException::invalid_type($source, CacheData::class);
|
||||
throw exceptions::invalid_type($source, "source", CacheData::class);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -166,6 +166,12 @@ class cv {
|
||||
|
||||
#############################################################################
|
||||
|
||||
/** retourner $value si elle est non nulle, lancer une exception sinon */
|
||||
static final function not_null($value, ?string $kind=null) {
|
||||
if ($value !== null) return $value;
|
||||
throw exceptions::null_value($kind);
|
||||
}
|
||||
|
||||
/** vérifier si $value est un booléen, sinon retourner null */
|
||||
static final function check_bool($value): ?bool {
|
||||
return is_bool($value)? $value: null;
|
||||
@ -196,7 +202,7 @@ class cv {
|
||||
$index = is_int($value)? $value : null;
|
||||
$key = is_string($value)? $value : null;
|
||||
if ($index === null && $key === null && $throw_exception) {
|
||||
throw ValueException::invalid_kind($value, "key", $prefix);
|
||||
throw exceptions::invalid_type($value, $kind, "key", $prefix);
|
||||
} else {
|
||||
return [$index, $key];
|
||||
}
|
||||
@ -213,7 +219,7 @@ class cv {
|
||||
$scalar = !is_bool($value) && is_scalar($value)? $value : null;
|
||||
$array = is_array($value)? $value : null;
|
||||
if ($bool === null && $scalar === null && $array === null && $throw_exception) {
|
||||
throw ValueException::invalid_kind($value, "value", $prefix);
|
||||
throw exceptions::invalid_type($value, $kind, ["bool", "scalar", "array"], $prefix);
|
||||
} else {
|
||||
return [$bool, $scalar, $array];
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
namespace nulib\db;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
@ -66,7 +66,7 @@ class Capacitor implements ITransactor {
|
||||
if ($channel instanceof CapacitorChannel) {
|
||||
$this->subChannels[] = $channel;
|
||||
} else {
|
||||
throw ValueException::invalid_type($channel, CapacitorChannel::class);
|
||||
throw exceptions::invalid_type($channel, "channel", CapacitorChannel::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ use nulib\A;
|
||||
use nulib\cl;
|
||||
use nulib\cv;
|
||||
use nulib\db\_private\_migration;
|
||||
use nulib\exceptions;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
@ -596,7 +596,7 @@ abstract class CapacitorStorage {
|
||||
* si $filter n'est pas un tableau, il est transformé en ["id_" => $filter]
|
||||
*/
|
||||
function _one(CapacitorChannel $channel, $filter, ?array $mergeQuery=null): ?array {
|
||||
if ($filter === null) throw ValueException::null("filter");
|
||||
if ($filter === null) throw exceptions::null_value("filter");
|
||||
$this->_create($channel);
|
||||
$this->verifixFilter($channel, $filter);
|
||||
$raw = $this->db()->one(cl::merge([
|
||||
|
@ -1,14 +1,14 @@
|
||||
<?php
|
||||
namespace nulib\db\_private;
|
||||
|
||||
use nulib\ValueException;
|
||||
use nulib\exceptions;
|
||||
|
||||
abstract class _base extends _common {
|
||||
protected static function verifix(&$sql, ?array &$bindings=null, ?array &$meta=null): void {
|
||||
if (is_array($sql)) {
|
||||
$prefix = $sql[0] ?? null;
|
||||
if ($prefix === null) {
|
||||
throw new ValueException("requête invalide");
|
||||
throw exceptions::invalid_type($sql, "cette requête sql");
|
||||
} elseif (_create::isa($prefix)) {
|
||||
$sql = _create::parse($sql, $bindings);
|
||||
$meta = ["isa" => "create", "type" => "ddl"];
|
||||
@ -28,7 +28,7 @@ abstract class _base extends _common {
|
||||
$sql = _generic::parse($sql, $bindings);
|
||||
$meta = ["isa" => "generic", "type" => null];
|
||||
} else {
|
||||
throw ValueException::invalid_kind($sql, "query");
|
||||
throw exceptions::invalid_type($sql, "cette requête sql");
|
||||
}
|
||||
} else {
|
||||
if (!is_string($sql)) $sql = strval($sql);
|
||||
|
@ -2,8 +2,8 @@
|
||||
namespace nulib\db\_private;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\str;
|
||||
use nulib\ValueException;
|
||||
|
||||
class _common {
|
||||
protected static function consume(string $pattern, string &$string, ?array &$ms=null): bool {
|
||||
@ -249,7 +249,7 @@ class _common {
|
||||
protected static function check_eof(string $tmpsql, string $usersql): void {
|
||||
self::consume(';\s*', $tmpsql);
|
||||
if ($tmpsql) {
|
||||
throw new ValueException("unexpected value at end: $usersql");
|
||||
throw exceptions::invalid_value($usersql, "cette requête sql");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
namespace nulib\db\_private;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\ValueException;
|
||||
use nulib\exceptions;
|
||||
|
||||
class _insert extends _common {
|
||||
const SCHEMA = [
|
||||
@ -44,7 +44,7 @@ class _insert extends _common {
|
||||
} elseif ($into !== null) {
|
||||
$sql[] = $into;
|
||||
} else {
|
||||
throw new ValueException("expected table name: $usersql");
|
||||
throw exceptions::invalid_value($usersql, "cette requête sql", "il faut spécifier la table");
|
||||
}
|
||||
|
||||
## cols & values
|
||||
|
@ -2,8 +2,8 @@
|
||||
namespace nulib\db\_private;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\str;
|
||||
use nulib\ValueException;
|
||||
|
||||
class _select extends _common {
|
||||
const SCHEMA = [
|
||||
@ -101,7 +101,7 @@ class _select extends _common {
|
||||
$sql[] = "from";
|
||||
$sql[] = $from;
|
||||
} else {
|
||||
throw new ValueException("expected table name: $usersql");
|
||||
throw exceptions::invalid_value($usersql, "cette requête sql", "il faut spécifier la table");
|
||||
}
|
||||
|
||||
## where
|
||||
|
@ -6,8 +6,8 @@ use nulib\db\_private\_config;
|
||||
use nulib\db\_private\Tvalues;
|
||||
use nulib\db\IDatabase;
|
||||
use nulib\db\ITransactor;
|
||||
use nulib\exceptions;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
|
||||
class Pdo implements IDatabase {
|
||||
use Tvalues;
|
||||
@ -203,7 +203,7 @@ class Pdo implements IDatabase {
|
||||
$this->transactors[] = $transactor;
|
||||
$transactor->willUpdate();
|
||||
} else {
|
||||
throw ValueException::invalid_type($transactor, ITransactor::class);
|
||||
throw exceptions::invalid_type($transactor, "transactor", ITransactor::class);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
|
@ -6,8 +6,8 @@ use nulib\db\_private\_config;
|
||||
use nulib\db\_private\Tvalues;
|
||||
use nulib\db\IDatabase;
|
||||
use nulib\db\ITransactor;
|
||||
use nulib\exceptions;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
|
||||
class Pgsql implements IDatabase {
|
||||
use Tvalues;
|
||||
@ -253,7 +253,7 @@ class Pgsql implements IDatabase {
|
||||
$this->transactors[] = $transactor;
|
||||
$transactor->willUpdate();
|
||||
} else {
|
||||
throw ValueException::invalid_type($transactor, ITransactor::class);
|
||||
throw exceptions::invalid_type($transactor, "transactor", ITransactor::class);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
|
@ -7,8 +7,8 @@ use nulib\db\_private\_config;
|
||||
use nulib\db\_private\Tvalues;
|
||||
use nulib\db\IDatabase;
|
||||
use nulib\db\ITransactor;
|
||||
use nulib\exceptions;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
use SQLite3;
|
||||
use SQLite3Result;
|
||||
use SQLite3Stmt;
|
||||
@ -254,7 +254,7 @@ class Sqlite implements IDatabase {
|
||||
$this->transactors[] = $transactor;
|
||||
$transactor->willUpdate();
|
||||
} else {
|
||||
throw ValueException::invalid_type($transactor, ITransactor::class);
|
||||
throw exceptions::invalid_type($transactor, "transactor", ITransactor::class);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
|
@ -1,12 +1,82 @@
|
||||
<?php
|
||||
namespace nulib;
|
||||
|
||||
use nulib\php\content\c;
|
||||
use nulib\text\Word;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class exceptions: répertoire d'exceptions normalisées
|
||||
*/
|
||||
class exceptions {
|
||||
/** @param Throwable|ExceptionShadow $e */
|
||||
public static function get_user_message($e): ?string {
|
||||
if ($e instanceof UserException) $userMessage = $e->getUserMessage();
|
||||
elseif ($e instanceof ExceptionShadow) $userMessage = $e->getUserMessage();
|
||||
else return null;
|
||||
return c::to_string($userMessage);
|
||||
}
|
||||
|
||||
/** @param Throwable|ExceptionShadow $e */
|
||||
public static function get_tech_message($e): ?string {
|
||||
if ($e instanceof UserException) $techMessage = $e->getTechMessage();
|
||||
elseif ($e instanceof ExceptionShadow) $techMessage = $e->getTechMessage();
|
||||
else return null;
|
||||
return c::to_string($techMessage);
|
||||
}
|
||||
|
||||
/** @param Throwable|ExceptionShadow $e */
|
||||
public static function get_message($e): string {
|
||||
if ($e instanceof UserException) $userMessage = $e->getUserMessage();
|
||||
elseif ($e instanceof ExceptionShadow) $userMessage = $e->getUserMessage();
|
||||
else return $e->getMessage();
|
||||
return c::to_string($userMessage);
|
||||
}
|
||||
|
||||
/** @param Throwable|ExceptionShadow $e */
|
||||
public static final function get_summary($e, bool $includePrevious = true): string {
|
||||
$parts = [];
|
||||
$first = true;
|
||||
while ($e !== null) {
|
||||
$message = self::get_message($e);
|
||||
if (!$message) $message = "(no message)";
|
||||
$techMessage = self::get_tech_message($e);
|
||||
if ($techMessage) $message .= " |$techMessage|";
|
||||
if ($first) $first = false;
|
||||
else $parts[] = ", caused by ";
|
||||
if ($e instanceof ExceptionShadow) $class = $e->getClass();
|
||||
else $class = get_class($e);
|
||||
$parts[] = "$class: $message";
|
||||
$e = $includePrevious ? $e->getPrevious() : null;
|
||||
}
|
||||
return implode("", $parts);
|
||||
}
|
||||
|
||||
/** @param Throwable|ExceptionShadow $e */
|
||||
public 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, false);
|
||||
}
|
||||
$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 EXCEPTION = ValueException::class;
|
||||
|
||||
const WORD = "la valeur#s";
|
||||
|
||||
protected static Word $word;
|
||||
@ -15,23 +85,59 @@ class exceptions {
|
||||
return self::$word ??= new Word(static::WORD);
|
||||
}
|
||||
|
||||
static function value($value): string {
|
||||
if (is_object($value)) {
|
||||
return "<".get_class($value).">";
|
||||
} elseif (is_array($value)) {
|
||||
$values = $value;
|
||||
$parts = [];
|
||||
$index = 0;
|
||||
foreach ($values as $key => $value) {
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
$parts[] = self::value($value);
|
||||
} else {
|
||||
$parts[] = "$key=>".self::value($value);
|
||||
}
|
||||
}
|
||||
return "[".implode(", ", $parts)."]";
|
||||
} elseif (is_string($value)) {
|
||||
return $value;
|
||||
} else {
|
||||
return var_export($value, true);
|
||||
}
|
||||
}
|
||||
|
||||
static function generic($value, ?string $kind, ?string $cause, ?string $reason=null, ?Throwable $previous=null): UserException {
|
||||
$msg = "";
|
||||
if ($value !== null) {
|
||||
$msg .= self::value($value);
|
||||
$msg .= ": ";
|
||||
}
|
||||
$kind ??= self::word()->_ce();
|
||||
$msg .= $kind;
|
||||
$cause ??= "est invalide";
|
||||
if ($cause) $msg .= " $cause";
|
||||
if ($reason) $msg .= ": $reason";
|
||||
$code = $previous !== null? $previous->getCode(): 0;
|
||||
$class = static::EXCEPTION;
|
||||
return new $class($msg, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* indiquer qu'une valeur est invalide pour une raison générique
|
||||
*/
|
||||
static function invalid_value($value, ?string $reason=null): UserException {
|
||||
$msg = var_export($value, true);
|
||||
$msg .= self::word()->_ce();
|
||||
$msg .= " est invalide";
|
||||
if ($reason) $msg .= ": $reason";
|
||||
return new UserException($msg);
|
||||
static function invalid_value($value, ?string $kind=null, ?string $reason=null, ?Throwable $previous=null): UserException {
|
||||
return self::generic($value, $kind, null, $reason, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* spécialisation de {@link self::invalid_value()} qui permet d'indiquer les
|
||||
* types attendus
|
||||
*/
|
||||
static function invalid_type($value, $expectedTypes=null): UserException {
|
||||
$pronom = self::word()->pronom();
|
||||
static function invalid_type($value, ?string $kind=null, $expectedTypes=null, ?Throwable $previous=null): UserException {
|
||||
if ($kind !== null) $pronom = "il";
|
||||
else $pronom = self::word()->pronom();
|
||||
$expectedTypes = cl::withn($expectedTypes);
|
||||
if (!$expectedTypes) {
|
||||
$reason = null;
|
||||
@ -41,11 +147,12 @@ class exceptions {
|
||||
$reason = "$pronom doit être d'un des types suivants: ";
|
||||
}
|
||||
$reason .= implode(", ", $expectedTypes);
|
||||
return self::invalid_value($value, $reason);
|
||||
return self::invalid_value($value, $kind, $reason, $previous);
|
||||
}
|
||||
|
||||
static function invalid_format($value, $expectedFormats=null): UserException {
|
||||
$pronom = self::word()->pronom();
|
||||
static function invalid_format($value, ?string $kind=null, $expectedFormats=null, ?Throwable $previous=null): UserException {
|
||||
if ($kind !== null) $pronom = "il";
|
||||
else $pronom = self::word()->pronom();
|
||||
$expectedFormats = cl::withn($expectedFormats);
|
||||
if (!$expectedFormats) {
|
||||
$reason = null;
|
||||
@ -55,51 +162,90 @@ class exceptions {
|
||||
$reason = "$pronom doit être dans l'un des formats suivants: ";
|
||||
}
|
||||
$reason .= implode(", ", $expectedFormats);
|
||||
return self::invalid_value($value, $reason);
|
||||
return self::invalid_value($value, $kind, $reason, $previous);
|
||||
}
|
||||
|
||||
static function out_of_range($value, ?int $min=null, ?int $max=null): UserException {
|
||||
$pronom = self::word()->pronom();
|
||||
static function forbidden_value($value, ?string $kind=null, $allowedValues=null, ?Throwable $previous=null): UserException {
|
||||
if ($kind !== null) $pronom = "il";
|
||||
else $pronom = self::word()->pronom();
|
||||
$allowedValues = cl::withn($allowedValues);
|
||||
if (!$allowedValues) $reason = null;
|
||||
else $reason = "$pronom doit faire partie de cette liste: ";
|
||||
$reason .= implode(", ", $allowedValues);
|
||||
return self::invalid_value($value, $kind, $reason, $previous);
|
||||
}
|
||||
|
||||
static function out_of_range($value, ?string $kind=null, ?int $min=null, ?int $max=null, ?Throwable $previous=null): UserException {
|
||||
if ($kind !== null) {
|
||||
$pronom = "il";
|
||||
$compris = "compris";
|
||||
$superieur = "supérieur";
|
||||
$inferieur = "inférieur";
|
||||
} else {
|
||||
$word = self::word();
|
||||
$pronom = $word->pronom();
|
||||
$compris = $word->isFeminin()? "comprise": "compris";
|
||||
$superieur = $word->isFeminin()? "supérieure": "supérieur";
|
||||
$inferieur = $word->isFeminin()? "inférieure": "inférieur";
|
||||
}
|
||||
if ($min !== null && $max !== null) {
|
||||
$reason = "$pronom doit être compris entre $min et $max";
|
||||
$reason = "$pronom doit être $compris entre $min et $max";
|
||||
} else if ($min !== null) {
|
||||
$reason = "$pronom doit être supérieur à $min";
|
||||
$reason = "$pronom doit être $superieur à $min";
|
||||
} elseif ($max !== null) {
|
||||
$reason = "$pronom doit être inférieur à $max";
|
||||
$reason = "$pronom doit être $inferieur à $max";
|
||||
} else {
|
||||
$reason = null;
|
||||
}
|
||||
return self::invalid_value($value, $reason);
|
||||
return self::invalid_value($value, $kind, $reason, $previous);
|
||||
}
|
||||
|
||||
static function null_value(?string $reason=null): UserException {
|
||||
$msg = self::word()->_ce();
|
||||
$msg .= " ne doit pas être nulle";
|
||||
if ($reason) $msg .= ": $reason";
|
||||
return new UserException($msg);
|
||||
static function null_value(?string $kind=null, ?string $reason=null, ?Throwable $previous=null): UserException {
|
||||
if ($kind !== null) $nul = "null";
|
||||
else $nul = self::word()->isFeminin()? "nulle": "nul";
|
||||
return self::generic(null, $kind, "ne doit pas être $nul", $reason, $previous);
|
||||
}
|
||||
|
||||
static function missing_value_message(?int $amount=null, ?string $kind=null): string {
|
||||
$message = "il manque ";
|
||||
if ($kind !== null) {
|
||||
if ($amount !== null) $message = "$amount $kind";
|
||||
else $message = $kind;
|
||||
} else {
|
||||
if ($amount !== null) $message .= self::word()->q($amount);
|
||||
else $message .= self::word()->_un();
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* indiquer qu'une valeur est manquante
|
||||
*/
|
||||
static function missing_value(?int $amout=null, ?string $reason=null): UserException {
|
||||
$msg = "il manque ";
|
||||
if ($amout !== null) {
|
||||
$msg .= self::word()->q($amout);
|
||||
static function missing_value(?int $amount=null, ?string $kind=null, ?string $reason=null, ?Throwable $previous=null): UserException {
|
||||
$reason ??= self::missing_value_message($amount, $kind);
|
||||
$class = static::EXCEPTION;
|
||||
return new $class($reason, null, $previous);
|
||||
}
|
||||
|
||||
static function unexpected_value_message(?int $amount=null, ?string $kind=null): string {
|
||||
if ($amount !== null) {
|
||||
if ($kind !== null) $kind = "$amount $kind";
|
||||
else $kind = self::word()->q($amount);
|
||||
$message = "il y a $kind en trop";
|
||||
} else {
|
||||
$msg .= self::word()->_le();
|
||||
if ($kind !== null) $kind = "de $kind";
|
||||
else $kind = self::word()->_de(2);
|
||||
$message = "il y a trop $kind";
|
||||
}
|
||||
if ($reason) $msg .= ": $reason";
|
||||
return new UserException($msg);
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* indiquer qu'une valeur est en trop
|
||||
*/
|
||||
static function unexpected_value(?string $reason=null): UserException {
|
||||
$msg = "il y a trop ";
|
||||
$msg .= self::word()->_de(2);
|
||||
if ($reason) $msg .= ": $reason";
|
||||
return new UserException($msg);
|
||||
static function unexpected_value(?int $amount=null, ?string $kind=null, ?string $reason=null, ?Throwable $previous=null): UserException {
|
||||
$reason ??= self::unexpected_value_message($amount, $kind);
|
||||
$class = static::EXCEPTION;
|
||||
return new $class($reason, null, $previous);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace nulib\file;
|
||||
|
||||
use nulib\exceptions;
|
||||
use nulib\ValueException;
|
||||
|
||||
class SharedFile extends FileWriter {
|
||||
@ -9,7 +10,7 @@ class SharedFile extends FileWriter {
|
||||
const DEFAULT_MODE = "c+b";
|
||||
|
||||
function __construct($file, ?string $mode=null, ?bool $throwOnError=null, ?bool $allowLocking=null) {
|
||||
if ($file === null) throw ValueException::null("file");
|
||||
if ($file === null) throw exceptions::null_value("file");
|
||||
parent::__construct($file, $mode, $throwOnError, $allowLocking);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace nulib\file;
|
||||
|
||||
use nulib\exceptions;
|
||||
use nulib\file\csv\csv_flavours;
|
||||
use nulib\NoMoreDataException;
|
||||
use nulib\os\EOFException;
|
||||
@ -61,7 +62,7 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
||||
protected $stat;
|
||||
|
||||
function __construct($fd, bool $close=true, ?bool $throwOnError=null, ?bool $useLocking=null) {
|
||||
if ($fd === null) throw ValueException::null("resource");
|
||||
if ($fd === null) throw exceptions::null_value("resource");
|
||||
$this->fd = $fd;
|
||||
$this->close = $close;
|
||||
$this->throwOnError = $throwOnError ?? static::THROW_ON_ERROR;
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace nulib\file\tab;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\file\csv\CsvBuilder;
|
||||
use nulib\file\web\Upload;
|
||||
use nulib\os\path;
|
||||
@ -32,7 +33,7 @@ trait TAbstractBuilder {
|
||||
} elseif (is_array($builder)) {
|
||||
$params = cl::merge($builder, $params);
|
||||
} elseif ($builder !== null) {
|
||||
throw ValueException::invalid_type($builder, self::class);
|
||||
throw exceptions::invalid_type($builder, "builder", self::class);
|
||||
}
|
||||
|
||||
$output = $params["output"] ?? null;
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace nulib\file\tab;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\file\csv\CsvReader;
|
||||
use nulib\file\web\Upload;
|
||||
use nulib\os\path;
|
||||
@ -31,7 +32,7 @@ trait TAbstractReader {
|
||||
} elseif (is_array($reader)) {
|
||||
$params = cl::merge($reader, $params);
|
||||
} elseif ($reader !== null) {
|
||||
throw ValueException::invalid_type($reader, self::class);
|
||||
throw exceptions::invalid_type($reader, "reader", self::class);
|
||||
}
|
||||
|
||||
$input = $params["input"] ?? null;
|
||||
|
@ -19,8 +19,8 @@ class MailTemplate {
|
||||
$texprs = $mail["exprs"] ?? [];
|
||||
|
||||
$this->el = new ExpressionLanguage();
|
||||
ValueException::check_null($this->subject = $tsubject, "subject");
|
||||
ValueException::check_null($this->body = $tbody, "body");
|
||||
$this->subject = cv::not_null($tsubject, "subject");
|
||||
$this->body = cv::not_null($tbody, "body");
|
||||
$exprs = [];
|
||||
# Commencer par extraire les expressions de la forme {name}
|
||||
if (preg_match_all('/\{([a-zA-Z_][a-zA-Z0-9_.-]*)}/', $this->body, $mss, PREG_SET_ORDER)) {
|
||||
|
@ -4,6 +4,7 @@ namespace nulib\mail;
|
||||
use nulib\app\config;
|
||||
use nulib\cl;
|
||||
use nulib\cv;
|
||||
use nulib\exceptions;
|
||||
use nulib\output\msg;
|
||||
use nulib\str;
|
||||
use nulib\ValueException;
|
||||
@ -90,7 +91,7 @@ class mailer {
|
||||
$host = $params["host"] ?? null;
|
||||
$port = $params["port"] ?? 25;
|
||||
if ($host === null) {
|
||||
throw new ValueException("mail host is required");
|
||||
throw exceptions::null_value("host");
|
||||
}
|
||||
msg::debug("new PHPMailer using SMTP to $host:$port");
|
||||
$mailer->isSMTP();
|
||||
@ -106,7 +107,7 @@ class mailer {
|
||||
$mailer->isSendmail();
|
||||
break;
|
||||
default:
|
||||
throw ValueException::invalid_value($backend, "mailer backend");
|
||||
throw exceptions::forbidden_value($backend, "backend", ["smtp", "phpmail", "sendmail"]);
|
||||
}
|
||||
# debug
|
||||
$debug = $params["debug"] ?? SMTP::DEBUG_OFF;
|
||||
@ -114,7 +115,7 @@ class mailer {
|
||||
if ($debug < SMTP::DEBUG_OFF) $debug = SMTP::DEBUG_OFF;
|
||||
elseif ($debug > SMTP::DEBUG_LOWLEVEL) $debug = SMTP::DEBUG_LOWLEVEL;
|
||||
} elseif (!self::is_bool($debug)) {
|
||||
throw ValueException::invalid_value($debug, "debug mode");
|
||||
throw exceptions::invalid_type($debug, "debug", ["int", "bool"]);
|
||||
}
|
||||
$mailer->SMTPDebug = $debug;
|
||||
# auth, username, password
|
||||
@ -144,7 +145,10 @@ class mailer {
|
||||
$mailer->SMTPSecure = $secure;
|
||||
break;
|
||||
default:
|
||||
throw ValueException::invalid_value($secure, "encryption mode");
|
||||
throw exceptions::forbidden_value($secure, "secure", [
|
||||
PHPMailer::ENCRYPTION_SMTPS,
|
||||
PHPMailer::ENCRYPTION_STARTTLS,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,7 +190,7 @@ class mailer {
|
||||
$tos = str::join(",", $tos);
|
||||
msg::debug("Sending to $tos");
|
||||
if (!$mailer->send()) {
|
||||
throw new MailerException("Une erreur s'est produite pendant l'envoi du mail", $mailer->ErrorInfo);
|
||||
throw new MailerException("erreur d'envoi du mail", $mailer->ErrorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace nulib\output;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\str;
|
||||
use nulib\ValueException;
|
||||
|
||||
@ -15,7 +16,7 @@ abstract class _messenger {
|
||||
|
||||
static function set_messenger_class(string $msg_class, ?array $params=null) {
|
||||
if (!is_subclass_of($msg_class, IMessenger::class)) {
|
||||
throw ValueException::invalid_class($msg_class, IMessenger::class);
|
||||
throw exceptions::invalid_type($msg_class, $kind, IMessenger::class);
|
||||
}
|
||||
static::set_messenger(new $msg_class($params));
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace nulib\output;
|
||||
|
||||
use nulib\app\app;
|
||||
use nulib\exceptions;
|
||||
use nulib\output\std\ProxyMessenger;
|
||||
use nulib\ValueException;
|
||||
|
||||
@ -63,7 +64,7 @@ class console extends _messenger {
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
throw ValueException::invalid_value($verbosity, "verbosity");
|
||||
throw exceptions::forbidden_value($verbosity, $kind, ["silent", "quiet", "normal", "verbose", "debug"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ namespace nulib\output\std;
|
||||
use Exception;
|
||||
use nulib\A;
|
||||
use nulib\cl;
|
||||
use nulib\exceptions;
|
||||
use nulib\ExceptionShadow;
|
||||
use nulib\output\IMessenger;
|
||||
use nulib\UserException;
|
||||
@ -236,9 +237,11 @@ class StdMessenger implements _IMessenger {
|
||||
return $indentLevel;
|
||||
}
|
||||
|
||||
protected function _printTitle(?string $linePrefix, int $level,
|
||||
string $type, $content,
|
||||
int $indentLevel, StdOutput $out): void {
|
||||
protected function _printTitle(
|
||||
?string $linePrefix, int $level,
|
||||
string $type, $content,
|
||||
int $indentLevel, StdOutput $out
|
||||
): void {
|
||||
$prefixes = self::GENERIC_PREFIXES[$level][$type];
|
||||
if ($prefixes[0]) $out->print();
|
||||
$content = cl::with($content);
|
||||
@ -284,10 +287,12 @@ class StdMessenger implements _IMessenger {
|
||||
}
|
||||
}
|
||||
|
||||
protected function _printAction(?string $linePrefix, int $level,
|
||||
bool $printContent, $content,
|
||||
bool $printResult, ?bool $rsuccess, $rcontent,
|
||||
int $indentLevel, StdOutput $out): void {
|
||||
protected function _printAction(
|
||||
?string $linePrefix, int $level,
|
||||
bool $printContent, $content,
|
||||
bool $printResult, ?bool $rsuccess, $rcontent,
|
||||
int $indentLevel, StdOutput $out
|
||||
): void {
|
||||
$color = $out->isColor();
|
||||
if ($rsuccess === true) $type = "success";
|
||||
elseif ($rsuccess === false) $type = "failure";
|
||||
@ -357,9 +362,11 @@ class StdMessenger implements _IMessenger {
|
||||
}
|
||||
}
|
||||
|
||||
protected function _printGeneric(?string $linePrefix, int $level,
|
||||
string $type, $content,
|
||||
int $indentLevel, StdOutput $out): void {
|
||||
protected function _printGeneric(
|
||||
?string $linePrefix, int $level,
|
||||
string $type, $content,
|
||||
int $indentLevel, StdOutput $out
|
||||
): void {
|
||||
$prefixes = self::GENERIC_PREFIXES[$level][$type];
|
||||
$content = cl::with($content);
|
||||
if ($out->isColor()) {
|
||||
@ -390,7 +397,11 @@ class StdMessenger implements _IMessenger {
|
||||
}
|
||||
}
|
||||
|
||||
protected function _printGenericOrException(?int $level, string $type, $content, int $indentLevel, StdOutput $out): void {
|
||||
protected function _printGenericOrException(
|
||||
?int $level,
|
||||
string $type, $content,
|
||||
int $indentLevel, StdOutput $out
|
||||
): void {
|
||||
$linePrefix = $this->getLinePrefix();
|
||||
# si $content contient des exceptions, les afficher avec un level moindre
|
||||
$exceptions = null;
|
||||
@ -421,27 +432,18 @@ class StdMessenger implements _IMessenger {
|
||||
$level1 = $this->decrLevel($level);
|
||||
$showTraceback = $this->checkLevel($level1);
|
||||
foreach ($exceptions as $exception) {
|
||||
# tout d'abord userMessage
|
||||
if ($exception instanceof UserException) {
|
||||
$userMessage = UserException::get_user_message($exception);
|
||||
$userMessage ??= "Une erreur technique s'est produite";
|
||||
$showSummary = true;
|
||||
} else {
|
||||
$userMessage = UserException::get_summary($exception);
|
||||
$showSummary = false;
|
||||
}
|
||||
if ($userMessage !== null && $showContent) {
|
||||
# tout d'abord message
|
||||
$message = exceptions::get_message($exception);
|
||||
if ($showContent) {
|
||||
if ($printActions) { $this->printActions(); $printActions = false; }
|
||||
$this->_printGeneric($linePrefix, $level, $type, $userMessage, $indentLevel, $out);
|
||||
$this->_printGeneric($linePrefix, $level, $type, $message, $indentLevel, $out);
|
||||
}
|
||||
# puis summary et traceback
|
||||
if ($showTraceback) {
|
||||
if ($printActions) { $this->printActions(); $printActions = false; }
|
||||
if ($showSummary) {
|
||||
$summary = UserException::get_summary($exception);
|
||||
$this->_printGeneric($linePrefix, $level1, $type, $summary, $indentLevel, $out);
|
||||
}
|
||||
$traceback = UserException::get_traceback($exception);
|
||||
$summary = exceptions::get_summary($exception, false);
|
||||
$this->_printGeneric($linePrefix, $level1, $type, $summary, $indentLevel, $out);
|
||||
$traceback = exceptions::get_traceback($exception);
|
||||
$this->_printGeneric($linePrefix, $level1, $type, $traceback, $indentLevel, $out);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ use Exception;
|
||||
use nulib\A;
|
||||
use nulib\cl;
|
||||
use nulib\cv;
|
||||
use nulib\exceptions;
|
||||
use nulib\StateException;
|
||||
use nulib\ValueException;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
@ -446,11 +446,7 @@ class func {
|
||||
const TYPE_STATIC = self::TYPE_METHOD | self::FLAG_STATIC;
|
||||
|
||||
protected static function not_a_callable($func, ?string $reason) {
|
||||
if ($reason === null) {
|
||||
$msg = var_export($func, true);
|
||||
$reason = "$msg: not a callable";
|
||||
}
|
||||
return new ValueException($reason);
|
||||
throw exceptions::invalid_type($func, null, "callable");
|
||||
}
|
||||
|
||||
private static function _with($func, ?array $args=null, bool $strict=true, ?string &$reason=null): ?self {
|
||||
@ -604,7 +600,7 @@ class func {
|
||||
$mask = $staticOnly? self::MASK_PS: self::MASK_P;
|
||||
$expected = $staticOnly? self::METHOD_PS: self::METHOD_P;
|
||||
} else {
|
||||
throw new ValueException("$class_or_object: vous devez spécifier une classe ou un objet");
|
||||
throw exceptions::invalid_type($class_or_object, null, ["class", "object"]);
|
||||
}
|
||||
$methods = [];
|
||||
foreach ($c->getMethods() as $m) {
|
||||
@ -777,7 +773,7 @@ class func {
|
||||
if (is_object($object) && !($this->flags & self::FLAG_STATIC)) {
|
||||
if (is_object($c)) $c = get_class($c);
|
||||
if (is_string($c) && !($object instanceof $c)) {
|
||||
throw ValueException::invalid_type($object, $c);
|
||||
throw exceptions::invalid_type($object, "object", $c);
|
||||
}
|
||||
$this->object = $object;
|
||||
$this->bound = true;
|
||||
|
@ -438,7 +438,7 @@ class str {
|
||||
} elseif (preg_match(self::CAMEL_PATTERN2, $camel, $ms, PREG_OFFSET_CAPTURE)) {
|
||||
# préfixe en minuscule
|
||||
} else {
|
||||
throw ValueException::invalid_kind($camel, "camel string");
|
||||
throw exceptions::invalid_type($camel, $kind, "camel string");
|
||||
}
|
||||
$parts[] = strtolower($ms[1][0]);
|
||||
$index = intval($ms[1][1]) + strlen($ms[1][0]);
|
||||
|
@ -119,6 +119,14 @@ class Word {
|
||||
$this->w = $spec;
|
||||
}
|
||||
|
||||
function isMasculin(): bool {
|
||||
return !$this->fem;
|
||||
}
|
||||
|
||||
function isFeminin(): bool {
|
||||
return $this->fem;
|
||||
}
|
||||
|
||||
/**
|
||||
* retourner le mot sans article
|
||||
*
|
||||
|
@ -5,9 +5,8 @@ use nulib\UserException;
|
||||
use Throwable;
|
||||
|
||||
class CurlException extends UserException {
|
||||
function __construct($ch, ?string $message=null, $code=0, ?Throwable $previous=null) {
|
||||
if ($message === null) $message = "(unknown error)";
|
||||
$userMessage = $message;
|
||||
function __construct($ch, $userMessage=null, $code=0, ?Throwable $previous=null) {
|
||||
$userMessage ??= "erreur curl inconnue";
|
||||
$techMessage = null;
|
||||
if ($ch !== null) {
|
||||
$parts = [];
|
||||
@ -17,6 +16,7 @@ class CurlException extends UserException {
|
||||
if ($error != "") $parts[] = "error: $error";
|
||||
if ($parts) $techMessage = implode(", ", $parts);
|
||||
}
|
||||
parent::__construct($userMessage, $techMessage, $code, $previous);
|
||||
parent::__construct($userMessage, $code, $previous);
|
||||
$this->setTechMessage($techMessage);
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ class curl {
|
||||
if (!isset($curlOptions[CURLOPT_RETURNTRANSFER])) $curlOptions[CURLOPT_RETURNTRANSFER] = true;
|
||||
$extractHeaders = isset($curlOptions[CURLOPT_HEADER]) && $curlOptions[CURLOPT_HEADER];
|
||||
$ch = curl_init();
|
||||
if ($ch === false) throw new CurlException(null, "init");
|
||||
if ($ch === false) throw new CurlException(null, "erreur curl lors de l'initialisation");
|
||||
curl_setopt_array($ch, $curlOptions);
|
||||
try {
|
||||
$result = curl_exec($ch);
|
||||
if ($result === false) throw new CurlException($ch);
|
||||
if ($result === false) throw new CurlException($ch, "erreur curl lors du téléchargement");
|
||||
if ($extractHeaders) {
|
||||
$info = curl_getinfo($ch);
|
||||
$headersSize = $info["header_size"];
|
||||
|
@ -3,6 +3,7 @@
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use nulib\app\cli\Application;
|
||||
use nulib\cv;
|
||||
use nulib\mail\mailer;
|
||||
use nulib\ValueException;
|
||||
|
||||
@ -20,10 +21,8 @@ Application::run(new class extends Application {
|
||||
protected $to, $cc, $bcc, $from;
|
||||
|
||||
function main() {
|
||||
$subject = $this->args[0] ?? null;
|
||||
ValueException::check_null($subject, "subject");
|
||||
$body = $this->args[1] ?? null;
|
||||
ValueException::check_null($body, "body");
|
||||
$subject = cv::not_null($this->args[0] ?? null, "subject");
|
||||
$body = cv::not_null($this->args[1] ?? null, "body");
|
||||
mailer::send($this->to, $subject, $body, $this->cc, $this->bcc, $this->from);
|
||||
}
|
||||
});
|
||||
|
65
php/tbin/test-exceptions.php
Executable file
65
php/tbin/test-exceptions.php
Executable file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
require __DIR__."/../vendor/autoload.php";
|
||||
|
||||
use nulib\app\cli\Application;
|
||||
use nulib\exceptions;
|
||||
use nulib\output\msg;
|
||||
use nulib\UserException;
|
||||
|
||||
Application::run(new class extends Application {
|
||||
const ARGS = [
|
||||
"purpose" => "tester l'affichage des exception",
|
||||
|
||||
"merge" => parent::ARGS,
|
||||
];
|
||||
|
||||
function fart(): void {
|
||||
throw new RuntimeException("fart");
|
||||
}
|
||||
|
||||
function prout(): void {
|
||||
try {
|
||||
$this->fart();
|
||||
} catch (Exception $e) {
|
||||
throw new RuntimeException("prout", $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
try {
|
||||
throw new Exception("exception normale");
|
||||
} catch (Exception $e) {
|
||||
msg::info("summary: ". exceptions::get_summary($e));
|
||||
msg::error($e);
|
||||
}
|
||||
try {
|
||||
try {
|
||||
$this->prout();
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("exception normale", $e->getCode(), $e);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
msg::info("summary: ". exceptions::get_summary($e));
|
||||
msg::error($e);
|
||||
}
|
||||
try {
|
||||
throw exceptions::invalid_value("valeur", $kind)
|
||||
->setTechMessage("message technique");
|
||||
} catch (Exception $e) {
|
||||
msg::info("summary: ". exceptions::get_summary($e));
|
||||
msg::error($e);
|
||||
}
|
||||
try {
|
||||
try {
|
||||
$this->prout();
|
||||
} catch (Exception $e) {
|
||||
throw exceptions::invalid_value("valeur", $kind, null, $e)
|
||||
->setTechMessage("message technique");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
msg::info("summary: ". exceptions::get_summary($e));
|
||||
msg::error($e);
|
||||
}
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user