305 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace nur\v\base;
 | 
						|
 | 
						|
use Countable;
 | 
						|
use nur\A;
 | 
						|
use nur\b\ExceptionShadow;
 | 
						|
use nur\b\params\Parametrable;
 | 
						|
use nur\b\params\Tparametrable;
 | 
						|
use nur\b\ui\IMessenger;
 | 
						|
use nur\b\ValueException;
 | 
						|
use nur\msg;
 | 
						|
use nur\session;
 | 
						|
use nur\v\page;
 | 
						|
use Throwable;
 | 
						|
 | 
						|
class Alerter extends Parametrable implements Countable {
 | 
						|
  use Tparametrable;
 | 
						|
 | 
						|
  const SESSION_KEY = "__alerter";
 | 
						|
 | 
						|
  private static function get_session_key(?string $session_key): string {
 | 
						|
    if ($session_key !== null) return self::SESSION_KEY.":$session_key";
 | 
						|
    else return self::SESSION_KEY;
 | 
						|
  }
 | 
						|
 | 
						|
  # Types de messages
 | 
						|
  const TYPE_ERROR = 6, TYPE_WARNING = 5, TYPE_FAILURE = 4, TYPE_SUCCESS = 3, TYPE_NOTE = 2, TYPE_INFO = 1, TYPE_DEBUG = 0;
 | 
						|
 | 
						|
  const KEY_SESSION_KEY = "session_key";
 | 
						|
  const KEY_REDIRECT = "redirect";
 | 
						|
  const KEY_DISMISSIBLE = "dismissible";
 | 
						|
  const KEY_AUTO_SESSION = "auto_session";
 | 
						|
 | 
						|
  const PARAMETRABLE_PARAMS_SCHEMA = [
 | 
						|
    "session_key" => ["?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(); }
 | 
						|
}
 |