["?string", "", "clé de session pour enregistrer les messages"], "redirect" => ["?string", null, "url vers laquelle rediriger s'il faut afficher les messages en différé"], "dismissible" => ["bool", false, "les messages doivent-ils pouvoir être fermés par l'utilisateur?"], "auto_session" => ["bool", false, "faut-il enregistrer et/ou restaurer automatiquement la session?"], ]; function __construct(?array $params=null) { parent::__construct($params); $this->reset(false); if ($this->ppAutoSession) $this->restoreSession(); } /** @var string */ protected $sessionKey; function pp_setSessionKey(?string $sessionKey): void { $this->sessionKey = self::get_session_key($sessionKey); } /** @var ?string url vers laquelle rediriger */ protected $ppRedirect; /** @var bool */ protected $ppDismissible; /** @var bool */ protected $ppAutoSession; /** * modifier uniquement les paramètres spécifiés * * - $redirect n'est modifié que s'il est différente de false * - $dismissible n'est modifié que s'il est non null */ function setRedirect($redirect=false, ?bool $dismissible=null): Alerter { if ($redirect !== false) $this->ppRedirect = $redirect; if ($dismissible !== null) $this->ppDismissible = $dismissible; return $this; } /** @var array */ private $messages; /** * @var int type d'alerte à afficher. il s'agit de l'alerte la plus grave qui * a été ajoutée jusqu'ici */ private $type; /** @var int type de section pour les messages à afficher */ private $msgType, $msgLevel; /** * @var bool une erreur a-t-elle été ajoutée? c'est le cas à partir du type * {@link TYPE_FAILURE} */ private $error; /** @var bool valeur par défaut de 'dismissible' */ private $dismissible; /** enregistrer les messages en attente dans la session */ function saveSession(): void { session::set($this->sessionKey, [ "messages" => $this->messages, "atype" => $this->type, "mtype" => $this->msgType, "mlevel" => $this->msgLevel, "error" => $this->error, self::KEY_DISMISSIBLE => $this->dismissible, ]); } /** restaurer les messages en attente depuis la session. */ function restoreSession(?string $sessionKey=null, bool $clear=true): void { if ($sessionKey === null) $sessionKey = $this->sessionKey; else $sessionKey = self::get_session_key($sessionKey); if (session::has($sessionKey)) { [ "messages" => $this->messages, "atype" => $this->type, "mtype" => $this->msgType, "mlevel" => $this->msgLevel, "error" => $this->error, self::KEY_DISMISSIBLE => $this->dismissible, ] = session::get($sessionKey); if ($clear) session::del($sessionKey); } } function reset(?bool $autoSession=null): void { $this->messages = []; $this->type = -1; $this->msgType = -1; $this->msgLevel = -1; $this->error = false; $this->dismissible = $this->ppDismissible; if ($autoSession === null) $autoSession = $this->ppAutoSession; if ($autoSession) $this->saveSession(); } const MESSAGE_KEYS = [ IMessenger::KEY_USER, IMessenger::KEY_TECH, IMessenger::KEY_EXCEPTION, ]; /** * ajouter un message de type $type. les messages ne sont pas affichés de * suite: il faut appeler {@link print()} pour cela * * @param array|string|Throwable $message le message à afficher, conforme à * {@link IMessenger::MESSAGE_SCHEMA} * @param int $type le type de message * @return bool true si l'objet n'est pas dans un état d'erreur */ function add($message, int $type, ?bool $dismissible=null): bool { if ($message === null) return true; msg::get()->ensureMessage($message); foreach (self::MESSAGE_KEYS as $key) { # remplacer les exceptions par des instances de ExceptionShadow, afin # qu'elles puissent être sérialisées if ($message[$key] instanceof Throwable) { $message[$key] = new ExceptionShadow($message[$key]); } } if ($dismissible === null) $dismissible = A::get($message, self::KEY_DISMISSIBLE); if ($dismissible !== null) $this->dismissible = $dismissible; $message[self::KEY_DISMISSIBLE] = $dismissible; switch ($type) { case self::TYPE_DEBUG: $msgType = msg::DEBUG; $msgLevel = msg::NORMAL; if ($type > $this->type) { $this->type = $type; [$this->msgType, $this->msgLevel] = [msg::DEBUG, msg::NORMAL]; } break; case self::TYPE_INFO: $msgType = msg::INFO; $msgLevel = msg::NORMAL; if ($type > $this->type) { $this->type = $type; [$this->msgType, $this->msgLevel] = [msg::INFO, msg::NORMAL]; } break; case self::TYPE_NOTE: $msgType = msg::INFO; $msgLevel = msg::MAJOR; if ($type > $this->type) { $this->type = $type; [$this->msgType, $this->msgLevel] = [msg::INFO, msg::NORMAL]; } break; case self::TYPE_SUCCESS: $msgType = msg::INFO + msg::SUCCESS; $msgLevel = msg::MAJOR; if ($type > $this->type) { $this->type = $type; [$this->msgType, $this->msgLevel] = [msg::INFO, msg::NORMAL]; } break; case self::TYPE_FAILURE: $msgType = msg::INFO + msg::FAILURE; $msgLevel = msg::MAJOR; if ($type > $this->type) { $this->type = $type; [$this->msgType, $this->msgLevel] = [msg::INFO, msg::NORMAL]; $this->error = true; } break; case self::TYPE_WARNING: $msgType = msg::WARNING; $msgLevel = msg::MAJOR; if ($type > $this->type) { $this->type = $type; [$this->msgType, $this->msgLevel] = [msg::WARNING, msg::NORMAL]; $this->error = true; } break; case self::TYPE_ERROR: $msgType = msg::ERROR; $msgLevel = msg::MAJOR; if ($type > $this->type) { $this->type = $type; [$this->msgType, $this->msgLevel] = [msg::ERROR, msg::NORMAL]; $this->error = true; } break; default: throw ValueException::invalid_value($type, "type"); } $this->messages[] = [$message, $msgType, $msgLevel]; if ($this->ppAutoSession) $this->saveSession(); return !$this->error; } /** retourner le nombre de messages ajoutés */ function count(): int { return count($this->messages); } /** tester si cet objet est dans un état d'erreur suite à un message ajouté */ function isError(): bool { return $this->error; } protected function printNoReset(): bool { if (!$this->messages) return false; $dismissible = $this->dismissible; $msgType = $this->msgType; if ($msgType >= msg::ERROR) $title = "Erreur"; elseif ($msgType >= msg::WARNING) $title = "Avertissement"; elseif ($msgType >= msg::INFO) $title = "Information"; else $title = null; $msg = msg::get(); $msg->startSection($title, $this->msgType, $this->msgLevel); foreach ($this->messages as [$message, $type, $level]) { A::replace_z($message, self::KEY_DISMISSIBLE, $dismissible); $msg->addMessage($message, $type, $level); } $msg->endSection(); return true; } /** * afficher les messages qui sont en attente puis retourner $result qui vaut * par défaut !isError() */ function print($result=null) { if ($result === null) $result = !$this->error; if ($this->printNoReset()) $this->reset(); return $result; } /** * rediriger vers l'url spécifiée qui affichera les messages mis en attente * après les avoir chargés depuis la session * * si $redirect===false, utiliser la valeur par défaut spécifiée dans les * paramètres */ function redirect($redirect=false): void { if ($redirect === false) $redirect = $this->ppRedirect; page::redirect($redirect); } ############################################################################# # Méthodes de convenance function error($message): Alerter { $this->add($message, self::TYPE_ERROR); return $this; } function warning($message): Alerter { $this->add($message, self::TYPE_WARNING); return $this; } function note($message): Alerter { $this->add($message, self::TYPE_NOTE); return $this; } function success($message): Alerter { $this->add($message, self::TYPE_SUCCESS); return $this; } function failure($message): Alerter { $this->add($message, self::TYPE_FAILURE); return $this; } function info($message): Alerter { $this->add($message, self::TYPE_INFO); return $this; } function debug($message): Alerter { $this->add($message, self::TYPE_DEBUG); return $this; } function perror($message): void { $this->error($message); $this->print(); } function pwarning($message): void { $this->warning($message); $this->print(); } function pnote($message): void { $this->note($message); $this->print(); } function psuccess($message): void { $this->success($message); $this->print(); } function pfailure($message): void { $this->failure($message); $this->print(); } function pinfo($message): void { $this->info($message); $this->print(); } function pdebug($message): void { $this->debug($message); $this->print(); } }