Completed
Pull Request — master (#398)
by Tortue
01:54
created

MembersService   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 609
Duplicated Lines 7.72 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
wmc 62
lcom 1
cbo 13
dl 47
loc 609
rs 3.431
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A addMember() 7 16 3
A addSingleMember() 0 15 1
A addMassiveMembers() 0 12 3
A addMemberBasedOnItsType() 0 5 1
A addLocalMember() 0 12 3
A addEmailAddress() 0 8 2
A addContact() 0 8 2
A __construct() 19 19 1
A verifyIdentBasedOnItsType() 0 5 1
A verifyIdentLocalMember() 0 11 3
A verifyIdentEmailAddress() 0 18 4
A verifyIdentContact() 0 19 4
B addGroupMembers() 0 29 10
A addMassiveMails() 0 21 5
A getMember() 0 12 2
A getMemberById() 0 3 1
A levelMember() 7 28 4
A updateMemberLevel() 0 13 3
A editMemberLevel() 0 15 2
A switchOwner() 0 19 2
A removeMember() 14 33 4
A onUserRemoved() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like MembersService 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 MembersService, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Circles - bring cloud-users closer
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\Circles\Service;
28
29
30
use Exception;
31
use OC;
32
use OC\User\NoUserException;
33
use OCA\Circles\Circles\FileSharingBroadcaster;
34
use OCA\Circles\Db\CirclesRequest;
35
use OCA\Circles\Db\MembersRequest;
36
use OCA\Circles\Db\SharesRequest;
37
use OCA\Circles\Db\TokensRequest;
38
use OCA\Circles\Exceptions\CircleDoesNotExistException;
39
use OCA\Circles\Exceptions\CircleTypeNotValidException;
40
use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
41
use OCA\Circles\Exceptions\EmailAccountInvalidFormatException;
42
use OCA\Circles\Exceptions\GroupDoesNotExistException;
43
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
44
use OCA\Circles\Exceptions\MemberDoesNotExistException;
45
use OCA\Circles\Exceptions\MemberIsNotModeratorException;
46
use OCA\Circles\Exceptions\MemberIsOwnerException;
47
use OCA\Circles\Exceptions\MemberTypeCantEditLevelException;
48
use OCA\Circles\Exceptions\ModeratorIsNotHighEnoughException;
49
use OCA\Circles\Model\Circle;
50
use OCA\Circles\Model\Member;
51
use OCP\IGroup;
52
use OCP\IL10N;
53
use OCP\IUser;
54
use OCP\IUserManager;
55
56
57
/**
58
 * Class MembersService
59
 *
60
 * @package OCA\Circles\Service
61
 */
62
class MembersService {
63
64
	/** @var string */
65
	private $userId;
66
67
	/** @var IL10N */
68
	private $l10n;
69
70
	/** @var IUserManager */
71
	private $userManager;
72
73
	/** @var ConfigService */
74
	private $configService;
75
76
	/** @var CirclesRequest */
77
	private $circlesRequest;
78
79
	/** @var MembersRequest */
80
	private $membersRequest;
81
82
	/** @var SharesRequest */
83
	private $sharesRequest;
84
85
	/** @var TokensRequest */
86
	private $tokensRequest;
87
88
	/** @var CirclesService */
89
	private $circlesService;
90
91
	/** @var EventsService */
92
	private $eventsService;
93
94
	/** @var FileSharingBroadcaster */
95
	private $fileSharingBroadcaster;
96
97
	/** @var MiscService */
98
	private $miscService;
99
100
	/**
101
	 * MembersService constructor.
102
	 *
103
	 * @param string $userId
104
	 * @param IL10N $l10n
105
	 * @param IUserManager $userManager
106
	 * @param ConfigService $configService
107
	 * @param CirclesRequest $circlesRequest
108
	 * @param MembersRequest $membersRequest
109
	 * @param SharesRequest $sharesRequest
110
	 * @param TokensRequest $tokensRequest
111
	 * @param CirclesService $circlesService
112
	 * @param EventsService $eventsService
113
	 * @param FileSharingBroadcaster $fileSharingBroadcaster
114
	 * @param MiscService $miscService
115
	 */
116 View Code Duplication
	public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
117
		$userId, IL10N $l10n, IUserManager $userManager, ConfigService $configService,
118
		CirclesRequest $circlesRequest, MembersRequest $membersRequest, SharesRequest $sharesRequest,
119
		TokensRequest $tokensRequest, CirclesService $circlesService, EventsService $eventsService,
120
		FileSharingBroadcaster $fileSharingBroadcaster, MiscService $miscService
121
	) {
122
		$this->userId = $userId;
123
		$this->l10n = $l10n;
124
		$this->userManager = $userManager;
125
		$this->configService = $configService;
126
		$this->circlesRequest = $circlesRequest;
127
		$this->membersRequest = $membersRequest;
128
		$this->sharesRequest = $sharesRequest;
129
		$this->tokensRequest = $tokensRequest;
130
		$this->circlesService = $circlesService;
131
		$this->eventsService = $eventsService;
132
		$this->fileSharingBroadcaster = $fileSharingBroadcaster;
133
		$this->miscService = $miscService;
134
	}
135
136
137
	/**
138
	 * addMember();
139
	 *
140
	 * add a new member to a circle.
141
	 *
142
	 * @param string $circleUniqueId
143
	 * @param $ident
144
	 * @param int $type
145
	 *
146
	 * @param bool $force
147
	 *
148
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Member[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
149
	 * @throws Exception
150
	 */
151
	public function addMember($circleUniqueId, $ident, $type, bool $force = false) {
152
153 View Code Duplication
		if ($force === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
			$circle = $this->circlesRequest->forceGetCircle($circleUniqueId);
155
		} else {
156
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
157
			$circle->getHigherViewer()
158
				   ->hasToBeModerator();
159
		}
160
161
		if (!$this->addMassiveMembers($circle, $ident, $type)) {
162
			$this->addSingleMember($circle, $ident, $type);
163
		}
164
165
		return $this->membersRequest->getMembers($circle->getUniqueId(), $circle->getHigherViewer(), $force);
166
	}
167
168
169
	/**
170
	 * add a single member to a circle.
171
	 *
172
	 * @param Circle $circle
173
	 * @param string $ident
174
	 * @param int $type
175
	 *
176
	 * @throws MemberAlreadyExistsException
177
	 * @throws Exception
178
	 */
179
	private function addSingleMember(Circle $circle, $ident, $type) {
180
		$this->verifyIdentBasedOnItsType($ident, $type);
181
182
		$member = $this->membersRequest->getFreshNewMember($circle->getUniqueId(), $ident, $type);
183
		$member->hasToBeInviteAble();
184
185
		$this->circlesService->checkThatCircleIsNotFull($circle);
186
187
		$this->addMemberBasedOnItsType($circle, $member);
188
189
		$this->membersRequest->updateMember($member);
190
		$this->fileSharingBroadcaster->sendMailAboutExistingShares($circle, $member);
191
192
		$this->eventsService->onMemberNew($circle, $member);
193
	}
194
195
196
	/**
197
	 * add a bunch of users to a circle based on the type of the 'bunch'
198
	 *
199
	 * @param Circle $circle
200
	 * @param string $ident
201
	 * @param int $type
202
	 *
203
	 * @return bool
204
	 * @throws Exception
205
	 */
206
	private function addMassiveMembers(Circle $circle, $ident, $type) {
207
208
		if ($type === Member::TYPE_GROUP) {
209
			return $this->addGroupMembers($circle, $ident);
210
		}
211
212
		if ($type === Member::TYPE_USER) {
213
			return $this->addMassiveMails($circle, $ident);
214
		}
215
216
		return false;
217
	}
218
219
220
	/**
221
	 * add a new member based on its type.
222
	 *
223
	 * @param Circle $circle
224
	 * @param Member $member
225
	 *
226
	 * @throws Exception
227
	 */
228
	private function addMemberBasedOnItsType(Circle $circle, Member &$member) {
229
		$this->addLocalMember($circle, $member);
230
		$this->addEmailAddress($member);
231
		$this->addContact($member);
232
	}
233
234
235
	/**
236
	 * @param Circle $circle
237
	 * @param Member $member
238
	 *
239
	 * @throws Exception
240
	 */
241
	private function addLocalMember(Circle $circle, Member $member) {
242
243
		if ($member->getType() !== Member::TYPE_USER) {
244
			return;
245
		}
246
247
		$member->inviteToCircle($circle->getType());
248
249
		if ($this->configService->isInvitationSkipped()) {
250
			$member->joinCircle($circle->getType());
251
		}
252
	}
253
254
255
	/**
256
	 * add mail address as contact.
257
	 *
258
	 * @param Member $member
259
	 *
260
	 * @throws Exception
261
	 */
262
	private function addEmailAddress(Member $member) {
263
264
		if ($member->getType() !== Member::TYPE_MAIL) {
265
			return;
266
		}
267
268
		$member->addMemberToCircle();
269
	}
270
271
272
	/**
273
	 * Add contact as member.
274
	 *
275
	 * @param Member $member
276
	 *
277
	 * @throws Exception
278
	 */
279
	private function addContact(Member $member) {
280
281
		if ($member->getType() !== Member::TYPE_CONTACT) {
282
			return;
283
		}
284
285
		$member->addMemberToCircle();
286
	}
287
288
289
	/**
290
	 * Verify the availability of an ident, based on its type.
291
	 *
292
	 * @param string $ident
293
	 * @param int $type
294
	 *
295
	 * @throws Exception
296
	 */
297
	private function verifyIdentBasedOnItsType(&$ident, $type) {
298
		$this->verifyIdentLocalMember($ident, $type);
299
		$this->verifyIdentEmailAddress($ident, $type);
300
		$this->verifyIdentContact($ident, $type);
301
	}
302
303
304
	/**
305
	 * Verify if a local account is valid.
306
	 *
307
	 * @param $ident
308
	 * @param $type
309
	 *
310
	 * @throws NoUserException
311
	 */
312
	private function verifyIdentLocalMember(&$ident, $type) {
313
		if ($type !== Member::TYPE_USER) {
314
			return;
315
		}
316
317
		try {
318
			$ident = $this->miscService->getRealUserId($ident);
319
		} catch (NoUserException $e) {
0 ignored issues
show
Bug introduced by
The class OC\User\NoUserException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
320
			throw new NoUserException($this->l10n->t("This user does not exist"));
321
		}
322
	}
323
324
325
	/**
326
	 * Verify if a mail have a valid format.
327
	 *
328
	 * @param $ident
329
	 * @param $type
330
	 *
331
	 * @throws EmailAccountInvalidFormatException
332
	 */
333
	private function verifyIdentEmailAddress(&$ident, $type) {
334
335
		if ($type !== Member::TYPE_MAIL) {
336
			return;
337
		}
338
339
		if ($this->configService->isAccountOnly()) {
340
			throw new EmailAccountInvalidFormatException(
341
				$this->l10n->t('You cannot add a mail address as member of your Circle')
342
			);
343
		}
344
345
		if (!filter_var($ident, FILTER_VALIDATE_EMAIL)) {
346
			throw new EmailAccountInvalidFormatException(
347
				$this->l10n->t('Email format is not valid')
348
			);
349
		}
350
	}
351
352
353
	/**
354
	 * Verify if a contact exist in current user address books.
355
	 *
356
	 * @param $ident
357
	 * @param $type
358
	 *
359
	 * @throws NoUserException
360
	 * @throws EmailAccountInvalidFormatException
361
	 */
362
	private function verifyIdentContact(&$ident, $type) {
363
		if ($type !== Member::TYPE_CONTACT) {
364
			return;
365
		}
366
367
		if ($this->configService->isAccountOnly()) {
368
			throw new EmailAccountInvalidFormatException(
369
				$this->l10n->t('You cannot add a contact as member of your Circle')
370
			);
371
		}
372
373
		$tmpContact = $this->userId . ':' . $ident;
374
		$result = MiscService::getContactData($tmpContact);
375
		if (empty($result)) {
376
			throw new NoUserException($this->l10n->t("This contact is not available"));
377
		}
378
379
		$ident = $tmpContact;
380
	}
381
382
383
	/**
384
	 * @param Circle $circle
385
	 * @param string $groupId
386
	 *
387
	 * @return bool
388
	 * @throws Exception
389
	 */
390
	private function addGroupMembers(Circle $circle, $groupId) {
391
392
		$groupManager = OC::$server->getGroupManager();
393
		$group = $groupManager->get($groupId);
394
395
		$user = OC::$server->getUserSession()->getUser();
396
397
		if (!$this->configService->isAddingAnyGroupMembersAllowed() &&
398
			$group instanceof IGroup && $user instanceof IUser &&
0 ignored issues
show
Bug introduced by
The class OCP\IGroup does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
Bug introduced by
The class OCP\IUser does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
399
			!$group->inGroup($user) && !$groupManager->isAdmin($user->getUID())
400
		) {
401
			$group = null;
402
		}
403
404
		if ($group === null) {
405
			throw new GroupDoesNotExistException($this->l10n->t('This group does not exist'));
406
		}
407
408
		foreach ($group->getUsers() as $user) {
409
			try {
410
				$this->addSingleMember($circle, $user->getUID(), Member::TYPE_USER);
411
			} catch (MemberAlreadyExistsException $e) {
412
			} catch (Exception $e) {
413
				throw $e;
414
			}
415
		}
416
417
		return true;
418
	}
419
420
421
	/**
422
	 * @param Circle $circle
423
	 * @param string $mails
424
	 *
425
	 * @return bool
426
	 */
427
	private function addMassiveMails(Circle $circle, $mails) {
428
429
		$mails = trim($mails);
430
		if (substr($mails, 0, 6) !== 'mails:') {
431
			return false;
432
		}
433
434
		$mails = substr($mails, 6);
435
		foreach (explode(' ', $mails) as $mail) {
436
			if (!filter_var($mail, FILTER_VALIDATE_EMAIL)) {
437
				continue;
438
			}
439
440
			try {
441
				$this->addMember($circle->getUniqueId(), $mail, Member::TYPE_MAIL);
442
			} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
443
			}
444
		}
445
446
		return true;
447
	}
