Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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              // Currently in the page body - just render and exit immediately.
  63              // We insert some code to immediately insert this into the user-notifications created by the header.
  64              $id = uniqid();
  65              echo \html_writer::span(
  66                  $PAGE->get_renderer('core')->render(new \core\output\notification($message, $level)),
  67                  '', array('id' => $id));
  68  
  69              // Insert this JS here using a script directly rather than waiting for the page footer to load to avoid
  70              // ensure that the message is added to the user-notifications section as soon as possible after it is created.
  71              echo \html_writer::script(
  72                      "(function() {" .
  73                          "var notificationHolder = document.getElementById('user-notifications');" .
  74                          "if (!notificationHolder) { return; }" .
  75                          "var thisNotification = document.getElementById('{$id}');" .
  76                          "if (!thisNotification) { return; }" .
  77                          "notificationHolder.appendChild(thisNotification.firstChild);" .
  78                          "thisNotification.remove();" .
  79                      "})();"
  80                  );
  81              return;
  82          }
  83  
  84          // Add the notification directly to the session.
  85          // This will either be fetched in the header, or by JS in the footer.
  86          if (!isset($SESSION->notifications) || !array($SESSION->notifications)) {
  87              // Initialise $SESSION if necessary.
  88              if (!is_object($SESSION)) {
  89                  $SESSION = new stdClass();
  90              }
  91              $SESSION->notifications = [];
  92          }
  93          $SESSION->notifications[] = (object) array(
  94              'message'   => $message,
  95              'type'      => $level,
  96          );
  97      }
  98  
  99      /**
 100       * @param string[] $icon The icon to use. Required keys are 'pix' and 'component'.
 101       * @param string $message The message to display.
 102       * @param array $actions An array of action links
 103       * @param string $region Optional region name
 104       * @throws \coding_exception
 105       */
 106      public static function add_call_to_action(array $icon, string $message, array $actions, string $region = ''): void {
 107          global $OUTPUT, $PAGE;
 108  
 109          $context = new stdClass();
 110          $context->icon = $icon;
 111          $context->message = $message;
 112          $context->region = $region;
 113  
 114          $context->actions = array_map(function($action) {
 115              $data = [];
 116              foreach ($action['data'] as $name => $value) {
 117                  $data[] = ['name' => $name, 'value' => $value];
 118              }
 119              $action['data'] = $data;
 120  
 121              return $action;
 122          }, $actions);
 123  
 124          $notification = $OUTPUT->render_from_template('core/local/notification/cta', $context);
 125  
 126          if ($PAGE && $PAGE->state === \moodle_page::STATE_IN_BODY) {
 127              $id = uniqid();
 128              echo \html_writer::span($notification, '', ['id' => $id]);
 129              echo \html_writer::script(
 130                      "(function() {" .
 131                      "var notificationHolder = document.getElementById('user-notifications');" .
 132                      "if (!notificationHolder) { return; }" .
 133                      "var thisNotification = document.getElementById('{$id}');" .
 134                      "if (!thisNotification) { return; }" .
 135                      "notificationHolder.insertBefore(thisNotification.firstChild, notificationHolder.firstChild);" .
 136                      "thisNotification.remove();" .
 137                      "})();"
 138              );
 139          } else {
 140              throw new \coding_exception('You are calling add_call_to_action() either too early or too late.');
 141          }
 142      }
 143  
 144      /**
 145       * Fetch all of the notifications in the stack and clear the stack.
 146       *
 147       * @return array All of the notifications in the stack
 148       */
 149      public static function fetch() {
 150          global $SESSION;
 151  
 152          if (!isset($SESSION) || !isset($SESSION->notifications)) {
 153              return [];
 154          }
 155  
 156          $notifications = $SESSION->notifications;
 157          unset($SESSION->notifications);
 158  
 159          $renderables = [];
 160          foreach ($notifications as $notification) {
 161              $renderable = new \core\output\notification($notification->message, $notification->type);
 162              $renderables[] = $renderable;
 163          }
 164  
 165          return $renderables;
 166      }
 167  
 168      /**
 169       * Fetch all of the notifications in the stack and clear the stack.
 170       *
 171       * @return array All of the notifications in the stack
 172       */
 173      public static function fetch_as_array(\renderer_base $renderer) {
 174          $notifications = [];
 175          foreach (self::fetch() as $notification) {
 176              $notifications[] = [
 177                  'template'  => $notification->get_template_name(),
 178                  'variables' => $notification->export_for_template($renderer),
 179              ];
 180          }
 181          return $notifications;
 182      }
 183  
 184      /**
 185       * Add a success message to the notification stack.
 186       *
 187       * @param string $message The message to add to the stack
 188       */
 189      public static function success($message) {
 190          return self::add($message, self::SUCCESS);
 191      }
 192  
 193      /**
 194       * Add a info message to the notification stack.
 195       *
 196       * @param string $message The message to add to the stack
 197       */
 198      public static function info($message) {
 199          return self::add($message, self::INFO);
 200      }
 201  
 202      /**
 203       * Add a warning message to the notification stack.
 204       *
 205       * @param string $message The message to add to the stack
 206       */
 207      public static function warning($message) {
 208          return self::add($message, self::WARNING);
 209      }
 210  
 211      /**
 212       * Add a error message to the notification stack.
 213       *
 214       * @param string $message The message to add to the stack
 215       */
 216      public static function error($message) {
 217          return self::add($message, self::ERROR);
 218      }
 219  }