Team::supportsMatchCount()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * This file contains functionality relating to the teams belonging to the current league
4
 *
5
 * @package    BZiON\Models
6
 * @license    https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3
7
 */
8
9
/**
10
 * A league team
11
 * @package    BZiON\Models
12
 */
13
class Team extends AvatarModel implements TeamInterface, DuplexUrlInterface, EloInterface
14
{
15
    /**
16
     * The description of the team written in markdown
17
     *
18
     * @var string
19
     */
20
    protected $description;
21
22
    /**
23
     * The creation date of the team
24
     *
25
     * @var TimeDate
26
     */
27
    protected $created;
28
29
    /**
30
     * The team's current elo
31
     *
32
     * @var int
33
     */
34
    protected $elo;
35
36
    /**
37
     * The team's activity
38
     *
39
     * null if we haven't calculated it yet
40
     *
41
     * @var float|null
42
     */
43
    protected $activity = null;
44
45
    /**
46
     * The id of the team leader
47
     *
48
     * @var int
49
     */
50
    protected $leader;
51
52
    /**
53
     * The number of matches won
54
     *
55
     * @var int
56
     */
57
    protected $matches_won;
58
59
    /**
60
     * The number of matches lost
61
     *
62
     * @var int
63
     */
64
    protected $matches_lost;
65
66
    /**
67
     * The number of matches tied
68
     *
69
     * @var int
70
     */
71
    protected $matches_draw;
72
73
    /**
74
     * The total number of matches
75
     *
76
     * @var int
77
     */
78
    protected $matches_total;
79
80
    /**
81
     * The number of members
82
     *
83
     * @var int
84
     */
85
    protected $members;
86
87
    /**
88
     * The team's status
89
     *
90
     * @var string
91
     */
92
    protected $status;
93
94
    const DEFAULT_STATUS = 'closed';
95
96
    /**
97
     * The name of the database table used for queries
98
     */
99
    const TABLE = "teams";
100
101
    /**
102
     * The location where avatars will be stored
103
     */
104
    const AVATAR_LOCATION = "/web/assets/imgs/avatars/teams/";
105
106
    const CREATE_PERMISSION = Permission::CREATE_TEAM;
107
    const EDIT_PERMISSION = Permission::EDIT_TEAM;
108
    const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_TEAM;
109
    const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_TEAM;
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    protected function assignResult($team)
115
    {
116
        $this->name = $team['name'];
117
        $this->alias = $team['alias'];
118
        $this->description = $team['description'];
119 55
        $this->avatar = $team['avatar'];
120
        $this->created = TimeDate::fromMysql($team['created']);
121 55
        $this->elo = $team['elo'];
122 55
        $this->leader = $team['leader'];
123 55
        $this->matches_won = $team['matches_won'];
124 55
        $this->matches_lost = $team['matches_lost'];
125 55
        $this->matches_draw = $team['matches_draw'];
126 55
        $this->members = $team['members'];
127 55
        $this->status = $team['status'];
128 55
129 55
        $this->matches_total = $this->matches_won + $this->matches_lost + $this->matches_draw;
130 55
131 55
        $this->activity = isset($team['activity']) ? $team['activity'] : 0;
132 55
    }
133 55
134
    /**
135 55
     * Adds a new member to the team
136 55
     *
137
     * @param int $id The id of the player to add to the team
138
     *
139
     * @return bool|null True if both the player was added to the team AND the team member count was incremented
140
     */
141 View Code Duplication
    public function addMember($id)
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...
142
    {
143
        $player = Player::get($id);
144
145 55
        if (!$player->isTeamless()) {
146
            throw new Exception("The player already belongs in a team");
147 55
        }
148
149 55
        $player->setTeam($this->getId());
150
        $this->update('members', ++$this->members);
151
    }
152
153 55
    /**
154 55
     * Increase or decrease the ELO of the team
155 55
     *
156
     * @param int   $adjust The value to be added to the current ELO (negative to subtract)
157
     * @param Match $match  The match where this Elo change took place
158
     */
159
    public function adjustElo($adjust, Match $match = null)
160
    {
161
        $this->elo += $adjust;
162
        $this->update("elo", $this->elo);
163 33
    }
164
165 33
    /**
166 33
     * Change the ELO of the team
167 33
     *
168
     * @param int $elo The new team ELO
169
     */
170
    public function setElo($elo)
171
    {
172
        $this->updateProperty($this->elo, "elo", $elo);
173
    }
174 6
175
    /**
176 6
     * Increment the team's match count
177 6
     *
178
     * @param int    $adjust The number to add to the current matches number (negative to substract)
179
     * @param string $type   The match count that should be changed. Can be 'win', 'draw' or 'loss'
180
     */
181
    public function changeMatchCount($adjust, $type)
182
    {
183
        $this->matches_total += $adjust;
184
185 33
        switch ($type) {
186
            case "win":
187 33
            case "won":
188
                $this->update("matches_won", $this->matches_won += $adjust);
189
190 33
                return;
191 31
            case "loss":
192 15
            case "lost":
193
                $this->update("matches_lost", $this->matches_lost += $adjust);
194 15
195 31
                return;
196 16
            default:
197 16
                $this->update("matches_draw", $this->matches_draw += $adjust);
198
199 16
                return;
200
        }
201 16
    }
202
203 16
    /**
204
     * Decrement the team's match count by one
205
     *
206
     * @param string $type The type of the match. Can be 'win', 'draw' or 'loss'
207
     */
208
    public function decrementMatchCount($type)
209
    {
210
        $this->changeMatchCount(-1, $type);
211
    }
212
213
    /**
214
     * Get the activity of the team
215
     *
216
     * @return float The team's activity
217
     */
218
    public function getActivity()
219
    {
220
        return $this->activity;
221
    }
222 1
223
    /**
224 1
     * Get the creation date of the team
225
     *
226 1
     * @return TimeDate The creation date of the team
227
     */
228
    public function getCreationDate()
229
    {
230
        return $this->created->copy();
231
    }
232
233
    /**
234 1
     * Get the description of the team
235 1
     *
236 1
     * @return string  The description of the team
237 1
     */
238
    public function getDescription()
239
    {
240
        return $this->description;
241
    }
242 1
243
    /**
244
     * Get the current elo of the team
245
     *
246
     * @return int The elo of the team
247
     */
248
    public function getElo()
249
    {
250 2
        return $this->elo;
251
    }
252 2
253
    /**
254
     * Get the leader of the team
255
     *
256
     * @return Player The object representing the team leader
257
     */
258
    public function getLeader()
259
    {
260 1
        return Player::get($this->leader);
261
    }
262 1
263
    /**
264
     * Get the matches this team has participated in
265
     *
266
     * @param string $matchType The filter for match types: "all", "wins", "losses", or "draws"
267
     * @param int    $count     The amount of matches to be retrieved
268
     * @param int    $page      The number of the page to return
269
     *
270 34
     * @return Match[] The array of match IDs this team has participated in
271
     */
272 34
    public function getMatches($matchType = "all", $count = 5, $page = 1)
273
    {
274
        return Match::getQueryBuilder()
275
             ->active()
276
             ->with($this, $matchType)
277
             ->sortBy('time')->reverse()
278
             ->limit($count)->fromPage($page)
279
             ->getModels($fast = true);
280 2
    }
281
282 2
    /**
283
     * Get the number of matches that resulted as a draw
284
     *
285
     * @return int The number of matches, respectively
286
     */
287
    public function getMatchesDraw()
288
    {
289
        return $this->matches_draw;
290
    }
291
292
    /**
293
     * Get the number of matches that the team has lost
294 2
     *
295
     * @return int The number of matches, respectively
296 2
     */
297 2
    public function getMatchesLost()
298 2
    {
299 2
        return $this->matches_lost;
300 2
    }
301 2
302
    /**
303
     * Get the URL that points to the team's list of matches
304
     *
305
     * @return string The team's list of matches
306
     */
307
    public function getMatchesURL()
308
    {
309 1
        return Service::getGenerator()->generate("match_by_team_list", array("team" => $this->getAlias()));
310
    }
311 1
312
    /**
313
     * Get the number of matches that the team has won
314
     *
315
     * @return int The number of matches, respectively
316
     */
317
    public function getMatchesWon()
318
    {
319 1
        return $this->matches_won;
320
    }
321 1
322
    /**
323
     * Get the members on the team
324
     *
325
     * @return Player[] The members on the team
326
     */
327
    public function getMembers()
328
    {
329
        $leader = $this->leader;
330
        $members = Player::getTeamMembers($this->id);
331
332
        usort($members, function ($a, $b) use ($leader) {
333
            // Leader always goes first
334
            if ($a->getId() == $leader) {
335
                return -1;
336
            }
337
            if ($b->getId() == $leader) {
338
                return 1;
339 1
            }
340
341 1
            // Sort the rest of the players alphabetically
342
            $sort = Player::getAlphabeticalSort();
343
344
            return $sort($a, $b);
345
        });
346
347
        return $members;
348
    }
349 2
350
    /**
351 2
     * Get the name of the team
352 2
     *
353
     * @return string The name of the team
354
     */
355
    public function getName()
356 2
    {
357 2
        if ($this->name === null) {
358
            return "None";
359 1
        }
360 1
        return $this->name;
361
    }
362
363
    /**
364
     * Get the name of the team, safe for use in your HTML
365
     *
366
     * @return string The name of the team
367 2
     */
368
    public function getEscapedName()
369 2
    {
370
        if (!$this->valid) {
371
            return "<em>None</em>";
372
        }
373
        return $this->escape($this->name);
374
    }
375
376
    /**
377 55
     * Get the number of members on the team
378
     *
379 55
     * @return int The number of members on the team
380
     */
381
    public function getNumMembers()
382 55
    {
383
        return $this->members;
384
    }
385
386
    /**
387
     * Get the total number of matches this team has played
388
     *
389
     * @return int The total number of matches this team has played
390 1
     */
391
    public function getNumTotalMatches()
392 1
    {
393
        return $this->matches_total;
394
    }
395 1
396
    /**
397
     * Get the rank category a team belongs too based on their ELO
398
     *
399
     * This value is always a multiple of 100 and less than or equal to 2000
400
     *
401
     * @return int The rank category a team belongs to
402
     */
403 2
    public function getRankValue()
404
    {
405 2
        return min(2000, floor($this->getElo() / 100) * 100);
406
    }
407
408
    /**
409
     * Get the HTML for an image with the rank symbol
410
     *
411
     * @return string The HTML for a rank image
412
     */
413 2
    public function getRankImageLiteral()
414
    {
415 2
        return '<div class="c-rank c-rank--' . $this->getRankValue() . '" aria-hidden="true"></div>';
416
    }
417
418
    /**
419
     * Increment the team's match count by one
420
     *
421
     * @param string $type The type of the match. Can be 'win', 'draw' or 'loss'
422
     */
423
    public function incrementMatchCount($type)
424
    {
425 1
        $this->changeMatchCount(1, $type);
426
    }
427 1
428
    /**
429
     * Check if a player is part of this team
430
     *
431
     * @param int $playerID The player to check
432
     *
433
     * @return bool True if the player belongs to this team
434
     */
435 1
    public function isMember($playerID)
436
    {
437 1
        $player = Player::get($playerID);
438
439
        return $player->getTeam()->isSameAs($this);
440
    }
441
442
    /**
443
     * Removes a member from the team
444
     *
445
     * @param  int  $id The id of the player to remove
446
     * @return void
447
     */
448 View Code Duplication
    public function removeMember($id)
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...
449
    {
450
        if (!$this->isMember($id)) {
451
            throw new Exception("The player is not a member of that team");
452
        }
453
454
        $player = Player::get($id);
455
456
        $player->update("team", null);
457 2
        $this->update('members', --$this->members);
458
    }
459 2
460
    /**
461 2
     * Update the description of the team
462
     *
463
     * @param  string $description The description of the team written as markdown
464
     * @return void
465
     */
466
    public function setDescription($description)
467
    {
468
        $this->update("description", $description);
469
    }
470 2
471
    /**
472 2
     * Change the status of the team
473
     *
474
     * @param  string $newStatus The new status of the team (open, closed, disabled or deleted)
475
     * @return self
476 2
     */
477
    public function setStatus($newStatus)
478 2
    {
479 2
        return $this->updateProperty($this->status, 'status', $newStatus);
480 2
    }
481
482
    /**
483
     * Change the leader of the team
484
     *
485
     * @param  int  $leader The ID of the new leader of the team
486
     * @return self
487
     */
488
    public function setLeader($leader)
489
    {
490
        return $this->updateProperty($this->leader, 'leader', $leader);
491
    }
492
493
    /**
494
     * Find if a specific match is the team's last one
495
     *
496
     * @param  int|Match $match The match
497
     * @return bool
498
     */
499
    public function isLastMatch($match)
500
    {
501
        // Find if this team participated in any matches after the current match
502
        return !Match::getQueryBuilder()
503
            ->with($this)
504
            ->where('status')->notEquals('deleted')
505
            ->where('time')->isAfter(Match::get($match)->getTimestamp())
506
            ->any();
507
    }
508
509
    /**
510
     * {@inheritdoc}
511
     */
512
    public function delete()
513
    {
514
        parent::delete();
515
516
        // Remove all the members of a deleted team
517
        $this->updateProperty($this->members, 'members', 0);
518
        $this->db->execute('UPDATE players SET team = NULL WHERE team = ?', $this->id);
519
    }
520
521 1
    /**
522
     * {@inheritdoc}
523
     */
524 1
    public function supportsMatchCount()
525 1
    {
526 1
        return $this->isValid();
527 1
    }
528 1
529
    /**
530
     * Create a new team
531
     *
532
     * @param  string           $name        The name of the team
533
     * @param  int              $leader      The ID of the person creating the team, also the leader
534 1
     * @param  string           $avatar      The URL to the team's avatar
535
     * @param  string           $description The team's description
536 1
     * @param  string           $status      The team's status (open, closed, disabled or deleted)
537
     * @param  string|\TimeDate $created     The date the team was created
538
     *
539 1
     * @return Team   An object that represents the newly created team
540 1
     */
541 1
    public static function createTeam($name, $leader, $avatar, $description, $status = 'closed', $created = "now")
542
    {
543
        $created = TimeDate::from($created);
544
545
        $team = self::create(array(
546 42
            'name'         => $name,
547
            'alias'        => self::generateAlias($name),
548 42
            'description'  => $description,
549
            'elo'          => 1200,
550
            'matches_won'  => 0,
551
            'matches_draw' => 0,
552
            'matches_lost' => 0,
553
            'members'      => 0,
554
            'avatar'       => $avatar,
555
            'leader'       => $leader,
556
            'status'       => $status,
557
            'created'      => $created->toMysql(),
558
        ));
559
560
        $team->addMember($leader);
561
        $team->getIdenticon($team->getId());
562
563 56
        return $team;
564
    }
565 56
566
    /**
567 56
     * Get all the teams in the database that are not disabled or deleted
568 56
     *
569 56
     * @return Team[] An array of Team IDs
570 56
     */
571 56
    public static function getTeams()
572 56
    {
573 56
        return self::arrayIdToModel(
574 56
            self::fetchIdsFrom(
575 56
                "status", array("disabled", "deleted"),
576 56
                true, "ORDER BY elo DESC"
577 56
            )
578 56
        );
579 56
    }
580 56
581
    /**
582
     * Get a single team by its name
583 55
     *
584 55
     * @param  string $name The team name to look for
585
     * @return Team
586 55
     */
587
    public static function getFromName($name)
588
    {
589
        $team = static::get(self::fetchIdFrom($name, 'name'));
590
591
        return $team->inject('name', $name);
592
    }
593
594
    /**
595
     * Alphabetical order function for use in usort (case-insensitive)
596
     * @return Closure The sort function
597
     */
598
    public static function getAlphabeticalSort()
599
    {
600
        return function (Team $a, Team $b) {
601
            return strcasecmp($a->getName(), $b->getName());
602
        };
603
    }
604
605
    /**
606
     * {@inheritdoc}
607
     */
608
    public static function getActiveStatuses()
609
    {
610 1
        return array('open', 'closed');
611
    }
612 1
613
    /**
614 1
     * {@inheritdoc}
615
     */
616
    public static function getEagerColumns($prefix = null)
617
    {
618
        $columns = [
619
            'id',
620
            'name',
621
            'alias',
622
            'description',
623 1
            'avatar',
624
            'created',
625 1
            'elo',
626
            'leader',
627
            'matches_won',
628
            'matches_lost',
629
            'matches_draw',
630
            'members',
631 1
            'status',
632
        ];
633 1
634
        return self::formatColumns($prefix, $columns);
635
    }
636
637
    /**
638
     * Get a query builder for teams
639
     * @return TeamQueryBuilder
640 1
     */
641
    public static function getQueryBuilder()
642 1
    {
643 1
        return new TeamQueryBuilder('Team', array(
644
            'columns' => array(
645
                'name'    => 'name',
646
                'elo'     => 'elo',
647
                'leader'  => 'leader',
648
                'members' => 'members',
649
                'status'  => 'status'
650
            ),
651
            'name' => 'name',
652
        ));
653
    }
654
655
    /**
656 1
     * {@inheritdoc}
657
     */
658 1
    protected function isEditor($player)
659
    {
660
        return $player->isSameAs($this->getLeader());
661
    }
662
}
663