448
449
450
	/**
451
	 * getMember();
452
	 *
453
	 * Will return any data of a user related to a circle (as a Member). User can be a 'non-member'
454
	 * Viewer needs to be at least Member of the Circle
455
	 *
456
	 * @param $circleId
457
	 * @param $userId
458
	 * @param $type
459
	 * @param bool $forceAll
460
	 *
461
	 * @return Member
462
	 * @throws CircleDoesNotExistException
463
	 * @throws ConfigNoCircleAvailableException
464
	 * @throws MemberDoesNotExistException
465
	 */
466
	public function getMember($circleId, $userId, $type, $forceAll = false) {
467
		if (!$forceAll) {
468
			$this->circlesRequest->getCircle($circleId, $this->userId)
469
								 ->getHigherViewer()
470
								 ->hasToBeMember();
471
		}
472
473
		$member = $this->membersRequest->forceGetMember($circleId, $userId, $type);
474
		$member->setNote('');
475
476
		return $member;
477
	}
478
479
480
	/**
481
	 * @param string $memberId
482
	 *
483
	 * @return Member
484
	 * @throws MemberDoesNotExistException
485
	 */
486
	public function getMemberById(string $memberId): Member {
487
		return $this->membersRequest->forceGetMemberById($memberId);
488
	}
