Completed
Push — master ( 8f238b...4d49a8 )
by Konstantinos
03:51
created

Team::getMatches()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1
Metric Value
dl 0
loc 9
ccs 2
cts 2
cp 1
rs 9.6666
cc 1
eloc 7
nc 1
nop 3
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
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
    /**
95
     * A list of cached matches to calculate team activity
96
     *
97
     * @var Match[]|null
98
     */
99
    public static $cachedMatches = null;
100
101
    /**
102
     * The name of the database table used for queries
103
     */
104
    const TABLE = "teams";
105
106
    /**
107
     * The location where avatars will be stored
108
     */
109
    const AVATAR_LOCATION = "/web/assets/imgs/avatars/teams/";
110
111
    const CREATE_PERMISSION = Permission::CREATE_TEAM;
112
    const EDIT_PERMISSION = Permission::EDIT_TEAM;
113
    const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_TEAM;
114
    const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_TEAM;
115
116
    /**
117 18
     * {@inheritdoc}
118
     */
119 18
    protected function assignResult($team)
120 18
    {
121 18
        $this->name = $team['name'];
122 18
        $this->alias = $team['alias'];
123 18
        $this->description = $team['description'];
124 18
        $this->avatar = $team['avatar'];
125 18
        $this->created = TimeDate::fromMysql($team['created']);
126 18
        $this->elo = $team['elo'];
127 18
        $this->activity = null;
128 18
        $this->leader = $team['leader'];
129 18
        $this->matches_won = $team['matches_won'];
130 18
        $this->matches_lost = $team['matches_lost'];
131 18
        $this->matches_draw = $team['matches_draw'];
132
        $this->members = $team['members'];
133 18
        $this->status = $team['status'];
134 18
135
        $this->matches_total = $this->matches_won + $this->matches_lost + $this->matches_draw;
136
    }
137
138
    /**
139
     * Adds a new member to the team
140
     *
141
     * @param int $id The id of the player to add to the team
142
     *
143 18
     * @return bool|null True if both the player was added to the team AND the team member count was incremented
144
     */
145 18
    public function addMember($id)
146
    {
147 18
        $player = Player::get($id);
148
149
        if (!$player->isTeamless()) {
150
            throw new Exception("The player already belongs in a team");
151 18
        }
152 18
153 18
        $player->setTeam($this->getId());
154
        $this->update('members', ++$this->members, "i");
155
    }
156
157
    /**
158
     * Increase or decrease the ELO of the team
159
     *
160 9
     * @param int $adjust The value to be added to the current ELO (negative to substract)
161
     */
162 9
    public function changeElo($adjust)
163 9
    {
164 9
        $this->elo += $adjust;
165
        $this->update("elo", $this->elo, "i");
166
    }
167
168
    /**
169
     * Change the ELO of the team
170
     *
171
     * @param int $elo The new team ELO
172
     */
173
    public function setElo($elo)
174
    {
175
        $this->updateProperty($this->elo, "elo", $elo, "i");
176
    }
177
178
    /**
179
     * Increment the team's match count
180
     *
181
     * @param int    $adjust The number to add to the current matches number (negative to substract)
182 9
     * @param string $type   The match count that should be changed. Can be 'win', 'draw' or 'loss'
183
     */
184 9
    public function changeMatchCount($adjust, $type)
185
    {
186
        $this->matches_total += $adjust;
187 9
188
        switch ($type) {
189 6
            case "win":
190
            case "won":
191 6
                $this->update("matches_won", $this->matches_won += $adjust, "i");
192
193 4
                return;
194 6
            case "loss":
195
            case "lost":
196 6
                $this->update("matches_lost", $this->matches_lost += $adjust, "i");
197
198 4
                return;
199
            default:
200 4
                $this->update("matches_draw", $this->matches_draw += $adjust, "i");
201
202
                return;
203
        }
204
    }
205
206
    /**
207
     * Decrement the team's match count by one
208
     *
209
     * @param string $type The type of the match. Can be 'win', 'draw' or 'loss'
210
     */
211
    public function decrementMatchCount($type)
212
    {
213
        $this->changeMatchCount(-1, $type);
214
    }
