Completed
Pull Request — master (#586)
by Maxence
02:16
created

Member::parseLevelString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 1
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\nc22\INC22QueryRow;
35
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
36
use daita\MySmallPhpTools\IDeserializable;
37
use daita\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize;
38
use daita\MySmallPhpTools\Traits\TArrayTools;
39
use DateTime;
40
use JsonSerializable;
41
use OCA\Circles\AppInfo\Capabilities;
42
use OCA\Circles\Exceptions\MemberNotFoundException;
43
use OCA\Circles\Exceptions\ParseMemberLevelException;
44
use OCA\Circles\Exceptions\UserTypeNotFoundException;
45
use OCA\Circles\IFederatedUser;
46
use OCA\Circles\IMemberships;
47
use OCA\Circles\Model\Federated\RemoteInstance;
48
49
50
/**
51
 * Class Member
52
 *
53
 * @package OCA\Circles\Model
54
 */
55
class Member extends ManagedModel implements
56
	IMemberships,
57
	IFederatedUser,
58
	IDeserializable,
59
	INC22QueryRow,
60
	JsonSerializable {
61
62
63
	use TArrayTools;
64
	use TNC22Deserialize;
65
66
67
	const LEVEL_NONE = 0;
68
	const LEVEL_MEMBER = 1;
69
	const LEVEL_MODERATOR = 4;
70
	const LEVEL_ADMIN = 8;
71
	const LEVEL_OWNER = 9;
72
73
	const TYPE_SINGLE = 0;
74
	const TYPE_USER = 1;
75
	const TYPE_GROUP = 2;
76
	const TYPE_MAIL = 4;
77
	const TYPE_CONTACT = 8;
78
	const TYPE_CIRCLE = 16;
79
	const TYPE_APP = 10000;
80
	const APP_CIRCLES = 10001;
81
82
83
	public static $TYPE = [
84
		0     => 'single',
85
		1     => 'user',
86
		2     => 'group',
87
		4     => 'mail',
88
		8     => 'contact',
89
		16    => 'circle',
90
		10000 => 'app'
91
	];
92
93
	/**
94
	 * Note: When editing those values, update lib/Application/Capabilities.php
95
	 *
96
	 * @see Capabilities::generateConstantsMember()
97
	 */
98
	const STATUS_INVITED = 'Invited';
99
	const STATUS_REQUEST = 'Requesting';
100
	const STATUS_MEMBER = 'Member';
101
	const STATUS_BLOCKED = 'Blocked';
102
103
104
	/**
105
	 * Note: When editing those values, update lib/Application/Capabilities.php
106
	 *
107
	 * @see Capabilities::generateConstantsMember()
108
	 * @var array
109
	 */
110
	public static $DEF_LEVEL = [
111
		1 => 'Member',
112
		4 => 'Moderator',
113
		8 => 'Admin',
114
		9 => 'Owner'
115
	];
116
117
118
	public static $DEF_TYPE_MAX = 31;
119
120
121
	/** @var string */
122
	private $id = '';
123
124
	/** @var string */
125
	private $circleId = '';
126
127
	/** @var string */
128
	private $singleId = '';
129
130
	/** @var string */
131
	private $userId = '';
132
133
	/** @var int */
134
	private $userType = 0;
135
136
	/** @var Circle */
137
	private $basedOn;
138
139
	/** @var Member */
140
	private $inheritanceFrom;
141
142
	/** @var FederatedUser */
143
	private $inheritedBy;
144
145
	/** @var string */
146
	private $instance = '';
147
148
	/** @var RemoteInstance */
149
	private $remoteInstance;
150
151
	/** @var bool */
152
	private $local = false;
153
154
	/** @var int */
155
	private $level = 0;
156
157
	/** @var string */
158
	private $status = 'Unknown';
159
160
	/** @var string */
161
	private $note = '';
162
163
	/** @var string */
164
	private $displayName = '';
165
166
	/** @var int */
167
	private $displayUpdate = 0;
168
169
	/** @var string */
170
	private $contactId = '';
171
172
	/** @var string */
173
	private $contactMeta = '';
174
175
	/** @var Circle */
176
	private $circle;
177
178
	/** @var int */
179
	private $joined = 0;
180
181
	/** @var Membership[] */
182
	private $memberships = null;
183
184
185
	/**
186
	 * Member constructor.
187
	 */
188
	public function __construct() {
189
	}
190
191
192
	/**
193
	 * @param string $id
194
	 *
195
	 * @return $this
196
	 */
197
	public function setId(string $id): self {
198
		$this->id = $id;
199
200
		return $this;
201
	}
202
203
	/**
204
	 * @return string
205
	 */
206
	public function getId(): string {
207
		return $this->id;
208
	}
209
210
211
	/**
212
	 * @param string $circleId
213
	 *
214
	 * @return Member
215
	 */
216
	public function setCircleId(string $circleId): self {
217
		$this->circleId = $circleId;
218
219
		return $this;
220
	}
221
222
	/**
223
	 * @return string
224
	 */
225
	public function getCircleId(): string {
226
		return $this->circleId;
227
	}
228
229
230
	/**
231
	 * This should replace user_id, user_type and instance; and will use the data from Circle with
232
	 * Config=CFG_SINGLE
233
	 *
234
	 * @param string $singleId
235
	 *
236
	 * @return $this
237
	 */
238
	public function setSingleId(string $singleId): self {
239
		$this->singleId = $singleId;
240
241
		return $this;
242
	}
243
244
	/**
245
	 * @return string
246
	 */
247
	public function getSingleId(): string {
248
		return $this->singleId;
249
	}
250
251
252
	/**
253
	 * @param string $userId
254
	 *
255
	 * @return Member
256
	 */
257
	public function setUserId(string $userId): self {
258
		$this->userId = $userId;
259
		if ($this->displayName === '') {
260
			$this->displayName = $userId;
261
		}
262
263
		return $this;
264
	}
265
266
	/**
267
	 * @return string
268
	 */
269
	public function getUserId(): string {
270
		return $this->userId;
271
	}
272
273
274
	/**
275
	 * @param int $userType
276
	 *
277
	 * @return Member
278
	 */
279
	public function setUserType(int $userType): self {
280
		$this->userType = $userType;
281
282
		return $this;
283
	}
284
285
	/**
286
	 * @return int
287
	 */
288
	public function getUserType(): int {
289
		return $this->userType;
290
	}
291
292
293
	/**
294
	 * @param string $instance
295
	 *
296
	 * @return Member
297
	 */
298
	public function setInstance(string $instance): self {
299
		$this->instance = $instance;
300
301
		return $this;
302
	}
303
304
	/**
305
	 * @return string
306
	 */
307
	public function getInstance(): string {
308
		return $this->instance;
309
	}
310
311
312
	/**
313
	 * @return bool
314
	 */
315
	public function hasRemoteInstance(): bool {
316
		return !is_null($this->remoteInstance);
317
	}
318
319
	/**
320
	 * @param RemoteInstance $remoteInstance
321
	 *
322
	 * @return Member
323
	 */
324
	public function setRemoteInstance(RemoteInstance $remoteInstance): self {
325
		$this->remoteInstance = $remoteInstance;
326
327
		return $this;
328
	}
329
330
	/**
331
	 * @return RemoteInstance
332
	 */
333
	public function getRemoteInstance(): RemoteInstance {
334
		return $this->remoteInstance;
335
	}
336
337
338
	/**
339
	 * @return bool
340
	 */
341
	public function hasBasedOn(): bool {
342
		return !is_null($this->basedOn);
343
	}
344
345
	/**
346
	 * @param Circle $basedOn
347
	 *
348
	 * @return $this
349
	 */
350
	public function setBasedOn(Circle $basedOn): self {
351
		$this->basedOn = $basedOn;
352
353
		return $this;
354
	}
355
356
	/**
357
	 * @return Circle
358
	 */
359
	public function getBasedOn(): Circle {
360
		return $this->basedOn;
361
	}
362
363
364
	/**
365
	 * @return bool
366
	 */
367
	public function hasInheritedBy(): bool {
368
		return !is_null($this->inheritedBy);
369
	}
370
371
	/**
372
	 * @param FederatedUser $inheritedBy
373
	 *
374
	 * @return $this
375
	 */
376
	public function setInheritedBy(FederatedUser $inheritedBy): self {
377
		$this->inheritedBy = $inheritedBy;
378
379
		return $this;
380
	}
381
382
	/**
383
	 * @return FederatedUser
384
	 */
385
	public function getInheritedBy(): FederatedUser {
386
		return $this->inheritedBy;
387
	}
388
389
390
	/**
391
	 * @return bool
392
	 */
393
	public function hasInheritanceFrom(): bool {
394
		return !is_null($this->inheritanceFrom);
395
	}
396
397
	/**
398
	 * @param Member $inheritanceFrom
399
	 *
400
	 * @return $this
401
	 */
402
	public function setInheritanceFrom(Member $inheritanceFrom): self {
403
		$this->inheritanceFrom = $inheritanceFrom;
404
405
		return $this;
406
	}
407
408
	/**
409
	 * @return Member|null
410
	 */
411
	public function getInheritanceFrom(): ?Member {
412
		return $this->inheritanceFrom;
413
	}
414
415
416
	/**
417
	 * @param bool $local
418
	 *
419
	 * @return Member
420
	 */
421
	public function setLocal(bool $local): self {
422
		$this->local = $local;
423
424
		return $this;
425
	}
426
427
	/**
428
	 * @return bool
429
	 */
430
	public function isLocal(): bool {
431
		return $this->local;
432
	}
433
434
435
	/**
436
	 * @param int $level
437
	 *
438
	 * @return Member
439
	 */
440
	public function setLevel(int $level): self {
441
		$this->level = $level;
442
443
		return $this;
444
	}
445
446
	/**
447
	 * @return int
448
	 */
449
	public function getLevel(): int {
450
		return $this->level;
451
	}
452
453
454
	/**
455
	 * @param string $status
456
	 *
457
	 * @return Member
458
	 */
459
	public function setStatus(string $status): self {
460
		$this->status = $status;
461
462
		return $this;
463
	}
464
465
	/**
466
	 * @return string
467
	 */
468
	public function getStatus(): string {
469
		return $this->status;
470
	}
471
472
473
	/**
474
	 * @param string $note
475
	 *
476
	 * @return Member
477
	 */
478
	public function setNote(string $note): self {
479
		$this->note = $note;
480
481
		return $this;
482
	}
483
484
	/**
485
	 * @return string
486
	 */
487
	public function getNote(): string {
488
		return $this->note;
489
	}
490
491
492
	/**
493
	 * @param string $displayName
494
	 *
495
	 * @return Member
496
	 */
497
	public function setDisplayName(string $displayName): self {
498
		if ($displayName !== '') {
499
			$this->displayName = $displayName;
500
		}
501
502
		return $this;
503
	}
504
505
506
	/**
507
	 * @param int $displayUpdate
508
	 *
509
	 * @return Member
510
	 */
511
	public function setDisplayUpdate(int $displayUpdate): self {
512
		$this->displayUpdate = $displayUpdate;
513
514
		return $this;
515
	}
516
517
	/**
518
	 * @return int
519
	 */
520
	public function getDisplayUpdate(): int {
521
		return $this->displayUpdate;
522
	}
523
524
525
	/**
526
	 * @return string
527
	 */
528
	public function getDisplayName(): string {
529
		return $this->displayName;
530
	}
531
532
533
	/**
534
	 * @param string $contactId
535
	 *
536
	 * @return Member
537
	 */
538
	public function setContactId(string $contactId): self {
539
		$this->contactId = $contactId;
540
541
		return $this;
542
	}
543
544
	/**
545
	 * @return string
546
	 */
547
	public function getContactId(): string {
548
		return $this->contactId;
549
	}
550
551
552
	/**
553
	 * @param string $contactMeta
554
	 *
555
	 * @return Member
556
	 */
557
	public function setContactMeta(string $contactMeta): self {
558
		$this->contactMeta = $contactMeta;
559
560
		return $this;
561
	}
562
563
	/**
564
	 * @return string
565
	 */
566
	public function getContactMeta(): string {
567
		return $this->contactMeta;
568
	}
569
570
571
	/**
572
	 * @param Circle $circle
573
	 *
574
	 * @return self
575
	 */
576
	public function setCircle(Circle $circle): self {
577
		$this->circle = $circle;
578
579
		return $this;
580
	}
581
582
	/**
583
	 * @return Circle
584
	 */
585
	public function getCircle(): Circle {
586
		return $this->circle;
587
	}
588
589
	/**
590
	 * @return bool
591
	 */
592
	public function hasCircle(): bool {
593
		return (!is_null($this->circle));
594
	}
595
596
597
	/**
598
	 * @param int $joined
599
	 *
600
	 * @return Member
601
	 */
602
	public function setJoined(int $joined): self {
603
		$this->joined = $joined;
604
605
		return $this;
606
	}
607
608
	/**
609
	 * @return int
610
	 */
611
	public function getJoined(): int {
612
		return $this->joined;
613
	}
614
615
616
	/**
617
	 * @return bool
618
	 */
619
	public function hasMemberships(): bool {
620
		return !is_null($this->memberships);
621
	}
622
623
	/**
624
	 * @param array $memberships
625
	 *
626
	 * @return self
627
	 */
628
	public function setMemberships(array $memberships): IMemberships {
629
		$this->memberships = $memberships;
630
631
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\Member) is incompatible with the return type declared by the interface OCA\Circles\IMemberships::setMemberships of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
632
	}
633
634
	/**
635
	 * @return Membership[]
636
	 */
637
	public function getMemberships(): array {
638
		if (is_null($this->memberships)) {
639
			$this->getManager()->getMemberships($this);
640
		}
641
642
		return $this->memberships;
643
	}
644
645
646
	/**
647
	 * @param Member $member
648
	 * @param bool $full
649
	 *
650
	 * @return bool
651
	 */
652
	public function compareWith(Member $member, bool $full = true): bool {
653
		if ($this->getId() !== $member->getId()
654
			|| $this->getCircleId() !== $member->getCircleId()
655
			|| $this->getSingleId() !== $member->getSingleId()
656
			|| $this->getUserId() !== $member->getUserId()
657
			|| $this->getUserType() <> $member->getUserType()
658
			|| $this->getInstance() !== $member->getInstance()) {
659
			return false;
660
		}
661
662
		if ($full
663
			&& ($this->getLevel() <> $member->getLevel()
664
				|| $this->getStatus() !== $member->getStatus())) {
665
			return false;
666
		}
667
668
		return true;
669
	}
670
671
672
	/**
673
	 * @param array $data
674
	 *
675
	 * @return $this
676
	 * @throws InvalidItemException
677
	 */
678
	public function import(array $data): IDeserializable {
679
		if ($this->get('userId', $data) === '') {
680
			throw new InvalidItemException();
681
		}
682
683
		$this->setId($this->get('id', $data));
684
		$this->setCircleId($this->get('circleId', $data));
685
		$this->setSingleId($this->get('singleId', $data));
686
		$this->setUserId($this->get('userId', $data));
687
		$this->setUserType($this->getInt('userType', $data));
688
		$this->setInstance($this->get('instance', $data));
689
		$this->setLocal($this->getBool('local', $data));
690
		$this->setLevel($this->getInt('level', $data));
691
		$this->setStatus($this->get('status', $data));
692
		$this->setDisplayName($this->get('displayName', $data));
693
		$this->setDisplayUpdate($this->getInt('displayUpdate', $data));
694
		$this->setNote($this->get('note', $data));
695
		$this->setContactId($this->get('contactId', $data));
696
		$this->setContactMeta($this->get('contactMeta', $data));
697
		$this->setJoined($this->getInt('joined', $data));
698
699
		try {
700
			/** @var Circle $circle */
701
			$circle = $this->deserialize($this->getArray('circle', $data), Circle::class);
702
			$this->setCircle($circle);
703
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
704
		}
705
706
		try {
707
			/** @var Circle $circle */
708
			$circle = $this->deserialize($this->getArray('basedOn', $data), Circle::class);
709
			$this->setBasedOn($circle);
710
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
711
		}
712
713
		try {
714
			/** @var FederatedUSer $inheritedBy */
715
			$inheritedBy = $this->deserialize($this->getArray('inheritedBy', $data), Membership::class);
716
			$this->setInheritedBy($inheritedBy);
717
		} catch (InvalidItemException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
718
		}
719
720
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\Member) is incompatible with the return type declared by the interface daita\MySmallPhpTools\IDeserializable::import of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
721
	}
