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