489
490
491
	/**
492
	 * @param string $circleUniqueId
493
	 * @param string $name
494
	 * @param int $type
495
	 * @param int $level
496
	 * @param bool $force
497
	 *
498
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Member[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
499
	 * @throws CircleDoesNotExistException
500
	 * @throws CircleTypeNotValidException
501
	 * @throws ConfigNoCircleAvailableException
502
	 * @throws MemberDoesNotExistException
503
	 * @throws MemberTypeCantEditLevelException
504
	 * @throws Exception
505
	 */
506
	public function levelMember($circleUniqueId, $name, $type, $level, bool $force = false) {
507
508
		$level = (int)$level;
509
		if ($force === false) {
510
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
511
		} else {
512
			$circle = $this->circlesRequest->forceGetCircle($circleUniqueId);
513
		}
514
515
		if ($circle->getType() === Circle::CIRCLES_PERSONAL) {
516
			throw new CircleTypeNotValidException(
517
				$this->l10n->t('You cannot edit level in a personal circle')
518
			);
519
		}
520
521
		$member = $this->membersRequest->forceGetMember($circle->getUniqueId(), $name, $type);
522
		$member->levelHasToBeEditable();
523
		$this->updateMemberLevel($circle, $member, $level, $force);
524
525 View Code Duplication
		if ($force === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
526
			return $this->membersRequest->getMembers(
527
				$circle->getUniqueId(), $circle->getHigherViewer()
528
			);
529
		} else {
530
			return $this->membersRequest->forceGetMembers($circle->getUniqueId());
531
		}
532
533
	}
