Passed
Push — master ( 403388...874eff )
by Roeland
17:00 queued 11s
created

Manager::getNotifiers()   B

Complexity

Conditions 9
Paths 10

Size

Total Lines 55
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 33
nc 10
nop 0
dl 0
loc 55
rs 8.0555
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 *
8
 * @author Joas Schilling <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Roeland Jago Douma <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program. If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OC\Notification;
29
30
use OC\AppFramework\Bootstrap\Coordinator;
31
use OCP\AppFramework\QueryException;
32
use OCP\ILogger;
33
use OCP\Notification\AlreadyProcessedException;
34
use OCP\Notification\IApp;
35
use OCP\Notification\IDeferrableApp;
36
use OCP\Notification\IDismissableNotifier;
37
use OCP\Notification\IManager;
38
use OCP\Notification\INotification;
39
use OCP\Notification\INotifier;
40
use OCP\RichObjectStrings\IValidator;
41
42
class Manager implements IManager {
43
	/** @var IValidator */
44
	protected $validator;
45
	/** @var ILogger */
46
	protected $logger;
47
	/** @var Coordinator */
48
	private $coordinator;
49
50
	/** @var IApp[] */
51
	protected $apps;
52
	/** @var string[] */
53
	protected $appClasses;
54
55
	/** @var INotifier[] */
56
	protected $notifiers;
57
	/** @var string[] */
58
	protected $notifierClasses;
59
60
	/** @var bool */
61
	protected $preparingPushNotification;
62
	/** @var bool */
63
	protected $deferPushing;
64
	/** @var bool */
65
	private $parsedRegistrationContext;
66
67
	public function __construct(IValidator $validator,
68
								ILogger $logger,
69
								Coordinator $coordinator) {
70
		$this->validator = $validator;
71
		$this->logger = $logger;
72
		$this->coordinator = $coordinator;
73
74
		$this->apps = [];
75
		$this->notifiers = [];
76
		$this->appClasses = [];
77
		$this->notifierClasses = [];
78
		$this->preparingPushNotification = false;
79
		$this->deferPushing = false;
80
		$this->parsedRegistrationContext = false;
81
	}
82
	/**
83
	 * @param string $appClass The service must implement IApp, otherwise a
84
	 *                          \InvalidArgumentException is thrown later
85
	 * @since 17.0.0
86
	 */
87
	public function registerApp(string $appClass): void {
88
		$this->appClasses[] = $appClass;
89
	}
90
91
	/**
92
	 * @param \Closure $service The service must implement INotifier, otherwise a
93
	 *                          \InvalidArgumentException is thrown later
94
	 * @param \Closure $info    An array with the keys 'id' and 'name' containing
95
	 *                          the app id and the app name
96
	 * @deprecated 17.0.0 use registerNotifierService instead.
97
	 * @since 8.2.0 - Parameter $info was added in 9.0.0
98
	 */
99
	public function registerNotifier(\Closure $service, \Closure $info) {
100
		$infoData = $info();
101
		$this->logger->logException(new \InvalidArgumentException(
102
			'Notifier ' . $infoData['name'] . ' (id: ' . $infoData['id'] . ') is not considered because it is using the old way to register.'
103
		));
104
	}
105
106
	/**
107
	 * @param string $notifierService The service must implement INotifier, otherwise a
108
	 *                          \InvalidArgumentException is thrown later
109
	 * @since 17.0.0
110
	 */
111
	public function registerNotifierService(string $notifierService): void {
112
		$this->notifierClasses[] = $notifierService;
113
	}
114
115
	/**
116
	 * @return IApp[]
117
	 */
118
	protected function getApps(): array {
119
		if (empty($this->appClasses)) {
120
			return $this->apps;
121
		}
122
123
		foreach ($this->appClasses as $appClass) {
124
			try {
125
				$app = \OC::$server->query($appClass);
126
			} catch (QueryException $e) {
127
				$this->logger->logException($e, [
128
					'message' => 'Failed to load notification app class: ' . $appClass,
129
					'app' => 'notifications',
130
				]);
131
				continue;
132
			}
133
134
			if (!($app instanceof IApp)) {
135
				$this->logger->error('Notification app class ' . $appClass . ' is not implementing ' . IApp::class, [
136
					'app' => 'notifications',
137
				]);
138
				continue;
139
			}
140
141
			$this->apps[] = $app;
142
		}
143
144
		$this->appClasses = [];
145
146
		return $this->apps;
147
	}
148
149
	/**
150
	 * @return INotifier[]
151
	 */
152
	public function getNotifiers(): array {
153
		if (!$this->parsedRegistrationContext) {
154
			$notifierServices = $this->coordinator->getRegistrationContext()->getNotifierServices();
155
			foreach ($notifierServices as $notifierService) {
156
				try {
157
					$notifier = \OC::$server->query($notifierService->getService());
158
				} catch (QueryException $e) {
159
					$this->logger->logException($e, [
160
						'message' => 'Failed to load notification notifier class: ' . $notifierService->getService(),
161
						'app' => 'notifications',
162
					]);
163
					continue;
164
				}
165
166
				if (!($notifier instanceof INotifier)) {
167
					$this->logger->error('Notification notifier class ' . $notifierService->getService() . ' is not implementing ' . INotifier::class, [
168
						'app' => 'notifications',
169
					]);
170
					continue;
171
				}
172
173
				$this->notifiers[] = $notifier;
174
			}
175
176
			$this->parsedRegistrationContext = true;
177
		}
178
179
		if (empty($this->notifierClasses)) {
180
			return $this->notifiers;
181
		}
182
183
		foreach ($this->notifierClasses as $notifierClass) {
184
			try {
185
				$notifier = \OC::$server->query($notifierClass);
186
			} catch (QueryException $e) {
187
				$this->logger->logException($e, [
188
					'message' => 'Failed to load notification notifier class: ' . $notifierClass,
189
					'app' => 'notifications',
190
				]);
191
				continue;
192
			}
193
194
			if (!($notifier instanceof INotifier)) {
195
				$this->logger->error('Notification notifier class ' . $notifierClass . ' is not implementing ' . INotifier::class, [
196
					'app' => 'notifications',
197
				]);
198
				continue;
199
			}
200
201
			$this->notifiers[] = $notifier;
202
		}
203
204
		$this->notifierClasses = [];
205
206
		return $this->notifiers;
207
	}
208
209
	/**
210
	 * @return INotification
211
	 * @since 8.2.0
212
	 */
213
	public function createNotification(): INotification {
214
		return new Notification($this->validator);
215
	}
216
217
	/**
218
	 * @return bool
219
	 * @since 8.2.0
220
	 */
221
	public function hasNotifiers(): bool {
222
		return !empty($this->notifiers) || !empty($this->notifierClasses);
223
	}
224
225
	/**
226
	 * @param bool $preparingPushNotification
227
	 * @since 14.0.0
228
	 */
229
	public function setPreparingPushNotification(bool $preparingPushNotification): void {
230
		$this->preparingPushNotification = $preparingPushNotification;
231
	}
232
233
	/**
234
	 * @return bool
235
	 * @since 14.0.0
236
	 */
237
	public function isPreparingPushNotification(): bool {
238
		return $this->preparingPushNotification;
239
	}
240
241
	/**
242
	 * The calling app should only "flush" when it got returned true on the defer call
243
	 * @return bool
244
	 * @since 20.0.0
245
	 */
246
	public function defer(): bool {
247
		$alreadyDeferring = $this->deferPushing;
248
		$this->deferPushing = true;
249
250
		$apps = $this->getApps();
251
252
		foreach ($apps as $app) {
253
			if ($app instanceof IDeferrableApp) {
254
				$app->defer();
255
			}
256
		}
257
258
		return !$alreadyDeferring;
259
	}
260
261
	/**
262
	 * @since 20.0.0
263
	 */
264
	public function flush(): void {
265
		$apps = $this->getApps();
266
267
		foreach ($apps as $app) {
268
			if (!$app instanceof IDeferrableApp) {
269
				continue;
270
			}
271
272
			try {
273
				$app->flush();
274
			} catch (\InvalidArgumentException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
275
			}
276
		}
277
278
		$this->deferPushing = false;
279
	}
280
281
	/**
282
	 * @param INotification $notification
283
	 * @throws \InvalidArgumentException When the notification is not valid
284
	 * @since 8.2.0
285
	 */
286
	public function notify(INotification $notification): void {
287
		if (!$notification->isValid()) {
288
			throw new \InvalidArgumentException('The given notification is invalid');
289
		}
290
291
		$apps = $this->getApps();
292
293
		foreach ($apps as $app) {
294
			try {
295
				$app->notify($notification);
296
			} catch (\InvalidArgumentException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
297
			}
298
		}
299
	}
300
301
	/**
302
	 * Identifier of the notifier, only use [a-z0-9_]
303
	 *
304
	 * @return string
305
	 * @since 17.0.0
306
	 */
307
	public function getID(): string {
308
		return 'core';
309
	}
310
311
	/**
312
	 * Human readable name describing the notifier
313
	 *
314
	 * @return string
315
	 * @since 17.0.0
316
	 */
317
	public function getName(): string {
318
		return 'core';
319
	}
320
321
	/**
322
	 * @param INotification $notification
323
	 * @param string $languageCode The code of the language that should be used to prepare the notification
324
	 * @return INotification
325
	 * @throws \InvalidArgumentException When the notification was not prepared by a notifier
326
	 * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
327
	 * @since 8.2.0
328
	 */
329
	public function prepare(INotification $notification, string $languageCode): INotification {
330
		$notifiers = $this->getNotifiers();
331
332
		foreach ($notifiers as $notifier) {
333
			try {
334
				$notification = $notifier->prepare($notification, $languageCode);
335
			} catch (\InvalidArgumentException $e) {
336
				continue;
337
			} catch (AlreadyProcessedException $e) {
338
				$this->markProcessed($notification);
339
				throw new \InvalidArgumentException('The given notification has been processed');
340
			}
341
342
			if (!($notification instanceof INotification) || !$notification->isValidParsed()) {
343
				throw new \InvalidArgumentException('The given notification has not been handled');
344
			}
345
		}
346
347
		if (!($notification instanceof INotification) || !$notification->isValidParsed()) {
0 ignored issues
show
introduced by
$notification is always a sub-type of OCP\Notification\INotification.
Loading history...
348
			throw new \InvalidArgumentException('The given notification has not been handled');
349
		}
350
351
		return $notification;
352
	}
353
354
	/**
355
	 * @param INotification $notification
356
	 */
357
	public function markProcessed(INotification $notification): void {
358
		$apps = $this->getApps();
359
360
		foreach ($apps as $app) {
361
			$app->markProcessed($notification);
362
		}
363
	}
364
365
	/**
366
	 * @param INotification $notification
367
	 * @return int
368
	 */
369
	public function getCount(INotification $notification): int {
370
		$apps = $this->getApps();
371
372
		$count = 0;
373
		foreach ($apps as $app) {
374
			$count += $app->getCount($notification);
375
		}
376
377
		return $count;
378
	}
379
380
	public function dismissNotification(INotification $notification): void {
381
		$notifiers = $this->getNotifiers();
382
383
		foreach ($notifiers as $notifier) {
384
			if ($notifier instanceof IDismissableNotifier) {
385
				try {
386
					$notifier->dismissNotification($notification);
387
				} catch (\InvalidArgumentException $e) {
388
					continue;
389
				}
390
			}
391
		}
392
	}
393
}
394