Passed
Push — master ( aad8b3...fab277 )
by Joas
13:25 queued 11s
created
lib/private/Notification/Manager.php 1 patch
Indentation   +381 added lines, -381 removed lines patch added patch discarded remove patch
@@ -43,385 +43,385 @@
 block discarded – undo
43 43
 use Psr\Log\LoggerInterface;
44 44
 
45 45
 class Manager implements IManager {
46
-	/** @var IValidator */
47
-	protected $validator;
48
-	/** @var IUserManager */
49
-	private $userManager;
50
-	/** @var ICache */
51
-	protected $cache;
52
-	/** @var IRegistry */
53
-	protected $subscription;
54
-	/** @var LoggerInterface */
55
-	protected $logger;
56
-	/** @var Coordinator */
57
-	private $coordinator;
58
-
59
-	/** @var IApp[] */
60
-	protected $apps;
61
-	/** @var string[] */
62
-	protected $appClasses;
63
-
64
-	/** @var INotifier[] */
65
-	protected $notifiers;
66
-	/** @var string[] */
67
-	protected $notifierClasses;
68
-
69
-	/** @var bool */
70
-	protected $preparingPushNotification;
71
-	/** @var bool */
72
-	protected $deferPushing;
73
-	/** @var bool */
74
-	private $parsedRegistrationContext;
75
-
76
-	public function __construct(IValidator $validator,
77
-								IUserManager $userManager,
78
-								ICacheFactory $cacheFactory,
79
-								IRegistry $subscription,
80
-								LoggerInterface $logger,
81
-								Coordinator $coordinator) {
82
-		$this->validator = $validator;
83
-		$this->userManager = $userManager;
84
-		$this->cache = $cacheFactory->createDistributed('notifications');
85
-		$this->subscription = $subscription;
86
-		$this->logger = $logger;
87
-		$this->coordinator = $coordinator;
88
-
89
-		$this->apps = [];
90
-		$this->notifiers = [];
91
-		$this->appClasses = [];
92
-		$this->notifierClasses = [];
93
-		$this->preparingPushNotification = false;
94
-		$this->deferPushing = false;
95
-		$this->parsedRegistrationContext = false;
96
-	}
97
-	/**
98
-	 * @param string $appClass The service must implement IApp, otherwise a
99
-	 *                          \InvalidArgumentException is thrown later
100
-	 * @since 17.0.0
101
-	 */
102
-	public function registerApp(string $appClass): void {
103
-		$this->appClasses[] = $appClass;
104
-	}
105
-
106
-	/**
107
-	 * @param \Closure $service The service must implement INotifier, otherwise a
108
-	 *                          \InvalidArgumentException is thrown later
109
-	 * @param \Closure $info    An array with the keys 'id' and 'name' containing
110
-	 *                          the app id and the app name
111
-	 * @deprecated 17.0.0 use registerNotifierService instead.
112
-	 * @since 8.2.0 - Parameter $info was added in 9.0.0
113
-	 */
114
-	public function registerNotifier(\Closure $service, \Closure $info) {
115
-		$infoData = $info();
116
-		$exception = new \InvalidArgumentException(
117
-			'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
118
-		);
119
-		$this->logger->error($exception->getMessage(), ['exception' => $exception]);
120
-	}
121
-
122
-	/**
123
-	 * @param string $notifierService The service must implement INotifier, otherwise a
124
-	 *                          \InvalidArgumentException is thrown later
125
-	 * @since 17.0.0
126
-	 */
127
-	public function registerNotifierService(string $notifierService): void {
128
-		$this->notifierClasses[] = $notifierService;
129
-	}
130
-
131
-	/**
132
-	 * @return IApp[]
133
-	 */
134
-	protected function getApps(): array {
135
-		if (empty($this->appClasses)) {
136
-			return $this->apps;
137
-		}
138
-
139
-		foreach ($this->appClasses as $appClass) {
140
-			try {
141
-				$app = \OC::$server->get($appClass);
142
-			} catch (ContainerExceptionInterface $e) {
143
-				$this->logger->error('Failed to load notification app class: ' . $appClass, [
144
-					'exception' => $e,
145
-					'app' => 'notifications',
146
-				]);
147
-				continue;
148
-			}
149
-
150
-			if (!($app instanceof IApp)) {
151
-				$this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
152
-					'app' => 'notifications',
153
-				]);
154
-				continue;
155
-			}
156
-
157
-			$this->apps[] = $app;
158
-		}
159
-
160
-		$this->appClasses = [];
161
-
162
-		return $this->apps;
163
-	}
164
-
165
-	/**
166
-	 * @return INotifier[]
167
-	 */
168
-	public function getNotifiers(): array {
169
-		if (!$this->parsedRegistrationContext) {
170
-			$notifierServices = $this->coordinator->getRegistrationContext()->getNotifierServices();
171
-			foreach ($notifierServices as $notifierService) {
172
-				try {
173
-					$notifier = \OC::$server->get($notifierService->getService());
174
-				} catch (ContainerExceptionInterface $e) {
175
-					$this->logger->error('Failed to load notification notifier class: ' . $notifierService->getService(), [
176
-						'exception' => $e,
177
-						'app' => 'notifications',
178
-					]);
179
-					continue;
180
-				}
181
-
182
-				if (!($notifier instanceof INotifier)) {
183
-					$this->logger->error('Notification notifier class ' . $notifierService->getService() . ' is not implementing ' . INotifier::class, [
184
-						'app' => 'notifications',
185
-					]);
186
-					continue;
187
-				}
188
-
189
-				$this->notifiers[] = $notifier;
190
-			}
191
-
192
-			$this->parsedRegistrationContext = true;
193
-		}
194
-
195
-		if (empty($this->notifierClasses)) {
196
-			return $this->notifiers;
197
-		}
198
-
199
-		foreach ($this->notifierClasses as $notifierClass) {
200
-			try {
201
-				$notifier = \OC::$server->get($notifierClass);
202
-			} catch (ContainerExceptionInterface $e) {
203
-				$this->logger->error('Failed to load notification notifier class: ' . $notifierClass, [
204
-					'exception' => $e,
205
-					'app' => 'notifications',
206
-				]);
207
-				continue;
208
-			}
209
-
210
-			if (!($notifier instanceof INotifier)) {
211
-				$this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
212
-					'app' => 'notifications',
213
-				]);
214
-				continue;
215
-			}
216
-
217
-			$this->notifiers[] = $notifier;
218
-		}
219
-
220
-		$this->notifierClasses = [];
221
-
222
-		return $this->notifiers;
223
-	}
224
-
225
-	/**
226
-	 * @return INotification
227
-	 * @since 8.2.0
228
-	 */
229
-	public function createNotification(): INotification {
230
-		return new Notification($this->validator);
231
-	}
232
-
233
-	/**
234
-	 * @return bool
235
-	 * @since 8.2.0
236
-	 */
237
-	public function hasNotifiers(): bool {
238
-		return !empty($this->notifiers) || !empty($this->notifierClasses);
239
-	}
240
-
241
-	/**
242
-	 * @param bool $preparingPushNotification
243
-	 * @since 14.0.0
244
-	 */
245
-	public function setPreparingPushNotification(bool $preparingPushNotification): void {
246
-		$this->preparingPushNotification = $preparingPushNotification;
247
-	}
248
-
249
-	/**
250
-	 * @return bool
251
-	 * @since 14.0.0
252
-	 */
253
-	public function isPreparingPushNotification(): bool {
254
-		return $this->preparingPushNotification;
255
-	}
256
-
257
-	/**
258
-	 * The calling app should only "flush" when it got returned true on the defer call
259
-	 * @return bool
260
-	 * @since 20.0.0
261
-	 */
262
-	public function defer(): bool {
263
-		$alreadyDeferring = $this->deferPushing;
264
-		$this->deferPushing = true;
265
-
266
-		$apps = $this->getApps();
267
-
268
-		foreach ($apps as $app) {
269
-			if ($app instanceof IDeferrableApp) {
270
-				$app->defer();
271
-			}
272
-		}
273
-
274
-		return !$alreadyDeferring;
275
-	}
276
-
277
-	/**
278
-	 * @since 20.0.0
279
-	 */
280
-	public function flush(): void {
281
-		$apps = $this->getApps();
282
-
283
-		foreach ($apps as $app) {
284
-			if (!$app instanceof IDeferrableApp) {
285
-				continue;
286
-			}
287
-
288
-			try {
289
-				$app->flush();
290
-			} catch (\InvalidArgumentException $e) {
291
-			}
292
-		}
293
-
294
-		$this->deferPushing = false;
295
-	}
296
-
297
-	/**
298
-	 * {@inheritDoc}
299
-	 */
300
-	public function isFairUseOfFreePushService(): bool {
301
-		$pushAllowed = $this->cache->get('push_fair_use');
302
-		if ($pushAllowed === null) {
303
-			/**
304
-			 * We want to keep offering our push notification service for free, but large
305
-			 * users overload our infrastructure. For this reason we have to rate-limit the
306
-			 * use of push notifications. If you need this feature, consider using Nextcloud Enterprise.
307
-			 */
308
-			$isFairUse = $this->subscription->delegateHasValidSubscription() || $this->userManager->countSeenUsers() < 1000;
309
-			$pushAllowed = $isFairUse ? 'yes' : 'no';
310
-			$this->cache->set('push_fair_use', $pushAllowed, 3600);
311
-		}
312
-		return $pushAllowed === 'yes';
313
-	}
314
-
315
-	/**
316
-	 * @param INotification $notification
317
-	 * @throws \InvalidArgumentException When the notification is not valid
318
-	 * @since 8.2.0
319
-	 */
320
-	public function notify(INotification $notification): void {
321
-		if (!$notification->isValid()) {
322
-			throw new \InvalidArgumentException('The given notification is invalid');
323
-		}
324
-
325
-		$apps = $this->getApps();
326
-
327
-		foreach ($apps as $app) {
328
-			try {
329
-				$app->notify($notification);
330
-			} catch (\InvalidArgumentException $e) {
331
-			}
332
-		}
333
-	}
334
-
335
-	/**
336
-	 * Identifier of the notifier, only use [a-z0-9_]
337
-	 *
338
-	 * @return string
339
-	 * @since 17.0.0
340
-	 */
341
-	public function getID(): string {
342
-		return 'core';
343
-	}
344
-
345
-	/**
346
-	 * Human readable name describing the notifier
347
-	 *
348
-	 * @return string
349
-	 * @since 17.0.0
350
-	 */
351
-	public function getName(): string {
352
-		return 'core';
353
-	}
354
-
355
-	/**
356
-	 * @param INotification $notification
357
-	 * @param string $languageCode The code of the language that should be used to prepare the notification
358
-	 * @return INotification
359
-	 * @throws \InvalidArgumentException When the notification was not prepared by a notifier
360
-	 * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
361
-	 * @since 8.2.0
362
-	 */
363
-	public function prepare(INotification $notification, string $languageCode): INotification {
364
-		$notifiers = $this->getNotifiers();
365
-
366
-		foreach ($notifiers as $notifier) {
367
-			try {
368
-				$notification = $notifier->prepare($notification, $languageCode);
369
-			} catch (\InvalidArgumentException $e) {
370
-				continue;
371
-			} catch (AlreadyProcessedException $e) {
372
-				$this->markProcessed($notification);
373
-				throw new \InvalidArgumentException('The given notification has been processed');
374
-			}
375
-
376
-			if (!$notification->isValidParsed()) {
377
-				throw new \InvalidArgumentException('The given notification has not been handled');
378
-			}
379
-		}
380
-
381
-		if (!$notification->isValidParsed()) {
382
-			throw new \InvalidArgumentException('The given notification has not been handled');
383
-		}
384
-
385
-		return $notification;
386
-	}
387
-
388
-	/**
389
-	 * @param INotification $notification
390
-	 */
391
-	public function markProcessed(INotification $notification): void {
392
-		$apps = $this->getApps();
393
-
394
-		foreach ($apps as $app) {
395
-			$app->markProcessed($notification);
396
-		}
397
-	}
398
-
399
-	/**
400
-	 * @param INotification $notification
401
-	 * @return int
402
-	 */
403
-	public function getCount(INotification $notification): int {
404
-		$apps = $this->getApps();
405
-
406
-		$count = 0;
407
-		foreach ($apps as $app) {
408
-			$count += $app->getCount($notification);
409
-		}
410
-
411
-		return $count;
412
-	}
413
-
414
-	public function dismissNotification(INotification $notification): void {
415
-		$notifiers = $this->getNotifiers();
416
-
417
-		foreach ($notifiers as $notifier) {
418
-			if ($notifier instanceof IDismissableNotifier) {
419
-				try {
420
-					$notifier->dismissNotification($notification);
421
-				} catch (\InvalidArgumentException $e) {
422
-					continue;
423
-				}
424
-			}
425
-		}
426
-	}
46
+    /** @var IValidator */
47
+    protected $validator;
48
+    /** @var IUserManager */
49
+    private $userManager;
50
+    /** @var ICache */
51
+    protected $cache;
52
+    /** @var IRegistry */
53
+    protected $subscription;
54
+    /** @var LoggerInterface */
55
+    protected $logger;
56
+    /** @var Coordinator */
57
+    private $coordinator;
58
+
59
+    /** @var IApp[] */
60
+    protected $apps;
61
+    /** @var string[] */
62
+    protected $appClasses;
63
+
64
+    /** @var INotifier[] */
65
+    protected $notifiers;
66
+    /** @var string[] */
67
+    protected $notifierClasses;
68
+
69
+    /** @var bool */
70
+    protected $preparingPushNotification;
71
+    /** @var bool */
72
+    protected $deferPushing;
73
+    /** @var bool */
74
+    private $parsedRegistrationContext;
75
+
76
+    public function __construct(IValidator $validator,
77
+                                IUserManager $userManager,
78
+                                ICacheFactory $cacheFactory,
79
+                                IRegistry $subscription,
80
+                                LoggerInterface $logger,
81
+                                Coordinator $coordinator) {
82
+        $this->validator = $validator;
83
+        $this->userManager = $userManager;
84
+        $this->cache = $cacheFactory->createDistributed('notifications');
85
+        $this->subscription = $subscription;
86
+        $this->logger = $logger;
87
+        $this->coordinator = $coordinator;
88
+
89
+        $this->apps = [];
90
+        $this->notifiers = [];
91
+        $this->appClasses = [];
92
+        $this->notifierClasses = [];
93
+        $this->preparingPushNotification = false;
94
+        $this->deferPushing = false;
95
+        $this->parsedRegistrationContext = false;
96
+    }
97
+    /**
98
+     * @param string $appClass The service must implement IApp, otherwise a
99
+     *                          \InvalidArgumentException is thrown later
100
+     * @since 17.0.0
101
+     */
102
+    public function registerApp(string $appClass): void {
103
+        $this->appClasses[] = $appClass;
104
+    }
105
+
106
+    /**
107
+     * @param \Closure $service The service must implement INotifier, otherwise a
108
+     *                          \InvalidArgumentException is thrown later
109
+     * @param \Closure $info    An array with the keys 'id' and 'name' containing
110
+     *                          the app id and the app name
111
+     * @deprecated 17.0.0 use registerNotifierService instead.
112
+     * @since 8.2.0 - Parameter $info was added in 9.0.0
113
+     */
114
+    public function registerNotifier(\Closure $service, \Closure $info) {
115
+        $infoData = $info();
116
+        $exception = new \InvalidArgumentException(
117
+            'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
118
+        );
119
+        $this->logger->error($exception->getMessage(), ['exception' => $exception]);
120
+    }
121
+
122
+    /**
123
+     * @param string $notifierService The service must implement INotifier, otherwise a
124
+     *                          \InvalidArgumentException is thrown later
125
+     * @since 17.0.0
126
+     */
127
+    public function registerNotifierService(string $notifierService): void {
128
+        $this->notifierClasses[] = $notifierService;
129
+    }
130
+
131
+    /**
132
+     * @return IApp[]
133
+     */
134
+    protected function getApps(): array {
135
+        if (empty($this->appClasses)) {
136
+            return $this->apps;
137
+        }
138
+
139
+        foreach ($this->appClasses as $appClass) {
140
+            try {
141
+                $app = \OC::$server->get($appClass);
142
+            } catch (ContainerExceptionInterface $e) {
143
+                $this->logger->error('Failed to load notification app class: ' . $appClass, [
144
+                    'exception' => $e,
145
+                    'app' => 'notifications',
146
+                ]);
147
+                continue;
148
+            }
149
+
150
+            if (!($app instanceof IApp)) {
151
+                $this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
152
+                    'app' => 'notifications',
153
+                ]);
154
+                continue;
155
+            }
156
+
157
+            $this->apps[] = $app;
158
+        }
159
+
160
+        $this->appClasses = [];
161
+
162
+        return $this->apps;
163
+    }
164
+
165
+    /**
166
+     * @return INotifier[]
167
+     */
168
+    public function getNotifiers(): array {
169
+        if (!$this->parsedRegistrationContext) {
170
+            $notifierServices = $this->coordinator->getRegistrationContext()->getNotifierServices();
171
+            foreach ($notifierServices as $notifierService) {
172
+                try {
173
+                    $notifier = \OC::$server->get($notifierService->getService());
174
+                } catch (ContainerExceptionInterface $e) {
175
+                    $this->logger->error('Failed to load notification notifier class: ' . $notifierService->getService(), [
176
+                        'exception' => $e,
177
+                        'app' => 'notifications',
178
+                    ]);
179
+                    continue;
180
+                }
181
+
182
+                if (!($notifier instanceof INotifier)) {
183
+                    $this->logger->error('Notification notifier class ' . $notifierService->getService() . ' is not implementing ' . INotifier::class, [
184
+                        'app' => 'notifications',
185
+                    ]);
186
+                    continue;
187
+                }
188
+
189
+                $this->notifiers[] = $notifier;
190
+            }
191
+
192
+            $this->parsedRegistrationContext = true;
193
+        }
194
+
195
+        if (empty($this->notifierClasses)) {
196
+            return $this->notifiers;
197
+        }
198
+
199
+        foreach ($this->notifierClasses as $notifierClass) {
200
+            try {
201
+                $notifier = \OC::$server->get($notifierClass);
202
+            } catch (ContainerExceptionInterface $e) {
203
+                $this->logger->error('Failed to load notification notifier class: ' . $notifierClass, [
204
+                    'exception' => $e,
205
+                    'app' => 'notifications',
206
+                ]);
207
+                continue;
208
+            }
209
+
210
+            if (!($notifier instanceof INotifier)) {
211
+                $this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
212
+                    'app' => 'notifications',
213
+                ]);
214
+                continue;
215
+            }
216
+
217
+            $this->notifiers[] = $notifier;
218
+        }
219
+
220
+        $this->notifierClasses = [];
221
+
222
+        return $this->notifiers;
223
+    }
224
+
225
+    /**
226
+     * @return INotification
227
+     * @since 8.2.0
228
+     */
229
+    public function createNotification(): INotification {
230
+        return new Notification($this->validator);
231
+    }
232
+
233
+    /**
234
+     * @return bool
235
+     * @since 8.2.0
236
+     */
237
+    public function hasNotifiers(): bool {
238
+        return !empty($this->notifiers) || !empty($this->notifierClasses);
239
+    }
240
+
241
+    /**
242
+     * @param bool $preparingPushNotification
243
+     * @since 14.0.0
244
+     */
245
+    public function setPreparingPushNotification(bool $preparingPushNotification): void {
246
+        $this->preparingPushNotification = $preparingPushNotification;
247
+    }
248
+
249
+    /**
250
+     * @return bool
251
+     * @since 14.0.0
252
+     */
253
+    public function isPreparingPushNotification(): bool {
254
+        return $this->preparingPushNotification;
255
+    }
256
+
257
+    /**
258
+     * The calling app should only "flush" when it got returned true on the defer call
259
+     * @return bool
260
+     * @since 20.0.0
261
+     */
262
+    public function defer(): bool {
263
+        $alreadyDeferring = $this->deferPushing;
264
+        $this->deferPushing = true;
265
+
266
+        $apps = $this->getApps();
267
+
268
+        foreach ($apps as $app) {
269
+            if ($app instanceof IDeferrableApp) {
270
+                $app->defer();
271
+            }
272
+        }
273
+
274
+        return !$alreadyDeferring;
275
+    }
276
+
277
+    /**
278
+     * @since 20.0.0
279
+     */
280
+    public function flush(): void {
281
+        $apps = $this->getApps();
282
+
283
+        foreach ($apps as $app) {
284
+            if (!$app instanceof IDeferrableApp) {
285
+                continue;
286
+            }
287
+
288
+            try {
289
+                $app->flush();
290
+            } catch (\InvalidArgumentException $e) {
291
+            }
292
+        }
293
+
294
+        $this->deferPushing = false;
295
+    }
296
+
297
+    /**
298
+     * {@inheritDoc}
299
+     */
300
+    public function isFairUseOfFreePushService(): bool {
301
+        $pushAllowed = $this->cache->get('push_fair_use');
302
+        if ($pushAllowed === null) {
303
+            /**
304
+             * We want to keep offering our push notification service for free, but large
305
+             * users overload our infrastructure. For this reason we have to rate-limit the
306
+             * use of push notifications. If you need this feature, consider using Nextcloud Enterprise.
307
+             */
308
+            $isFairUse = $this->subscription->delegateHasValidSubscription() || $this->userManager->countSeenUsers() < 1000;
309
+            $pushAllowed = $isFairUse ? 'yes' : 'no';
310
+            $this->cache->set('push_fair_use', $pushAllowed, 3600);
311
+        }
312
+        return $pushAllowed === 'yes';
313
+    }
314
+
315
+    /**
316
+     * @param INotification $notification
317
+     * @throws \InvalidArgumentException When the notification is not valid
318
+     * @since 8.2.0
319
+     */
320
+    public function notify(INotification $notification): void {
321
+        if (!$notification->isValid()) {
322
+            throw new \InvalidArgumentException('The given notification is invalid');
323
+        }
324
+
325
+        $apps = $this->getApps();
326
+
327
+        foreach ($apps as $app) {
328
+            try {
329
+                $app->notify($notification);
330
+            } catch (\InvalidArgumentException $e) {
331
+            }
332
+        }
333
+    }
334
+
335
+    /**
336
+     * Identifier of the notifier, only use [a-z0-9_]
337
+     *
338
+     * @return string
339
+     * @since 17.0.0
340
+     */
341
+    public function getID(): string {
342
+        return 'core';
343
+    }
344
+
345
+    /**
346
+     * Human readable name describing the notifier
347
+     *
348
+     * @return string
349
+     * @since 17.0.0
350
+     */
351
+    public function getName(): string {
352
+        return 'core';
353
+    }
354
+
355
+    /**
356
+     * @param INotification $notification
357
+     * @param string $languageCode The code of the language that should be used to prepare the notification
358
+     * @return INotification
359
+     * @throws \InvalidArgumentException When the notification was not prepared by a notifier
360
+     * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
361
+     * @since 8.2.0
362
+     */
363
+    public function prepare(INotification $notification, string $languageCode): INotification {
364
+        $notifiers = $this->getNotifiers();
365
+
366
+        foreach ($notifiers as $notifier) {
367
+            try {
368
+                $notification = $notifier->prepare($notification, $languageCode);
369
+            } catch (\InvalidArgumentException $e) {
370
+                continue;
371
+            } catch (AlreadyProcessedException $e) {
372
+                $this->markProcessed($notification);
373
+                throw new \InvalidArgumentException('The given notification has been processed');
374
+            }
375
+
376
+            if (!$notification->isValidParsed()) {
377
+                throw new \InvalidArgumentException('The given notification has not been handled');
378
+            }
379
+        }
380
+
381
+        if (!$notification->isValidParsed()) {
382
+            throw new \InvalidArgumentException('The given notification has not been handled');
383
+        }
384
+
385
+        return $notification;
386
+    }
387
+
388
+    /**
389
+     * @param INotification $notification
390
+     */
391
+    public function markProcessed(INotification $notification): void {
392
+        $apps = $this->getApps();
393
+
394
+        foreach ($apps as $app) {
395
+            $app->markProcessed($notification);
396
+        }
397
+    }
398
+
399
+    /**
400
+     * @param INotification $notification
401
+     * @return int
402
+     */
403
+    public function getCount(INotification $notification): int {
404
+        $apps = $this->getApps();
405
+
406
+        $count = 0;
407
+        foreach ($apps as $app) {
408
+            $count += $app->getCount($notification);
409
+        }
410
+
411
+        return $count;
412
+    }
413
+
414
+    public function dismissNotification(INotification $notification): void {
415
+        $notifiers = $this->getNotifiers();
416
+
417
+        foreach ($notifiers as $notifier) {
418
+            if ($notifier instanceof IDismissableNotifier) {
419
+                try {
420
+                    $notifier->dismissNotification($notification);
421
+                } catch (\InvalidArgumentException $e) {
422
+                    continue;
423
+                }
424
+            }
425
+        }
426
+    }
427 427
 }
Please login to merge, or discard this patch.