722
723
724
	/**
725
	 * @param array $data
726
	 * @param string $prefix
727
	 *
728
	 * @return INC22QueryRow
729
	 * @throws MemberNotFoundException
730
	 */
731
	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
732
		if ($this->get($prefix . 'single_id', $data) === '') {
733
			throw new MemberNotFoundException();
734
		}
735
736
		$this->setId($this->get($prefix . 'member_id', $data));
737
		$this->setCircleId($this->get($prefix . 'circle_id', $data));
738
		$this->setSingleId($this->get($prefix . 'single_id', $data));
739
		$this->setUserId($this->get($prefix . 'user_id', $data));
740
		$this->setUserType($this->getInt($prefix . 'user_type', $data));
741
		$this->setInstance($this->get($prefix . 'instance', $data));
742
		$this->setLevel($this->getInt($prefix . 'level', $data));
743
		$this->setStatus($this->get($prefix . 'status', $data));
744
		$this->setDisplayName($this->get($prefix . 'cached_name', $data));
745
		$this->setNote($this->get($prefix . 'note', $data));
746
		$this->setContactId($this->get($prefix . 'contact_id', $data));
747
		$this->setContactMeta($this->get($prefix . 'contact_meta', $data));
748
749
		$cachedUpdate = $this->get($prefix . 'cached_update', $data);
