Remove `@access` annotations
[phpmyadmin.git] / libraries / classes / Message.php
blob02ef92adb8f1fff317d3632f4513500f9e5def0b
1 <?php
3 declare(strict_types=1);
5 namespace PhpMyAdmin;
7 use Stringable;
9 use function __;
10 use function _ngettext;
11 use function array_unshift;
12 use function count;
13 use function htmlspecialchars;
14 use function is_array;
15 use function is_float;
16 use function is_int;
17 use function md5;
18 use function sprintf;
19 use function strlen;
21 use const ENT_COMPAT;
23 /**
24 * a single message
26 * simple usage examples:
27 * <code>
28 * // display simple error message 'Error'
29 * echo Message::error()->getDisplay();
31 * // get simple success message 'Success'
32 * $message = Message::success();
34 * // get special notice
35 * $message = Message::notice(__('This is a localized notice'));
36 * </code>
38 * more advanced usage example:
39 * <code>
40 * // create another message, a hint, with a localized string which expects
41 * $hint = Message::notice('Read the %smanual%s');
42 * // replace placeholders with the following params
43 * $hint->addParam('[doc@cfg_Example]');
44 * $hint->addParam('[/doc]');
45 * // add this hint as a tooltip
46 * $hint = showHint($hint);
48 * // add the retrieved tooltip reference to the original message
49 * $message->addMessage($hint);
50 * </code>
52 class Message implements Stringable
54 public const SUCCESS = 1; // 0001
55 public const NOTICE = 2; // 0010
56 public const ERROR = 8; // 1000
58 public const SANITIZE_NONE = 0; // 0000 0000
59 public const SANITIZE_STRING = 16; // 0001 0000
60 public const SANITIZE_PARAMS = 32; // 0010 0000
61 public const SANITIZE_BOOTH = 48; // 0011 0000
63 /**
64 * message levels
66 * @var array
68 public static $level = [
69 self::SUCCESS => 'success',
70 self::NOTICE => 'notice',
71 self::ERROR => 'error',
74 /**
75 * The message number
77 * @var int
79 protected $number = self::NOTICE;
81 /**
82 * The locale string identifier
84 * @var string
86 protected $string = '';
88 /**
89 * The formatted message
91 * @var string
93 protected $message = '';
95 /**
96 * Whether the message was already displayed
98 * @var bool
100 protected $isDisplayed = false;
103 * Whether to use BB code when displaying.
105 * @var bool
107 protected $useBBCode = true;
110 * Unique id
112 * @var string
114 protected $hash = null;
117 * holds parameters
119 * @var array
121 protected $params = [];
124 * holds additional messages
126 * @var array
128 protected $addedMessages = [];
131 * @param string $string The message to be displayed
132 * @param int $number A numeric representation of the type of message
133 * @param array $params An array of parameters to use in the message
134 * @param int $sanitize A flag to indicate what to sanitize, see
135 * constant definitions above
137 public function __construct(
138 string $string = '',
139 int $number = self::NOTICE,
140 array $params = [],
141 int $sanitize = self::SANITIZE_NONE
143 $this->setString($string, $sanitize & self::SANITIZE_STRING);
144 $this->setNumber($number);
145 $this->setParams($params, $sanitize & self::SANITIZE_PARAMS);
149 * magic method: return string representation for this object
151 public function __toString(): string
153 return $this->getMessage();
157 * get Message of type success
159 * shorthand for getting a simple success message
161 * @param string $string A localized string
162 * e.g. __('Your SQL query has been
163 * executed successfully')
165 * @return Message
167 * @static
169 public static function success(string $string = ''): self
171 if (empty($string)) {
172 $string = __('Your SQL query has been executed successfully.');
175 return new Message($string, self::SUCCESS);
179 * get Message of type error
181 * shorthand for getting a simple error message
183 * @param string $string A localized string e.g. __('Error')
185 * @return Message
187 * @static
189 public static function error(string $string = ''): self
191 if (empty($string)) {
192 $string = __('Error');
195 return new Message($string, self::ERROR);
199 * get Message of type notice
201 * shorthand for getting a simple notice message
203 * @param string $string A localized string
204 * e.g. __('The additional features for working with
205 * linked tables have been deactivated. To find out
206 * why click %shere%s.')
208 * @return Message
210 * @static
212 public static function notice(string $string): self
214 return new Message($string, self::NOTICE);
218 * get Message with customized content
220 * shorthand for getting a customized message
222 * @param string $message A localized string
223 * @param int $type A numeric representation of the type of message
225 * @return Message
227 * @static
229 public static function raw(string $message, int $type = self::NOTICE): self
231 $r = new Message('', $type);
232 $r->setMessage($message);
233 $r->setBBCode(false);
235 return $r;
239 * get Message for number of affected rows
241 * shorthand for getting a customized message
243 * @param int $rows Number of rows
245 * @return Message
247 * @static
249 public static function getMessageForAffectedRows(int $rows): self
251 $message = self::success(
252 _ngettext('%1$d row affected.', '%1$d rows affected.', $rows)
254 $message->addParam($rows);
256 return $message;
260 * get Message for number of deleted rows
262 * shorthand for getting a customized message
264 * @param int $rows Number of rows
266 * @return Message
268 * @static
270 public static function getMessageForDeletedRows(int $rows): self
272 $message = self::success(
273 _ngettext('%1$d row deleted.', '%1$d rows deleted.', $rows)
275 $message->addParam($rows);
277 return $message;
281 * get Message for number of inserted rows
283 * shorthand for getting a customized message
285 * @param int $rows Number of rows
287 * @return Message
289 * @static
291 public static function getMessageForInsertedRows(int $rows): self
293 $message = self::success(
294 _ngettext('%1$d row inserted.', '%1$d rows inserted.', $rows)
296 $message->addParam($rows);
298 return $message;
302 * get Message of type error with custom content
304 * shorthand for getting a customized error message
306 * @param string $message A localized string
308 * @return Message
310 * @static
312 public static function rawError(string $message): self
314 return self::raw($message, self::ERROR);
318 * get Message of type notice with custom content
320 * shorthand for getting a customized notice message
322 * @param string $message A localized string
324 * @return Message
326 * @static
328 public static function rawNotice(string $message): self
330 return self::raw($message, self::NOTICE);
334 * get Message of type success with custom content
336 * shorthand for getting a customized success message
338 * @param string $message A localized string
340 * @return Message
342 * @static
344 public static function rawSuccess(string $message): self
346 return self::raw($message, self::SUCCESS);
350 * returns whether this message is a success message or not
351 * and optionally makes this message a success message
353 * @param bool $set Whether to make this message of SUCCESS type
355 public function isSuccess(bool $set = false): bool
357 if ($set) {
358 $this->setNumber(self::SUCCESS);
361 return $this->getNumber() === self::SUCCESS;
365 * returns whether this message is a notice message or not
366 * and optionally makes this message a notice message
368 * @param bool $set Whether to make this message of NOTICE type
370 public function isNotice(bool $set = false): bool
372 if ($set) {
373 $this->setNumber(self::NOTICE);
376 return $this->getNumber() === self::NOTICE;
380 * returns whether this message is an error message or not
381 * and optionally makes this message an error message
383 * @param bool $set Whether to make this message of ERROR type
385 public function isError(bool $set = false): bool
387 if ($set) {
388 $this->setNumber(self::ERROR);
391 return $this->getNumber() === self::ERROR;
395 * Set whether we should use BB Code when rendering.
397 * @param bool $useBBCode Use BB Code?
399 public function setBBCode(bool $useBBCode): void
401 $this->useBBCode = $useBBCode;
405 * set raw message (overrides string)
407 * @param string $message A localized string
408 * @param bool $sanitize Whether to sanitize $message or not
410 public function setMessage(string $message, bool $sanitize = false): void
412 if ($sanitize) {
413 $message = self::sanitize($message);
416 $this->message = $message;
420 * set string (does not take effect if raw message is set)
422 * @param string $string string to set
423 * @param bool|int $sanitize whether to sanitize $string or not
425 public function setString(string $string, $sanitize = true): void
427 if ($sanitize) {
428 $string = self::sanitize($string);
431 $this->string = $string;
435 * set message type number
437 * @param int $number message type number to set
439 public function setNumber(int $number): void
441 $this->number = $number;
445 * add string or Message parameter
447 * usage
448 * <code>
449 * $message->addParam('[em]some string[/em]');
450 * </code>
452 * @param mixed $param parameter to add
454 public function addParam($param): void
456 if ($param instanceof self || is_float($param) || is_int($param)) {
457 $this->params[] = $param;
458 } else {
459 $this->params[] = htmlspecialchars((string) $param, ENT_COMPAT);
464 * add parameter as raw HTML, usually in conjunction with strings
466 * usage
467 * <code>
468 * $message->addParamHtml('<img src="img">');
469 * </code>
471 * @param string $param parameter to add
473 public function addParamHtml(string $param): void
475 $this->params[] = self::notice($param);
479 * add a bunch of messages at once
481 * @param Message[] $messages to be added
482 * @param string $separator to use between this and previous string/message
484 public function addMessages(array $messages, string $separator = ' '): void
486 foreach ($messages as $message) {
487 $this->addMessage($message, $separator);
492 * add a bunch of messages at once
494 * @param string[] $messages to be added
495 * @param string $separator to use between this and previous string/message
497 public function addMessagesString(array $messages, string $separator = ' '): void
499 foreach ($messages as $message) {
500 $this->addText($message, $separator);
505 * Real implementation of adding message
507 * @param Message $message to be added
508 * @param string $separator to use between this and previous string/message
510 private function addMessageToList(self $message, string $separator): void
512 if (! empty($separator)) {
513 $this->addedMessages[] = $separator;
516 $this->addedMessages[] = $message;
520 * add another raw message to be concatenated on displaying
522 * @param self $message to be added
523 * @param string $separator to use between this and previous string/message
525 public function addMessage(self $message, string $separator = ' '): void
527 $this->addMessageToList($message, $separator);
531 * add another raw message to be concatenated on displaying
533 * @param string $message to be added
534 * @param string $separator to use between this and previous string/message
536 public function addText(string $message, string $separator = ' '): void
538 $this->addMessageToList(self::notice(htmlspecialchars($message)), $separator);
542 * add another html message to be concatenated on displaying
544 * @param string $message to be added
545 * @param string $separator to use between this and previous string/message
547 public function addHtml(string $message, string $separator = ' '): void
549 $this->addMessageToList(self::rawNotice($message), $separator);
553 * set all params at once, usually used in conjunction with string
555 * @param array $params parameters to set
556 * @param bool|int $sanitize whether to sanitize params
558 public function setParams(array $params, $sanitize = false): void
560 if ($sanitize) {
561 $params = self::sanitize($params);
564 $this->params = $params;
568 * return all parameters
570 * @return array
572 public function getParams(): array
574 return $this->params;
578 * return all added messages
580 * @return array
582 public function getAddedMessages(): array
584 return $this->addedMessages;
588 * Sanitizes $message
590 * @param mixed $message the message(s)
592 * @return mixed the sanitized message(s)
594 * @static
596 public static function sanitize($message)
598 if (is_array($message)) {
599 foreach ($message as $key => $val) {
600 $message[$key] = self::sanitize($val);
603 return $message;
606 return htmlspecialchars((string) $message);
610 * decode $message, taking into account our special codes
611 * for formatting
613 * @param string $message the message
615 * @return string the decoded message
617 * @static
619 public static function decodeBB(string $message): string
621 return Sanitize::sanitizeMessage($message, false, true);
625 * wrapper for sprintf()
627 * @param mixed[] ...$params Params
629 * @return string formatted
631 public static function format(...$params): string
633 if (isset($params[1]) && is_array($params[1])) {
634 array_unshift($params[1], $params[0]);
635 $params = $params[1];
638 return sprintf(...$params);
642 * returns unique Message::$hash, if not exists it will be created
644 * @return string Message::$hash
646 public function getHash(): string
648 if ($this->hash === null) {
649 $this->hash = md5(
650 $this->getNumber() .
651 $this->string .
652 $this->message
656 return $this->hash;
660 * returns compiled message
662 * @return string complete message
664 public function getMessage(): string
666 $message = $this->message;
668 if (strlen($message) === 0) {
669 $string = $this->getString();
670 if (strlen($string) === 0) {
671 $message = '';
672 } else {
673 $message = $string;
677 if ($this->isDisplayed()) {
678 $message = $this->getMessageWithIcon($message);
681 if (count($this->getParams()) > 0) {
682 $message = self::format($message, $this->getParams());
685 if ($this->useBBCode) {
686 $message = self::decodeBB($message);
689 foreach ($this->getAddedMessages() as $add_message) {
690 $message .= $add_message;
693 return $message;
697 * Returns only message string without image & other HTML.
699 public function getOnlyMessage(): string
701 return $this->message;
705 * returns Message::$string
707 * @return string Message::$string
709 public function getString(): string
711 return $this->string;
715 * returns Message::$number
717 * @return int Message::$number
719 public function getNumber(): int
721 return $this->number;
725 * returns level of message
727 * @return string level of message
729 public function getLevel(): string
731 return self::$level[$this->getNumber()];
735 * returns HTML code for displaying this message
737 * @return string whole message box
739 public function getDisplay(): string
741 $this->isDisplayed(true);
743 $context = 'primary';
744 $level = $this->getLevel();
745 if ($level === 'error') {
746 $context = 'danger';
747 } elseif ($level === 'success') {
748 $context = 'success';
751 $template = new Template();
753 return $template->render('message', [
754 'context' => $context,
755 'message' => $this->getMessage(),
760 * sets and returns whether the message was displayed or not
762 * @param bool $isDisplayed whether to set displayed flag
764 public function isDisplayed(bool $isDisplayed = false): bool
766 if ($isDisplayed) {
767 $this->isDisplayed = true;
770 return $this->isDisplayed;
774 * Returns the message with corresponding image icon
776 * @param string $message the message(s)
778 * @return string message with icon
780 public function getMessageWithIcon(string $message): string
782 if ($this->getLevel() === 'error') {
783 $image = 's_error';
784 } elseif ($this->getLevel() === 'success') {
785 $image = 's_success';
786 } else {
787 $image = 's_notice';
790 $message = self::notice(Html\Generator::getImage($image)) . ' ' . $message;
792 return $message;