PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Notification / Manager.php
matomo / app / core / Notification Last commit date
Manager.php 6 months ago
Manager.php
191 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik\Notification;
10
11 use Piwik\Notification;
12 use Piwik\Session;
13 use Piwik\Session\SessionNamespace;
14 /**
15 * Posts and removes UI notifications (see {@link Piwik\Notification} to learn more).
16 *
17 */
18 class Manager
19 {
20 public const MAX_NOTIFICATIONS_IN_SESSION = 30;
21 /**
22 * @var ?SessionNamespace
23 */
24 private static $session = null;
25 /**
26 * @var array<string, Notification>
27 */
28 private static $notifications = [];
29 /**
30 * Posts a notification that will be shown in Piwik's status bar. If a notification with the same ID
31 * has been posted and has not been closed/removed, it will be replaced with `$notification`.
32 *
33 * @param string $id A unique identifier for this notification. The ID must be a valid HTML
34 * element ID. It can only contain alphanumeric characters (underscores can
35 * be used).
36 * @param Notification $notification The notification to post.
37 * @return bool true if the notification was added, false if it was ignored because there were too many
38 * pending ones.
39 * @api
40 */
41 public static function notify($id, Notification $notification) : bool
42 {
43 self::checkId($id);
44 self::removeOldestNotificationsIfThereAreTooMany();
45 return self::addNotification($id, $notification);
46 }
47 /**
48 * Removes a posted notification by ID.
49 *
50 * @param string $id The notification ID, see {@link notify()}.
51 */
52 public static function cancel($id) : void
53 {
54 self::checkId($id);
55 self::removeNotification($id);
56 }
57 /**
58 * Removes all temporary notifications.
59 *
60 * Call this method after the notifications have been
61 * displayed to make sure temporary notifications won't be displayed twice.
62 */
63 public static function cancelAllNonPersistent() : void
64 {
65 foreach (self::getAllNotifications() as $id => $notification) {
66 if (Notification::TYPE_PERSISTENT != $notification->type) {
67 self::removeNotification($id);
68 }
69 }
70 }
71 /**
72 * Determine all notifications that needs to be displayed. They are sorted by priority. Highest priorities first.
73 * @return array<string, Notification>
74 */
75 public static function getAllNotificationsToDisplay() : array
76 {
77 $notifications = self::getAllNotifications();
78 uasort($notifications, function ($n1, $n2) {
79 /** @var Notification $n1 */
80 /** @var Notification $n2 */
81 if ($n1->getPriority() == $n2->getPriority()) {
82 return 0;
83 }
84 return $n1->getPriority() > $n2->getPriority() ? -1 : 1;
85 });
86 return $notifications;
87 }
88 /**
89 * @param $id
90 * @throws \Exception In case id is empty or if id contains non word characters
91 */
92 private static function checkId($id) : void
93 {
94 if (empty($id)) {
95 throw new \Exception('Notification ID is empty.');
96 }
97 if (!preg_match('/^\\w*$/', $id)) {
98 throw new \Exception('Invalid Notification ID given. Only word characters (AlNum + underscore) allowed.');
99 }
100 }
101 private static function addNotification($id, Notification $notification) : bool
102 {
103 self::saveNotificationAcrossUiRequestsIfNeeded($id, $notification);
104 if (count(self::$notifications) >= self::MAX_NOTIFICATIONS_IN_SESSION) {
105 return \false;
106 }
107 // we store all kinda notifications here so in case the session is not enabled or disabled later there is still
108 // a chance it gets delivered to the UI during the same request.
109 self::$notifications[$id] = $notification;
110 return \true;
111 }
112 private static function saveNotificationAcrossUiRequestsIfNeeded($id, Notification $notification) : void
113 {
114 if (self::isSessionEnabled()) {
115 // we need to save even non persistent notifications if possible. Otherwise if there's a redirect
116 // a notification is not shown on the next page view
117 $session = self::getSession();
118 $session->notifications[$id] = $notification;
119 }
120 }
121 private static function removeOldestNotificationsIfThereAreTooMany() : void
122 {
123 if (!self::isSessionEnabled()) {
124 return;
125 }
126 $maxNotificationsInSession = self::MAX_NOTIFICATIONS_IN_SESSION;
127 $session = self::getSession();
128 while (count($session->notifications) >= $maxNotificationsInSession) {
129 array_shift($session->notifications);
130 }
131 }
132 /**
133 * @return array<string, Notification>
134 */
135 private static function getAllNotifications() : array
136 {
137 if (!self::isSessionEnabled()) {
138 return [];
139 }
140 $notifications = self::$notifications;
141 foreach ($notifications as $id => $notification) {
142 // we copy them over to the session if possible and persist it in case the session was not yet
143 // writable / enabled at the time the notification was added.
144 self::saveNotificationAcrossUiRequestsIfNeeded($id, $notification);
145 }
146 $session = self::getSession();
147 foreach ($session->notifications as $id => $notification) {
148 $notifications[$id] = $notification;
149 }
150 return $notifications;
151 }
152 private static function removeNotification($id) : void
153 {
154 if (array_key_exists($id, self::$notifications)) {
155 unset(self::$notifications[$id]);
156 }
157 if (self::isSessionEnabled()) {
158 $session = self::getSession();
159 if (array_key_exists($id, $session->notifications)) {
160 unset($session->notifications[$id]);
161 }
162 }
163 }
164 private static function isSessionEnabled() : bool
165 {
166 return Session::isWritable() && Session::isReadable();
167 }
168 private static function getSession() : SessionNamespace
169 {
170 if (!isset(self::$session)) {
171 self::$session = new SessionNamespace('notification');
172 }
173 if (empty(self::$session->notifications) && self::isSessionEnabled()) {
174 self::$session->notifications = [];
175 }
176 return self::$session;
177 }
178 public static function cancelAllNotifications() : void
179 {
180 self::$notifications = [];
181 }
182 /**
183 * for tests
184 * @return array<string, Notification>
185 */
186 public static function getPendingInMemoryNotifications() : array
187 {
188 return self::$notifications;
189 }
190 }
191