750
		if ($cachedUpdate !== '') {
751
			$this->setDisplayUpdate(DateTime::createFromFormat('Y-m-d H:i:s', $cachedUpdate)->getTimestamp());
752
		}
753
754
		$joined = $this->get($prefix . 'joined', $data);
755
		if ($joined !== '') {
756
			$this->setJoined(DateTime::createFromFormat('Y-m-d H:i:s', $joined)->getTimestamp());
757
		}
758
759
		if ($this->getInstance() === '') {
760
			$this->setLocal(true);
761
			$this->setInstance($this->get('_params.local', $data));
762
		}
763
764
		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
765
766
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (OCA\Circles\Model\Member) is incompatible with the return type declared by the interface daita\MySmallPhpTools\Db...Row::importFromDatabase of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
767
	}
768
769
770
	/**
771
	 * @return string[]
772
	 */
773
	public function jsonSerialize(): array {
774
		$arr = [
775
			'id'            => $this->getId(),
776
			'circleId'      => $this->getCircleId(),
777
			'singleId'      => $this->getSingleId(),
778
			'userId'        => $this->getUserId(),
779
			'userType'      => $this->getUserType(),
780
			'instance'      => $this->getInstance(),
781
			'local'         => $this->isLocal(),
782
			'level'         => $this->getLevel(),
783
			'status'        => $this->getStatus(),
784
			'displayName'   => $this->getDisplayName(),
785
			'displayUpdate' => $this->getDisplayUpdate(),
786
			'note'          => $this->getNote(),
787
			'contactId'     => $this->getContactId(),
788
			'contactMeta'   => $this->getContactMeta(),
789
			'joined'        => $this->getJoined()
790
		];
791
792
		if ($this->hasBasedOn()) {
793
			$arr['basedOn'] = $this->getBasedOn();
794
		}
795
796
		if ($this->hasInheritedBy()) {
797
			$arr['inheritedBy'] = $this->getInheritedBy();
798
		}
799
800
		if ($this->hasInheritanceFrom()) {
801
			$arr['inheritanceFrom'] = $this->getInheritanceFrom();
802
		}
803
804
		if ($this->hasCircle()) {
805
			$arr['circle'] = $this->getCircle();
806
		}
807
808
		if ($this->hasMemberships()) {
809
			$arr['memberships'] = $this->getMemberships();
810
		}
811
812
		if ($this->hasRemoteInstance()) {
813
			$arr['remoteInstance'] = $this->getRemoteInstance();
814
		}
815
816
		return $arr;
817
	}
