Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core;
  18  
  19  /**
  20   * User Alert notifications.
  21   *
  22   * @package    core
  23   * @copyright  2016 Andrew Nicols <andrew@nicols.co.uk>
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  use stdClass;
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  class notification {
  32      /**
  33       * A notification of level 'success'.
  34       */
  35      const SUCCESS = 'success';
  36  
  37      /**
  38       * A notification of level 'warning'.
  39       */
  40      const WARNING = 'warning';
  41  
  42      /**
  43       * A notification of level 'info'.
  44       */
  45      const INFO = 'info';
  46  
  47      /**
  48       * A notification of level 'error'.
  49       */
  50      const ERROR = 'error';
  51  
  52      /**
  53       * Add a message to the session notification stack.
  54       *
  55       * @param string $message The message to add to the stack
  56       * @param string $level   The type of message to add to the stack
  57       */
  58      public static function add($message, $level = null) {
  59          global $PAGE, $SESSION;
  60  
  61          if ($PAGE && ($PAGE->state === \moodle_page::STATE_IN_BODY
  62             || $PAGE->state === \moodle_page::STATE_DONE)) {
  63              // Currently in the page body - just render and exit immediately.
  64              // We insert some code to immediately insert this into the user-notifications created by the header.
  65              $id = uniqid();
  66              echo \html_writer::span(
  67                  $PAGE->get_renderer('core')->render(new \core\output\notification($message, $level)),
  68                  '', array('id' => $id));
  69  
  70              // Insert this JS here using a script directly rather than waiting for the page footer to load to avoid
  71              // ensure that the message is added to the user-notifications section as soon as possible after it is created.
  72              echo \html_writer::script(
  73                      "(function() {" .
  74                          "var notificationHolder = document.getElementById('user-notifications');" .
  75                          "if (!notificationHolder) { return; }" .
  76                          "var thisNotification = document.getElementById('{$id}');" .
  77                          "if (!thisNotification) { return; }" .
  78                          "notificationHolder.appendChild(thisNotification.firstChild);" .
  79                          "thisNotification.remove();" .
  80                      "})();"
  81                  );
  82              return;
  83          }
  84  
  85          // Add the notification directly to the session.
  86          // This will either be fetched in the header, or by JS in the footer.
  87          if (!isset($SESSION->notifications) || !array($SESSION->notifications)) {
  88              // Initialise $SESSION if necessary.
  89              if (!is_object($SESSION)) {
  90                  $SESSION = new stdClass();
  91              }
  92              $SESSION->notifications = [];
  93          }
  94          $SESSION->notifications[] = (object) array(
  95              'message'   => $message,
  96              'type'      => $level,
  97          );
  98      }
  99  
 100      /**
 101       * @param string[] $icon The icon to use. Required keys are 'pix' and 'component'.
 102       * @param string $message The message to display.
 103       * @param array $actions An array of action links
 104       * @param string $region Optional region name
 105       * @throws \coding_exception
 106       */
 107      public static function add_call_to_action(array $icon, string $message, array $actions, string $region = ''): void {
 108          global $OUTPUT, $PAGE;
 109  
 110          $context = new stdClass();
 111          $context->icon = $icon;
 112          $context->message = $message;
 113          $context->region = $region;
 114  
 115          $context->actions = array_map(function($action) {
 116              $data = [];
 117              foreach ($action['data'] as $name => $value) {
 118                  $data[] = ['name' => $name, 'value' => $value];
 119              }
 120              $action['data'] = $data;
 121  
 122              return $action;
 123          }, $actions);
 124  
 125          $notification = $OUTPUT->render_from_template('core/local/notification/cta', $context);
 126  
 127          if ($PAGE && $PAGE->state === \moodle_page::STATE_IN_BODY) {
 128              $id = uniqid();
 129              echo \html_writer::span($notification, '', ['id' => $id]);
 130              echo \html_writer::script(
 131                      "(function() {" .
 132                      "var notificationHolder = document.getElementById('user-notifications');" .
 133                      "if (!notificationHolder) { return; }" .
 134                      "var thisNotification = document.getElementById('{$id}');" .
 135                      "if (!thisNotification) { return; }" .
 136                      "notificationHolder.insertBefore(thisNotification.firstChild, notificationHolder.firstChild);" .
 137                      "thisNotification.remove();" .
 138                      "})();"
 139              );
 140          } else {
 141              throw new \coding_exception('You are calling add_call_to_action() either too early or too late.');
 142          }
 143      }
 144  
 145      /**
 146       * Fetch all of the notifications in the stack and clear the stack.
 147       *
 148       * @return array All of the notifications in the stack
 149       */
 150      public static function fetch() {
 151          global $SESSION;
 152  
 153          if (!isset($SESSION) || !isset($SESSION->notifications)) {
 154              return [];
 155          }
 156  
 157          $notifications = $SESSION->notifications;
 158          unset($SESSION->notifications);
 159  
 160          $renderables = [];
 161          foreach ($notifications as $notification) {
 162              $renderable = new \core\output\notification($notification->message, $notification->type);
 163              $renderables[] = $renderable;
 164          }
 165  
 166          return $renderables;
 167      }
 168  
 169      /**
 170       * Fetch all of the notifications in the stack and clear the stack.
 171       *
 172       * @return array All of the notifications in the stack
 173       */
 174      public static function fetch_as_array(\renderer_base $renderer) {
 175          $notifications = [];
 176          foreach (self::fetch() as $notification) {
 177              $notifications[] = [
 178                  'template'  => $notification->get_template_name(),
 179                  'variables' => $notification->export_for_template($renderer),
 180              ];
 181          }
 182          return $notifications;
 183      }
 184  
 185      /**
 186       * Add a success message to the notification stack.
 187       *
 188       * @param string $message The message to add to the stack
 189       */
 190      public static function success($message) {
 191          return self::add($message, self::SUCCESS);
 192      }
 193  
 194      /**
 195       * Add a info message to the notification stack.
 196       *
 197       * @param string $message The message to add to the stack
 198       */
 199      public static function info($message) {
 200          return self::add($message, self::INFO);
 201      }
 202  
 203      /**
 204       * Add a warning message to the notification stack.
 205       *
 206       * @param string $message The message to add to the stack
 207       */
 208      public static function warning($message) {
 209          return self::add($message, self::WARNING);
 210      }
 211  
 212      /**
 213       * Add a error message to the notification stack.
 214       *
 215       * @param string $message The message to add to the stack
 216       */
 217      public static function error($message) {
 218          return self::add($message, self::ERROR);
 219      }
 220  }