215
216
    /**
217
     * Get the activity of the team
218
     *
219 1
     * @return float The team's activity
220
     */
221 1
    public function getActivity()
222
    {
223
        if ($this->activity === null) {
224
            // We don't have a cached activity value
225
            if (self::$cachedMatches === null) {
226
                self::$cachedMatches = Match::getQueryBuilder()
227
                    ->active()
228
                    ->with($this)
229 1
                    ->where('time')->isAfter(TimeDate::from('45 days ago'))
230 1
                    ->getModels($fast = true);
231 1
            }
232 1
233
234
            $this->activity = 0.0;
235
            foreach (self::$cachedMatches as $match) {
236 1
                if ($match->involvesTeam($this)) {
237
                    $this->activity += $match->getActivity();
238
                }
239
            }
240
        }
241
242
        return $this->activity;
243
    }
244 2
245
    /**
246 2
     * Get the creation date of the team
247
     *
248
     * @return TimeDate The creation date of the team
249
     */
250
    public function getCreationDate()
251
    {
252
        return $this->created;
253
    }
254
255 1
    /**
256
     * Get the description of the team
257 1
     *
258
     * @param  bool $md false for HTML format, true for the original markdown
0 ignored issues
show
Bug introduced by
There is no parameter named $md. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
259
     * @return string  The description of the team
260
     */
261
    public function getDescription()
262
    {
263
        return $this->description;
264
    }
265 9
266
    /**
267 9
     * Get the current elo of the team
268
     *
269
     * @return int The elo of the team
270
     */
271
    public function getElo()
272
    {
273
        return $this->elo;
274
    }
275 2
276
    /**
277 2
     * Get the leader of the team
278
     *
279
     * @return Player The object representing the team leader
280
     */
281
    public function getLeader()
282
    {
283
        return Player::get($this->leader);
284
    }
285
286
    /**
287
     * Get the matches this team has participated in
288
     *
289 2
     * @param string $matchType The filter for match types: "all", "wins", "losses", or "draws"
290
     * @param int    $count     The amount of matches to be retrieved
291 2
     * @param int    $page      The number of the page to return
292 2
     *
293 2
     * @return Match[] The array of match IDs this team has participated in
294 2
     */
295 2
    public function getMatches($matchType = "all", $count = 5, $page = 1)
296 2
    {
297
        return Match::getQueryBuilder()
298
             ->active()
299
             ->with($this, $matchType)
300
             ->sortBy('time')->reverse()
301
             ->limit($count)->fromPage($page)
302
             ->getModels($fast = true);
303
    }
304 1
305
    /**
306 1
     * Get the number of matches that resulted as a draw
307
     *
308
     * @return int The number of matches, respectively
309
     */
310
    public function getMatchesDraw()
311
    {
312
        return $this->matches_draw;
313
    }
314 1
315
    /**
316 1
     * Get the number of matches that the team has lost
317
     *
318
     * @return int The number of matches, respectively
319
     */
320
    public function getMatchesLost()
321
    {
322
        return $this->matches_lost;
323
    }
324
325
    /**
326
     * Get the URL that points to the team's list of matches
327
     *
328
     * @return string The team's list of matches
329
     */
330
    public function getMatchesURL()
331
    {
332
        return Service::getGenerator()->generate("match_by_team_list", array("team" => $this->getAlias()));
333
    }
334 1
335
    /**
336 1
     * Get the number of matches that the team has won
337
     *
338
     * @return int The number of matches, respectively
339
     */
340
    public function getMatchesWon()
341
    {
342
        return $this->matches_won;
343
    }
344 2
345
    /**
346 2
     * Get the members on the team
347 2
     *
348
     * @return Player[] The members on the team
349
     */
350
    public function getMembers()
351 2
    {
352 2
        $leader = $this->leader;
353
        $members = Player::getTeamMembers($this->id);
354 1
355 1
        usort($members, function ($a, $b) use ($leader) {
356
            // Leader always goes first
357
            if ($a->getId() == $leader) {
358
                return -1;
359
            }
360
            if ($b->getId() == $leader) {
361
                return 1;
362 2
            }
363
364 2
            // Sort the rest of the players alphabetically
365
            $sort = Player::getAlphabeticalSort();
366
367
            return $sort($a, $b);
368
        });
369
370
        return $members;
371
    }