534
535
536
	/**
537
	 * @param Circle $circle
538
	 * @param Member $member
539
	 * @param $level
540
	 * @param bool $force
541
	 *
542
	 * @throws Exception
543
	 */
544
	private function updateMemberLevel(Circle $circle, Member $member, $level, bool $force = false) {
545
		if ($member->getLevel() === $level) {
546
			return;
547
		}
548
549
		if ($level === Member::LEVEL_OWNER) {
550
			$this->switchOwner($circle, $member, $force);
551
		} else {
552
			$this->editMemberLevel($circle, $member, $level, $force);
553
		}
554
555
		$this->eventsService->onMemberLevel($circle, $member);
556
	}
557
558
559
	/**
560
	 * @param Circle $circle
561
	 * @param Member $member
562
	 * @param $level
563
	 * @param bool $force
564
	 *
565
	 * @throws Exception
566
	 */
567
	private function editMemberLevel(Circle $circle, Member &$member, $level, bool $force = false) {
568
		if ($force === false) {
569
			$isMod = $circle->getHigherViewer();
570
			$isMod->hasToBeModerator();
571
			$isMod->hasToBeHigherLevel($level);
572
573
			$member->hasToBeMember();
574
			$isMod->hasToBeHigherLevel($member->getLevel());
575
		}
576
577
		$member->cantBeOwner();
578
579
		$member->setLevel($level);
580
		$this->membersRequest->updateMember($member);
581
	}
