Completed
Pull Request — master (#551)
by Maxence
01:55
created

Member   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 552
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 0
Metric Value
wmc 55
lcom 2
cbo 7
dl 0
loc 552
rs 6
c 0
b 0
f 0

38 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A setId() 0 5 1
A getId() 0 3 1
A setCircleId() 0 5 1
A getCircleId() 0 3 1
A setSingleId() 0 5 1
A getSingleId() 0 3 1
A setUserId() 0 5 1
A getUserId() 0 3 1
A setUserType() 0 5 1
A getUserType() 0 3 1
A setInstance() 0 5 1
A getInstance() 0 3 1
A setLevel() 0 5 1
A getLevel() 0 3 1
A setStatus() 0 5 1
A getStatus() 0 3 1
A setNote() 0 5 1
A getNote() 0 3 1
A setCachedName() 0 5 1
A setCachedUpdate() 0 5 1
A getCachedUpdate() 0 3 1
A getCachedName() 0 3 1
A setContactId() 0 5 1
A getContactId() 0 3 1
A setContactMeta() 0 5 1
A getContactMeta() 0 3 1
A setCircle() 0 5 1
A getCircle() 0 3 1
A hasCircle() 0 3 1
A setJoined() 0 5 1
A getJoined() 0 3 1
A isMember() 0 3 1
B compareWith() 0 18 9
A import() 0 29 3
A jsonSerialize() 0 26 2
B importFromDatabase() 0 38 6
A parseLevelString() 0 11 2

How to fix   Complexity   

Complex Class

Complex classes like Member often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Member, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\Model;
33
34
use daita\MySmallPhpTools\Db\Nextcloud\nc21\INC21QueryRow;
35
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
36
use daita\MySmallPhpTools\Model\Nextcloud\nc21\INC21Convert;
37
use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Convert;
38
use daita\MySmallPhpTools\Traits\TArrayTools;
39
use DateTime;
40
use JsonSerializable;
41
use OCA\Circles\Exceptions\MemberLevelException;
42
use OCA\Circles\Exceptions\MemberNotFoundException;
43
use OCA\Circles\IFederatedUser;
44
45
46
/**
47
 * Class Member
48
 *
49
 * @package OCA\Circles\Model
50
 */
51
class Member extends ManagedModel implements IFederatedUser, INC21Convert, INC21QueryRow, JsonSerializable {
52
53
54
	use TArrayTools;
55
	use TNC21Convert;
56
57
58
	const LEVEL_NONE = 0;
59
	const LEVEL_MEMBER = 1;
60
	const LEVEL_MODERATOR = 4;
61
	const LEVEL_ADMIN = 8;
62
	const LEVEL_OWNER = 9;
63
64
	const TYPE_CIRCLE = 16;
65
	const TYPE_USER = 1;
66
	const TYPE_GROUP = 2;
67
	const TYPE_MAIL = 3;
68
	const TYPE_CONTACT = 4;
69
70
	const STATUS_NONMEMBER = 'Unknown';
71
	const STATUS_INVITED = 'Invited';
72
	const STATUS_REQUEST = 'Requesting';
73
	const STATUS_MEMBER = 'Member';
74
	const STATUS_BLOCKED = 'Blocked';
75
	const STATUS_KICKED = 'Kicked';
76
77
	static $DEF_LEVEL = [
78
		1 => 'Member',
79
		4 => 'Moderator',
80
		8 => 'Admin',
81
		9 => 'Owner'
82
	];
83
84
85
	/** @var string */
86
	private $id = '';
87
88
	/** @var string */
89
	private $circleId = '';
90
91
	/** @var string */
92
	private $singleId = '';
93
94
	/** @var string */
95
	private $userId = '';
96
97
	/** @var int */
98
	private $userType = self::TYPE_USER;
99
100
	/** @var string */
101
	private $instance = '';
102
103
	/** @var int */
104
	private $level = 0;
105
106
	/** @var string */
107
	private $status = 'Unknown';
108
109
	/** @var string */
110
	private $note = '';
111
112
	/** @var string */
113
	private $cachedName = '';
114
115
	/** @var int */
116
	private $cachedUpdate = 0;
117
118
	/** @var string */
119
	private $contactId = '';
120
121
	/** @var string */
122
	private $contactMeta = '';
123
124
	/** @var Circle */
125
	private $circle;
126
127
128
	/** @var int */
129
	private $joined = 0;
130
131
132
	/**
133
	 * Member constructor.
134
	 */
135
	public function __construct() {
136
	}
137
138
139
	/**
140
	 * @param string $id
141
	 *
142
	 * @return $this
143
	 */
144
	public function setId(string $id): self {
145
		$this->id = $id;
146
147
		return $this;
148
	}
149
150
	/**
151
	 * @return string
152
	 */
153
	public function getId(): string {
154
		return $this->id;
155
	}
156
157
158
	/**
159
	 * @param string $circleId
160
	 *
161
	 * @return Member
162
	 */
163
	public function setCircleId(string $circleId): self {
164
		$this->circleId = $circleId;
165
166
		return $this;
167
	}
168
169
	/**
170
	 * @return string
171
	 */
172
	public function getCircleId(): string {
173
		return $this->circleId;
174
	}
175
176
177
	/**
178
	 * This should replace user_id, user_type and instance; and will use the data from Circle with
179
	 * Config=CFG_SINGLE
180
	 *
181
	 * @param string $singleId
182
	 *
183
	 * @return $this
184
	 */
185
	public function setSingleId(string $singleId): self {
186
		$this->singleId = $singleId;
187
188
		return $this;
189
	}
190
191
	/**
192
	 * @return string
193
	 */
194
	public function getSingleId(): string {
195
		return $this->singleId;
196
	}
197
198
199
	/**
200
	 * @param string $userId
201
	 *
202
	 * @return Member
203
	 */
204
	public function setUserId(string $userId): self {
205
		$this->userId = $userId;
206
207
		return $this;
208
	}
209
210
	/**
211
	 * @return string
212
	 */
213
	public function getUserId(): string {
214
		return $this->userId;
215
	}
216
217
218
	/**
219
	 * @param int $userType
220
	 *
221
	 * @return Member
222
	 */
223
	public function setUserType(int $userType): self {
224
		$this->userType = $userType;
225
226
		return $this;
227
	}
228
229
	/**
230
	 * @return int
231
	 */
232
	public function getUserType(): int {
233
		return $this->userType;
234
	}
235
236
237
	/**
238
	 * @param string $instance
239
	 *
240
	 * @return Member
241
	 */
242
	public function setInstance(string $instance): self {
243
		$this->instance = $instance;
244
245
		return $this;
246
	}
247
248
	/**
249
	 * @return string
250
	 */
251
	public function getInstance(): string {
252
		return $this->instance;
253
	}
254
255
256
	/**
257
	 * @param int $level
258
	 *
259
	 * @return Member
260
	 */
261
	public function setLevel(int $level): self {
262
		$this->level = $level;
263
264
		return $this;
265
	}
266
267
	/**
268
	 * @return int
269
	 */
270
	public function getLevel(): int {
271
		return $this->level;
272
	}
273
274
275
	/**
276
	 * @param string $status
277
	 *
278
	 * @return Member
279
	 */
280
	public function setStatus(string $status): self {
281
		$this->status = $status;
282
283
		return $this;
284
	}
285
286
	/**
287
	 * @return string
288
	 */
289
	public function getStatus(): string {
290
		return $this->status;
291
	}
292
293
294
	/**
295
	 * @param string $note
296
	 *
297
	 * @return Member
298
	 */
299
	public function setNote(string $note): self {
300
		$this->note = $note;
301
302
		return $this;
303
	}
304
305
	/**
306
	 * @return string
307
	 */
308
	public function getNote(): string {
309
		return $this->note;
310
	}
311
312
313
	/**
314
	 * @param string $cachedName
315
	 *
316
	 * @return Member
317
	 */
318
	public function setCachedName(string $cachedName): self {
319
		$this->cachedName = $cachedName;
320
321
		return $this;
322
	}
323
324
325
	/**
326
	 * @param int $cachedUpdate
327
	 *
328
	 * @return Member
329
	 */
330
	public function setCachedUpdate(int $cachedUpdate): self {
331
		$this->cachedUpdate = $cachedUpdate;
332
333
		return $this;
334
	}
335
336
	/**
337
	 * @return int
338
	 */
339
	public function getCachedUpdate(): int {
340
		return $this->cachedUpdate;
341
	}
342
343
344
	/**
345
	 * @return string
346
	 */
347
	public function getCachedName(): string {
348
		return $this->cachedName;
349
	}
350
351
352
	/**
353
	 * @param string $contactId
354
	 *
355
	 * @return Member
356
	 */
357
	public function setContactId(string $contactId): self {
358
		$this->contactId = $contactId;
359
360
		return $this;
361
	}
362
363
	/**
364
	 * @return string
365
	 */
366
	public function getContactId(): string {
367
		return $this->contactId;
368
	}
369
370
371
	/**
372
	 * @param string $contactMeta
373
	 *
374
	 * @return Member
375
	 */
376
	public function setContactMeta(string $contactMeta): self {
377
		$this->contactMeta = $contactMeta;
378
379
		return $this;
380
	}
381
382
	/**
383
	 * @return string
384
	 */
385
	public function getContactMeta(): string {
386
		return $this->contactMeta;
387
	}
388
389
390
	/**
391
	 * @param Circle $circle
392
	 *
393
	 * @return self
394
	 */
395
	public function setCircle(Circle $circle): self {
396
		$this->circle = $circle;
397
398
		return $this;
399
	}
400
401
	/**
402
	 * @return Circle
403
	 */
404
	public function getCircle(): Circle {
405
		return $this->circle;
406
	}
407
408
	/**
409
	 * @return bool
410
	 */
411
	public function hasCircle(): bool {
412
		return (!is_null($this->circle));
413
	}
414
415
416
	/**
417
	 * @param int $joined
418
	 *
419
	 * @return Member
420
	 */
421
	public function setJoined(int $joined): self {
422
		$this->joined = $joined;
423
424
		return $this;
425
	}
426
427
	/**
428
	 * @return int
429
	 */
430
	public function getJoined(): int {
431
		return $this->joined;
432
	}
433
434
435
	/**
436
	 * @return bool
437
	 */
438
	public function isMember(): bool {
439
		return ($this->level > 0);
440
	}
441
442
443
	/**
444
	 * @param Member $member
445
	 * @param bool $full
446
	 *
447
	 * @return bool
448
	 */
449
	public function compareWith(Member $member, bool $full = true): bool {
450
		if ($this->getId() !== $member->getId()
451
			|| $this->getCircleId() !== $member->getCircleId()
452
			//			|| $this->getSingleId() !== $member->getSingleId()
453
			|| $this->getUserId() !== $member->getUserId()
454
			|| $this->getUserType() <> $member->getUserType()
455
			|| $this->getInstance() !== $member->getInstance()) {
456
			return false;
457
		}
458
459
		if ($full
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !($full && ($this...$member->getStatus()));.
Loading history...
460
			&& ($this->getLevel() <> $member->getLevel()
461
				|| $this->getStatus() !== $member->getStatus())) {
462
			return false;
463
		}
464
465
		return true;
466
	}
467
468
469
	/**
470
	 * @param array $data
471
	 *
472
	 * @return $this
473
	 * @throws InvalidItemException
474
	 */
475
	public function import(array $data): INC21Convert {
476
		if ($this->get('user_id', $data) === '') {
477
			throw new InvalidItemException();
478
		}
479
480
		$this->setId($this->get('id', $data));
481
		$this->setCircleId($this->get('circle_id', $data));
482
		$this->setSingleId($this->get('single_id', $data));
483
		$this->setUserId($this->get('user_id', $data));
484
		$this->setUserType($this->getInt('user_type', $data));
485
		$this->setInstance($this->get('instance', $data));
486
		$this->setLevel($this->getInt('level', $data));
487
		$this->setStatus($this->get('status', $data));
488
		$this->setCachedName($this->get('cached_name', $data));
489
		$this->setCachedUpdate($this->getInt('cached_update', $data));
490
		$this->setNote($this->get('note', $data));
491
		$this->setContactId($this->get('contact_id', $data));
492
		$this->setContactMeta($this->get('contact_meta', $data));
493
		$this->setJoined($this->getInt('joined', $data));
494
495
		try {
496
			/** @var Circle $circle */
497
			$circle = $this->convert($this->getArray('circle', $data), Circle::class);
498
			$this->setCircle($circle);
499
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
500
		}
501
502
		return $this;
503
	}
504
505
506
	/**
507
	 * @return string[]
508
	 */
509
	public function jsonSerialize(): array {
510
		$arr = array_filter(
511
			[
512
				'id'            => $this->getId(),
513
				'circle_id'     => $this->getCircleId(),
514
				'single_id'     => $this->getSingleId(),
515
				'user_id'       => $this->getUserId(),
516
				'user_type'     => $this->getUserType(),
517
				'instance'      => $this->getInstance(),
518
				'level'         => $this->getLevel(),
519
				'status'        => $this->getStatus(),
520
				'cached_name'   => $this->getCachedName(),
521
				'cached_update' => $this->getCachedUpdate(),
522
				'note'          => $this->getNote(),
523
				'contact_id'    => $this->getContactId(),
524
				'contact_meta'  => $this->getContactMeta(),
525
				'joined'        => $this->getJoined()
526
			]
527
		);
528
529
		if ($this->hasCircle()) {
530
			$arr['circle'] = $this->getCircle();
531
		}
532
533
		return $arr;
534
	}
535
536
537
	/**
538
	 * @param array $data
539
	 * @param string $prefix
540
	 *
541
	 * @return INC21QueryRow
542
	 * @throws MemberNotFoundException
543
	 */
544
	public function importFromDatabase(array $data, string $prefix = ''): INC21QueryRow {
545
		if (!array_key_exists($prefix . 'member_id', $data)) {
546
			throw new MemberNotFoundException();
547
		};
548
549
		$this->setId($this->get($prefix . 'member_id', $data));
550
		$this->setCircleId($this->get($prefix . 'circle_id', $data));
551
		$this->setSingleId($this->get($prefix . 'single_id', $data));
552
		$this->setUserId($this->get($prefix . 'user_id', $data));
553
		$this->setUserType($this->getInt($prefix . 'user_type', $data));
554
		$this->setInstance($this->get($prefix . 'instance', $data));
555
		$this->setLevel($this->getInt($prefix . 'level', $data));
556
		$this->setStatus($this->get($prefix . 'status', $data));
557
		$this->setCachedName($this->get($prefix . 'cached_name', $data));
558
		$this->setNote($this->get($prefix . 'note', $data));
559
		$this->setContactId($this->get($prefix . 'contact_id', $data));
560
		$this->setContactMeta($this->get($prefix . 'contact_meta', $data));
561
562
		$cachedUpdate = $this->get($prefix . 'cached_update', $data);
563
		if ($cachedUpdate !== '') {
564
			$this->setCachedUpdate(DateTime::createFromFormat('Y-m-d H:i:s', $cachedUpdate)->getTimestamp());
565
		}
566
567
		$joined = $this->get($prefix . 'joined', $data);
568
		if ($joined !== '') {
569
			$this->setJoined(DateTime::createFromFormat('Y-m-d H:i:s', $joined)->getTimestamp());
570
		}
571
572
		if ($this->getInstance() === '') {
573
			$this->setInstance($this->get('_params.local', $data));
574
		}
575
576
		if ($prefix === '') {
577
			$this->getManager()->importCircleFromDatabase($this, $data);
578
		}
579
580
		return $this;
581
	}
582
583
584
	/**
585
	 * @param string $levelString
586
	 *
587
	 * @return int
588
	 * @throws MemberLevelException
589
	 */
590
	public static function parseLevelString(string $levelString): int {
591
		$levelString = ucfirst(strtolower($levelString));
592
		$level = array_search($levelString, Member::$DEF_LEVEL);
593
594
		if (!$level) {
595
			$all = implode(', ', array_values(self::$DEF_LEVEL));
596
			throw new MemberLevelException('Available levels: ' . $all);
597
		}
598
599
		return (int)$level;
600
	}
601
602
}
603
604