372 18
373
    /**
374 18
     * Get the name of the team
375
     *
376
     * @return string The name of the team
377 18
     */
378
    public function getName()
379
    {
380
        if ($this->name === null) {
381
            return "None";
382
        }
383
        return $this->name;
384
    }
385 1
386
    /**
387 1
     * Get the name of the team, safe for use in your HTML
388
     *
389
     * @return string The name of the team
390 1
     */
391
    public function getEscapedName()
392
    {
393
        if (!$this->valid) {
394
            return "<em>None</em>";
395
        }
396
        return $this->escape($this->name);
397
    }
398 2
399
    /**
400 2
     * Get the number of members on the team
401
     *
402
     * @return int The number of members on the team
403
     */
404
    public function getNumMembers()
405
    {
406
        return $this->members;
407
    }
408 1
409
    /**
410 1
     * Get the total number of matches this team has played
411
     *
412
     * @return int The total number of matches this team has played
413
     */
414
    public function getNumTotalMatches()
415
    {
416
        return $this->matches_total;
417
    }
418
419
    /**
420 1
     * Get the rank category a team belongs too based on their ELO
421
     *
422 1
     * This value is always a multiple of 100 and less than or equal to 2000
423
     *
424
     * @return int The rank category a team belongs to
425
     */
426
    public function getRankValue()
427
    {
428
        return min(2000, floor($this->getElo() / 100) * 100);
429
    }
430 1
431
    /**
432 1
     * Get the HTML for an image with the rank symbol
433
     *
434
     * @return string The HTML for a rank image
435
     */
436
    public function getRankImageLiteral()
437
    {
438
        return '<div class="c-rank c-rank--' . $this->getRankValue() . '"></div>';
439
    }
440
441
    /**
442
     * Increment the team's match count by one
443
     *
444
     * @param string $type The type of the match. Can be 'win', 'draw' or 'loss'
445
     */
446
    public function incrementMatchCount($type)
447
    {
448
        $this->changeMatchCount(1, $type);
449
    }
450
451
    /**
452 2
     * Check if a player is part of this team
453
     *
454 2
     * @param int $playerID The player to check
455
     *
456 2
     * @return bool True if the player belongs to this team
457
     */
458
    public function isMember($playerID)
459
    {
460
        $player = Player::get($playerID);
461
462
        return ($player->getTeam()->isSameAs($this));
463
    }
464
465 2
    /**
466
     * Removes a member from the team
467 2
     *
468
     * @param  int  $id The id of the player to remove
469
     * @return void
470
     */
471 2
    public function removeMember($id)
472
    {
473 2
        if (!$this->isMember($id)) {
474 2
            throw new Exception("The player is not a member of that team");
475 2
        }
476
477
        $player = Player::get($id);
478
479
        $player->update("team", null, "s");
480
        $this->update('members', --$this->members, "i");
481
    }
482
483
    /**
484
     * Update the description of the team
485
     *
486
     * @param  string $description The description of the team written as markdown
487
     * @return void
488
     */
489
    public function setDescription($description)
490
    {
491
        $this->update("description", $description, "s");
492
    }
493
494
    /**
495
     * Change the status of the team
496
     *
497
     * @param  string $newStatus The new status of the team (open, closed, disabled or deleted)
498
     * @return self
499
     */
500
    public function setStatus($newStatus)
501
    {
502
        return $this->updateProperty($this->status, 'status', $newStatus, 's');
503
    }
504
505
    /**
506
     * Change the leader of the team
507
     *
508
     * @param  int  $leader The ID of the new leader of the team
509
     * @return self
510
     */
511
    public function setLeader($leader)
512
    {
513
        return $this->updateProperty($this->leader, 'leader', $leader, 'i');
514
    }
515
516 1
    /**
517
     * Find if a specific match is the team's last one
518
     *
519 1
     * @param  int  $matchID The ID of the match
520 1
     * @return bool
521 1
     */
522 1
    public function isLastMatch($matchID)