582
583
	/**
584
	 * @param Circle $circle
585
	 * @param Member $member
586
	 * @param bool $force
587
	 *
588
	 * @throws Exception
589
	 */
590
	private function switchOwner(Circle $circle, Member &$member, bool $force = false) {
591
		if ($force === false) {
592
			$isMod = $circle->getHigherViewer();
593
594
			// should already be possible from an NCAdmin, but not enabled in the frontend.
595
			$this->circlesService->hasToBeOwner($isMod);
596
		} else {
597
			$isMod = $circle->getOwner();
598
		}
599
600
		$member->hasToBeMember();
601
		$member->cantBeOwner();
602
603
		$member->setLevel(Member::LEVEL_OWNER);
604
		$this->membersRequest->updateMember($member);
605
606
		$isMod->setLevel(Member::LEVEL_ADMIN);
607
		$this->membersRequest->updateMember($isMod);
608
	}
609
610
611
	/**
612
	 * @param string $circleUniqueId
613
	 * @param string $name
614
	 * @param $type
615
	 * @param bool $force
616
	 *
617
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Member[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
618
	 * @throws CircleDoesNotExistException
619
	 * @throws ConfigNoCircleAvailableException
620
	 * @throws MemberDoesNotExistException
621
	 * @throws MemberIsNotModeratorException
622
	 * @throws MemberIsOwnerException
623
	 * @throws ModeratorIsNotHighEnoughException
624
	 */
625
	public function removeMember($circleUniqueId, $name, $type, bool $force = false) {
626
627 View Code Duplication
		if ($force === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
628
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
629
			$circle->getHigherViewer()
630
				   ->hasToBeModerator();
631
		} else {
632
			$circle = $this->circlesRequest->forceGetCircle($circleUniqueId);
633
		}
634
635
		$member = $this->membersRequest->forceGetMember($circleUniqueId, $name, $type);
636
		$member->hasToBeMemberOrAlmost();
637
		$member->cantBeOwner();
638
639
		if ($force === false) {
640
			$circle->getHigherViewer()
641
				   ->hasToBeHigherLevel($member->getLevel());
642
		}
643
644
		$this->eventsService->onMemberLeaving($circle, $member);
645
646
		$this->membersRequest->removeMember($member);
647
		$this->sharesRequest->removeSharesFromMember($member);
648
		$this->tokensRequest->removeTokensFromMember($member);
649
650 View Code Duplication
		if ($force === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
651
			return $this->membersRequest->getMembers(
652
				$circle->getUniqueId(), $circle->getHigherViewer()
653
			);
654
		} else {
655
			return $this->membersRequest->forceGetMembers($circle->getUniqueId());
656
		}
657
	}
658
659
660
	/**
661
	 * When a user is removed, remove him from all Circles
662
	 *
663
	 * @param $userId
664
	 */
665
	public function onUserRemoved($userId) {
666
		$this->membersRequest->removeAllMembershipsFromUser($userId);
667
	}
668
669
670
}
671
672