818
819
820
	/**
821
	 * @param int $level
822
	 *
823
	 * @return int
824
	 * @throws ParseMemberLevelException
825
	 */
826
	public static function parseLevelInt(int $level): int {
827
		if (!array_key_exists($level, self::$DEF_LEVEL)) {
828
			$all = implode(', ', array_keys(self::$DEF_LEVEL));
829
			throw new ParseMemberLevelException('Available levels: ' . $all, 121);
830
		}
831
832
		return $level;
833
	}
834
835
836
	/**
837
	 * @param string $levelString
838
	 *
839
	 * @return int
840
	 * @throws ParseMemberLevelException
841
	 */
842
	public static function parseLevelString(string $levelString): int {
843
		$levelString = ucfirst(strtolower($levelString));
844
		$level = array_search($levelString, Member::$DEF_LEVEL);
845
846
		if (!$level) {
847
			$all = implode(', ', array_values(self::$DEF_LEVEL));
848
			throw new ParseMemberLevelException('Available levels: ' . $all, 121);
849
		}
850
851
		return (int)$level;
852
	}
853
854
	/**
855
	 * @param string $typeString
856
	 *
857
	 * @return int
858
	 * @throws UserTypeNotFoundException
859
	 */
860
	public static function parseTypeString(string $typeString): int {
861
		$typeString = strtolower($typeString);
862
		$type = array_search($typeString, Member::$TYPE);
863
864
		if ($type === false) {
865
			$all = implode(', ', array_values(self::$TYPE));
866
			throw new UserTypeNotFoundException('Available types: ' . $all);
867
		}
868
869
		return (int)$type;
870
	}
871
872
}
873
874