523 1
    {
524
        // Find if this team participated in any matches after the current match
525
        return !Match::getQueryBuilder()
526
            ->with($this)
527
            ->where('status')->notEquals('deleted')
528
            ->where('time')->isAfter(Match::get($matchID)->getTimestamp())
529 1
            ->any();
530
    }
531 1
532
    /**
533
     * {@inheritdoc}
534 1
     */
535 1
    public function delete()
536 1
    {
537 1
        parent::delete();
538
539
        // Remove all the members of a deleted team
540
        $this->updateProperty($this->members, 'members', 0, 'i');
541
        $this->db->query("UPDATE `players` SET `team` = NULL WHERE `team` = ?",
542
            'i', $this->id);
543
    }
544
545
    /**
546
     * Create a new team
547
     *
548
     * @param  string           $name        The name of the team
549
     * @param  int              $leader      The ID of the person creating the team, also the leader
550
     * @param  string           $avatar      The URL to the team's avatar
551 19
     * @param  string           $description The team's description
552
     * @param  string           $status      The team's status (open, closed, disabled or deleted)
553 19
     * @param  string|\TimeDate $created     The date the team was created
554
     *
555 19
     * @return Team   An object that represents the newly created team
556 19
     */
557 19
    public static function createTeam($name, $leader, $avatar, $description, $status = 'closed', $created = "now")
558 19
    {
559 19
        $created = TimeDate::from($created);
560 19
561 19
        $team = self::create(array(
562 19
            'name'         => $name,
563 19
            'alias'        => self::generateAlias($name),
564 19
            'description'  => $description,
565 19
            'elo'          => 1200,
566 19
            'activity'     => 0.00,
567 19
            'matches_won'  => 0,
568 19
            'matches_draw' => 0,
569 19
            'matches_lost' => 0,
570
            'members'      => 0,
571 18
            'avatar'       => $avatar,
572 18
            'leader'       => $leader,
573
            'status'       => $status,
574 18
            'created'      => $created->toMysql(),
575
        ), 'sssidiiiissss');
576
577
        $team->addMember($leader);
578
        $team->getIdenticon($team->getId());
579
580
        return $team;
581
    }
582
583
    /**
584
     * Get all the teams in the database that are not disabled or deleted
585
     *
586
     * @return Team[] An array of Team IDs
587
     */
588
    public static function getTeams()
589
    {
590
        return self::arrayIdToModel(
591
            parent::fetchIdsFrom(
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (fetchIdsFrom() instead of getTeams()). Are you sure this is correct? If so, you might want to change this to $this->fetchIdsFrom().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
592
                "status", array("disabled", "deleted"),
593
                "s", true, "ORDER BY elo DESC"
594
            )
595
        );
596
    }
597
598 1
    /**
599
     * Get a single team by its name
600 1
     *
601
     * @param  string $name The team name to look for
602 1
     * @return Team
603
     */
604
    public static function getFromName($name)
605
    {
606
        $team = static::get(self::fetchIdFrom($name, 'name', 's'));
607
608
        return $team->inject('name', $name);
609
    }
610
611 1
    /**
612
     * Alphabetical order function for use in usort (case-insensitive)
613 1
     * @return Closure The sort function
614
     */
615
    public static function getAlphabeticalSort()
616
    {
617
        return function (Team $a, Team $b) {
618
            return strcasecmp($a->getName(), $b->getName());
619 1
        };
620
    }
621 1
622
    /**
623
     * {@inheritdoc}
624
     */
625
    public static function getActiveStatuses()
626
    {
627
        return array('open', 'closed');
628 1
    }
629
630 1
    /**
631
     * Get a query builder for teams
632
     * @return QueryBuilder
633
     */
634 View Code Duplication
    public static function getQueryBuilder()
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...
635
    {
636 1
        return new QueryBuilder('Team', array(
637
            'columns' => array(
638
                'name' => 'name',
639
                'elo' => 'elo',
640
                'members' => 'members',
641
                'status' => 'status'
642
            ),
643
            'name' => 'name',
644 1
        ));
645
    }
646 1
647
    /**
648
     * {@inheritdoc}
649
     */
650
    protected function isEditor($player)
651
    {
652
        return $player->isSameAs($this->getLeader());
653
    }
654
}
655