MDL-68076 core: Introduced \core\notification::cta()
[moodle.git] / lib / classes / notification.php
CommitLineData
0346323c
AN
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
17namespace 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
2a00bd15
GK
27use stdClass;
28
0346323c
AN
29defined('MOODLE_INTERNAL') || die();
30
31class 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.
2f244f1c 86 if (!isset($SESSION->notifications) || !array($SESSION->notifications)) {
2a00bd15
GK
87 // Initialise $SESSION if necessary.
88 if (!is_object($SESSION)) {
89 $SESSION = new stdClass();
90 }
2f244f1c
AN
91 $SESSION->notifications = [];
92 }
0346323c
AN
93 $SESSION->notifications[] = (object) array(
94 'message' => $message,
95 'type' => $level,
96 );
97 }
98
3fecf7b5
SR
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
0346323c
AN
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;
2f244f1c 157 unset($SESSION->notifications);
0346323c
AN
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}