Guild   F
last analyzed

Complexity

Total Complexity 78

Size/Duplication

Total Lines 361
Duplicated Lines 0 %

Test Coverage

Coverage 72.44%

Importance

Changes 0
Metric Value
wmc 78
eloc 154
dl 0
loc 361
ccs 113
cts 156
cp 0.7244
rs 2.16
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A canManage() 0 5 2
A upgrade() 0 15 4
A listOfGuilds() 0 5 2
A canFound() 0 12 4
A leave() 0 11 3
A getMaxRank() 0 6 2
A checkNameAvailability() 0 6 2
A getMembers() 0 2 1
A canJoin() 0 7 3
A join() 0 16 4
A editGuild() 0 13 5
A getUserGuild() 0 6 2
A getGuild() 0 6 2
A found() 0 22 4
A __construct() 0 4 1
A canUpgrade() 0 12 5
B promote() 0 19 9
A canLeave() 0 10 4
B kick() 0 19 9
B demote() 0 19 10

How to fix   Complexity   

Complex Class

Complex classes like Guild 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.

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 Guild, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types=1);
3
4
namespace Nexendrie\Model;
5
6
use Nexendrie\Orm\Guild as GuildEntity;
7
use Nexendrie\Orm\User as UserEntity;
8
use Nexendrie\Orm\Group as GroupEntity;
9
use Nextras\Orm\Collection\ICollection;
10
11
/**
12
 * Guild Model
13
 *
14
 * @author Jakub Konečný
15
 * @property-read int $maxRank
16
 */
