MDL-30811 output: Add support for session notifications
[moodle.git] / lib / classes / notification.php
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/>.
17 namespace core;
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  */
27 defined('MOODLE_INTERNAL') || die();
29 class notification {
30     /**
31      * A notification of level 'success'.
32      */
33     const SUCCESS = 'success';
35     /**
36      * A notification of level 'warning'.
37      */
38     const WARNING = 'warning';
40     /**
41      * A notification of level 'info'.
42      */
43     const INFO = 'info';
45     /**
46      * A notification of level 'error'.
47      */
48     const ERROR = 'error';
50     /**
51      * Add a message to the session notification stack.
52      *
53      * @param string $message The message to add to the stack
54      * @param string $level   The type of message to add to the stack
55      */
56     public static function add($message, $level = null) {
57         global $PAGE, $SESSION;
59         if ($PAGE && $PAGE->state === \moodle_page::STATE_IN_BODY) {
60             // Currently in the page body - just render and exit immediately.
61             // We insert some code to immediately insert this into the user-notifications created by the header.
62             $id = uniqid();
63             echo \html_writer::span(
64                 $PAGE->get_renderer('core')->render(new \core\output\notification($message, $level)),
65                 '', array('id' => $id));
67             // Insert this JS here using a script directly rather than waiting for the page footer to load to avoid
68             // ensure that the message is added to the user-notifications section as soon as possible after it is created.
69             echo \html_writer::script(
70                     "(function() {" .
71                         "var notificationHolder = document.getElementById('user-notifications');" .
72                         "if (!notificationHolder) { return; }" .
73                         "var thisNotification = document.getElementById('{$id}');" .
74                         "if (!thisNotification) { return; }" .
75                         "notificationHolder.appendChild(thisNotification.firstChild);" .
76                         "thisNotification.remove();" .
77                     "})();"
78                 );
79             return;
80         }
82         // Add the notification directly to the session.
83         // This will either be fetched in the header, or by JS in the footer.
84         $SESSION->notifications[] = (object) array(
85             'message'   => $message,
86             'type'      => $level,
87         );
88     }
90     /**
91      * Fetch all of the notifications in the stack and clear the stack.
92      *
93      * @return array All of the notifications in the stack
94      */
95     public static function fetch() {
96         global $SESSION;
98         if (!isset($SESSION) || !isset($SESSION->notifications)) {
99             return [];
100         }
102         $notifications = $SESSION->notifications;
103         $SESSION->notifications = [];
105         $renderables = [];
106         foreach ($notifications as $notification) {
107             $renderable = new \core\output\notification($notification->message, $notification->type);
108             $renderables[] = $renderable;
109         }
111         return $renderables;
112     }
114     /**
115      * Fetch all of the notifications in the stack and clear the stack.
116      *
117      * @return array All of the notifications in the stack
118      */
119     public static function fetch_as_array(\renderer_base $renderer) {
120         $notifications = [];
121         foreach (self::fetch() as $notification) {
122             $notifications[] = [
123                 'template'  => $notification->get_template_name(),
124                 'variables' => $notification->export_for_template($renderer),
125             ];
126         }
127         return $notifications;
128     }
130     /**
131      * Add a success message to the notification stack.
132      *
133      * @param string $message The message to add to the stack
134      */
135     public static function success($message) {
136         return self::add($message, self::SUCCESS);
137     }
139     /**
140      * Add a info message to the notification stack.
141      *
142      * @param string $message The message to add to the stack
143      */
144     public static function info($message) {
145         return self::add($message, self::INFO);
146     }
148     /**
149      * Add a warning message to the notification stack.
150      *
151      * @param string $message The message to add to the stack
152      */
153     public static function warning($message) {
154         return self::add($message, self::WARNING);
155     }
157     /**
158      * Add a error message to the notification stack.
159      *
160      * @param string $message The message to add to the stack
161      */
162     public static function error($message) {
163         return self::add($message, self::ERROR);
164     }