17 1
final class Guild {
18
  protected \Nexendrie\Orm\Model $orm;
19
  protected \Nette\Security\User $user;
20
  protected int $foundingPrice;
21
  
22
  use \Nette\SmartObject;
23
  
24
  public function __construct(\Nexendrie\Orm\Model $orm, \Nette\Security\User $user, SettingsRepository $sr) {
25 1
    $this->orm = $orm;
26 1
    $this->user = $user;
27 1
    $this->foundingPrice = $sr->settings["fees"]["foundGuild"];
28 1
  }
29
  
30
  /**
31
   * Get list of guild from specified town
32
   *
33
   * @return GuildEntity[]|ICollection
34
   */
35
  public function listOfGuilds(int $town = 0): ICollection {
36 1
    if($town === 0) {
37 1
      return $this->orm->guilds->findAll();
38
    }
39 1
    return $this->orm->guilds->findByTown($town);
40
  }
41
  
42
  /**
43
   * Get specified guild
44
   *
45
   * @throws GuildNotFoundException
46
   */
47
  public function getGuild(int $id): GuildEntity {
48 1
    $guild = $this->orm->guilds->getById($id);
49 1
    if($guild === null) {
50 1
      throw new GuildNotFoundException();
51
    }
52 1
    return $guild;
53
  }
54
  
55
  /**
56
   * Check whether a name can be used
57
   */
58
  private function checkNameAvailability(string $name, int $id = null): bool {
59 1
    $guild = $this->orm->guilds->getByName($name);
60 1
    if($guild === null) {
61 1
      return true;
62
    }
63
    return ($guild->id === $id);
64
  }
65
  
66
  /**
67
   * Edit specified guild
68
   *
69
   * @throws GuildNotFoundException
70
   * @throws GuildNameInUseException
71
   */
72
  public function editGuild(int $id, array $data): void {
73
    try {
74 1
      $guild = $this->getGuild($id);
75 1
    } catch(GuildNotFoundException $e) {
76 1
      throw $e;
77
    }
78 1
    foreach($data as $key => $value) {
79 1
      if($key === "name" && !$this->checkNameAvailability($value, $id)) {
80
        throw new GuildNameInUseException();
81
      }
82 1
      $guild->$key = $value;
83
    }
84 1
    $this->orm->guilds->persistAndFlush($guild);
85 1
  }
86
  
87
  /**
88
   * Get specified user's guild
89
   */
90
  public function getUserGuild(int $uid = null): ?GuildEntity {
91 1
    $user = $this->orm->users->getById($uid ?? $this->user->id);
92 1
    if($user === null) {
93 1
      return null;
94
    }
95 1
    return $user->guild;
96
  }
97
  
98
  /**
99
   * Check whether the user can found a guild
100
   */
101
  public function canFound(): bool {
102 1
    if(!$this->user->isLoggedIn()) {
103 1
      return false;
104
    }
105
    /** @var UserEntity $user */
106 1
    $user = $this->orm->users->getById($this->user->id);
107 1
    if($user->group->path !== GroupEntity::PATH_CITY) {
108 1
      return false;
109 1
    } elseif($user->guild !== null) {
110 1
      return false;
111
    }
112 1
    return true;
113
  }
114
  
115
  /**
116
   * Found a guild
117
   *
118
   * @throws CannotFoundGuildException
119
   * @throws GuildNameInUseException
120
   * @throws InsufficientFundsException
121
   */
122
  public function found(array $data): void {
123 1
    if(!$this->canFound()) {
124 1
      throw new CannotFoundGuildException();
125
    }
126
    /** @var UserEntity $user */
127
    $user = $this->orm->users->getById($this->user->id);
128
    if(!$this->checkNameAvailability($data["name"])) {
129
      throw new GuildNameInUseException();
130
    }
131
    if($user->money < $this->foundingPrice) {
132
      throw new InsufficientFundsException();
133
    }
134
    $guild = new GuildEntity();
135
    $this->orm->guilds->attach($guild);
136
    $guild->name = $data["name"];
137
    $guild->description = $data["description"];
138
    $guild->town = $this->user->identity->town;
139
    $user->lastActive = time();
140
    $user->money -= $this->foundingPrice;
141
    $user->guild = $guild;
142
    $user->guildRank = $this->getMaxRank();
143
    $this->orm->users->persistAndFlush($user);
144
  }
145
  
146
  /**
147
   * Check whether the user can join a guild
148
   */
149
  public function canJoin(): bool {
150 1
    if(!$this->user->isLoggedIn()) {
151 1
      return false;
152
    }
153
    /** @var UserEntity $user */
154 1
    $user = $this->orm->users->getById($this->user->id);
155 1
    return ($user->group->path === GroupEntity::PATH_CITY && $user->guild === null);
156
  }
157
  
158
  /**
159
   * Join a guild
160
   *
161
   * @throws AuthenticationNeededException
162
   * @throws CannotJoinGuildException
163
   * @throws GuildNotFoundException
164
   */
165
  public function join(int $id): void {
166 1
    if(!$this->user->isLoggedIn()) {
167 1
      throw new AuthenticationNeededException();
168 1
    } elseif(!$this->canJoin()) {
169 1
      throw new CannotJoinGuildException();
170
    }
171
    try {
172 1
      $guild = $this->getGuild($id);
173 1
    } catch(GuildNotFoundException $e) {
174 1
      throw $e;
175
    }
176
    /** @var UserEntity $user */
177
    $user = $this->orm->users->getById($this->user->id);
178
    $user->guild = $guild;
179
    $user->guildRank = 1;
180
    $this->orm->users->persistAndFlush($user);
181
  }
182
  
183
  /**
184
   * Check whether the user can leave guild
185
   * @throws AuthenticationNeededException
186
   */
187
  public function canLeave(): bool {
188 1
    if(!$this->user->isLoggedIn()) {
189 1
      throw new AuthenticationNeededException();
190
    }
191
    /** @var UserEntity $user */
192 1
    $user = $this->orm->users->getById($this->user->id);
193 1
    if($user->guild === null || $user->guildRank === null) {
194 1
      return false;
195
    }
196 1
    return !($user->guildRank->id === $this->getMaxRank());
197
  }
198
  
199
  /**
200
   * Leave guild
201
   *
202
   * @throws AuthenticationNeededException
203
   * @throws CannotLeaveGuildException
204
   */
205
  public function leave(): void {
206 1
    if(!$this->user->isLoggedIn()) {
207 1
      throw new AuthenticationNeededException();
208
    }
209 1
    if(!$this->canLeave()) {
210 1
      throw new CannotLeaveGuildException();
211
    }
212
    /** @var UserEntity $user */
213
    $user = $this->orm->users->getById($this->user->id);
214
    $user->guild = $user->guildRank = null;
215
    $this->orm->users->persistAndFlush($user);
216
  }
217
  
218
  /**
219
   * Check whether the user can manage guild
220
   *
221
   * @throws AuthenticationNeededException
222
   */
223
  public function canManage(): bool {
224 1
    if(!$this->user->isLoggedIn()) {
225 1
      throw new AuthenticationNeededException();
226
    }
227 1
    return $this->user->isAllowed(AuthorizatorFactory::GUILD_RESOURCE_NAME, "manage");
228
  }
229
  
230
  /**
231
   * Check whether the user can upgrade guild
232
   *
233
   * @throws AuthenticationNeededException
234
   */
235
  public function canUpgrade(): bool {
236 1
    if(!$this->user->isLoggedIn()) {
237 1
      throw new AuthenticationNeededException();
238
    }
239
    /** @var UserEntity $user */
240 1
    $user = $this->orm->users->getById($this->user->id);
241 1
    if($user->guild === null || !$this->user->isAllowed(AuthorizatorFactory::GUILD_RESOURCE_NAME, "upgrade")) {
242 1
      return false;
243 1
    } elseif($user->guild->level >= GuildEntity::MAX_LEVEL) {
244
      return false;
245
    }
246 1
    return true;
247
  }
248
  
249
  /**
250
   * Upgrade guild
251
   *
252
   * @throws AuthenticationNeededException
253
   * @throws CannotUpgradeGuildException
254
   * @throws InsufficientFundsException
255
   */
256
  public function upgrade(): void {
257 1
    if(!$this->user->isLoggedIn()) {
258 1
      throw new AuthenticationNeededException();
259
    }
260 1
    if(!$this->canUpgrade()) {
261 1
      throw new CannotUpgradeGuildException();
262
    }
263
    /** @var GuildEntity $guild */
264
    $guild = $this->getUserGuild();
265
    if($guild->money < $guild->upgradePrice) {
266
      throw new InsufficientFundsException();
267
    }
268
    $guild->money -= $guild->upgradePrice;
269
    $guild->level++;
270
    $this->orm->guilds->persistAndFlush($guild);
271
  }
272
  
273
  /**
274
   * Get members of specified order
275
   *
276
   * @return UserEntity[]|ICollection
277
   */
278
  public function getMembers(int $guild): ICollection {
279 1
    return $this->orm->users->findByGuild($guild);
280
  }
281
  
282
  protected function getMaxRank(): int {
283 1
    static $rank = null;
284 1
    if($rank === null) {
285 1
      $rank = $this->orm->guildRanks->findAll()->countStored();
286
    }
287 1
    return $rank;
288
  }
289
  
290
  /**
291
   * Promote a user
292
   *
293
   * @throws AuthenticationNeededException
294
   * @throws MissingPermissionsException
295
   * @throws UserNotFoundException
296
   * @throws UserNotInYourGuildException
297
   * @throws CannotPromoteMemberException
298
   */
299
  public function promote(int $userId): void {
300 1
    if(!$this->user->isLoggedIn()) {
301 1
      throw new AuthenticationNeededException();
302 1
    } elseif(!$this->user->isAllowed(AuthorizatorFactory::GUILD_RESOURCE_NAME, "promote")) {
303 1
      throw new MissingPermissionsException();
304
    }
305 1
    $user = $this->orm->users->getById($userId);
306 1
    if($user === null) {
307 1
      throw new UserNotFoundException();
308
    }
309
    /** @var UserEntity $admin */
310 1
    $admin = $this->orm->users->getById($this->user->id);
311 1
    if($admin->guild === null || $user->guild === null || $user->guild->id !== $admin->guild->id || $user->guildRank === null) {
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 128 characters
Loading history...
312 1
      throw new UserNotInYourGuildException();
313 1
    } elseif($user->guildRank->id >= $this->maxRank - 1) {
314 1
      throw new CannotPromoteMemberException();
315
    }
316
    $user->guildRank = $this->orm->guildRanks->getById($user->guildRank->id + 1);
317
    $this->orm->users->persistAndFlush($user);
318
  }
319
  
320
  /**
321
   * Demote a user
322
   *
323
   * @throws AuthenticationNeededException
324
   * @throws MissingPermissionsException
325
   * @throws UserNotFoundException
326
   * @throws UserNotInYourGuildException
327
   * @throws CannotDemoteMemberException
328
   */
329
  public function demote(int $userId): void {
330 1
    if(!$this->user->isLoggedIn()) {
331 1
      throw new AuthenticationNeededException();
332 1
    } elseif(!$this->user->isAllowed(AuthorizatorFactory::GUILD_RESOURCE_NAME, "demote")) {
333 1
      throw new MissingPermissionsException();
334
    }
335 1
    $user = $this->orm->users->getById($userId);
336 1
    if($user === null) {
337 1
      throw new UserNotFoundException();
338
    }
339
    /** @var UserEntity $admin */
340 1
    $admin = $this->orm->users->getById($this->user->id);
341 1
    if($admin->guild === null || $user->guild === null || $user->guild->id !== $admin->guild->id || $user->guildRank === null) {
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 128 characters
Loading history...
342 1
      throw new UserNotInYourGuildException();
343 1
    } elseif($user->guildRank->id < 2 || $user->guildRank->id === $this->maxRank) {
344 1
      throw new CannotDemoteMemberException();
345
    }
346
    $user->guildRank = $this->orm->guildRanks->getById($user->guildRank->id - 1);
347
    $this->orm->users->persistAndFlush($user);
348
  }
349
  
350
  /**
351
   * Kick a user
352
   *
353
   * @throws AuthenticationNeededException
354
   * @throws MissingPermissionsException
355
   * @throws UserNotFoundException
356
   * @throws UserNotInYourGuildException
357
   * @throws CannotKickMemberException
358
   */
359
  public function kick(int $userId): void {
360 1
    if(!$this->user->isLoggedIn()) {
361 1
      throw new AuthenticationNeededException();
362 1
    } elseif(!$this->user->isAllowed(AuthorizatorFactory::GUILD_RESOURCE_NAME, "kick")) {
363 1
      throw new MissingPermissionsException();
364
    }
365 1
    $user = $this->orm->users->getById($userId);
366 1
    if($user === null) {
367 1
      throw new UserNotFoundException();
368
    }
369
    /** @var UserEntity $admin */
370 1
    $admin = $this->orm->users->getById($this->user->id);
371 1
    if($admin->guild === null || $user->guild === null || $user->guild->id !== $admin->guild->id || $user->guildRank === null) {
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 128 characters
Loading history...
372 1
      throw new UserNotInYourGuildException();
373 1
    } elseif($user->guildRank->id === $this->maxRank) {
374 1
      throw new CannotKickMemberException();
375
    }
376
    $user->guild = $user->guildRank = null;
377
    $this->orm->users->persistAndFlush($user);
378
  }
379
}
380
?>