Completed
Push — master ( 511324...c26f0f )
by Konstantinos
08:12
created

Match::getTeamEloNew()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.0416

Importance

Changes 2
Bugs 1 Features 0
Metric Value
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.4285
c 2
b 1
f 0
cc 3
eloc 6
nc 3
nop 1
crap 3.0416
1
<?php
2
/**
3
 * This file contains functionality relating to the official matches played in the 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
use BZIon\Model\Column\Timestamp;
9
10
/**
11
 * A match played between two teams
12
 * @package    BZiON\Models
13
 */
14
class Match extends UrlModel implements NamedModel
15
{
16
    use Timestamp;
17
18
    /**
19
     * The ID of the first team of the match
20
     * @var int
21
     */
22
    protected $team_a;
23
24
    /**
25
     * The ID of the second team of the match
26
     * @var int
27
     */
28
    protected $team_b;
29
30
    /**
31
     * The match points (usually the number of flag captures) Team A scored
32
     * @var int
33
     */
34
    protected $team_a_points;
35
36
    /**
37
     * The match points Team B scored
38
     * @var int
39
     */
40
    protected $team_b_points;
41
42
    /**
43
     * The BZIDs of players part of Team A who participated in the match, separated by commas
44
     * @var string
45
     */
46
    protected $team_a_players;
47
48
    /**
49
     * The BZIDs of players part of Team B who participated in the match, separated by commas
50
     * @var string
51
     */
52
    protected $team_b_players;
53
54
    /**
55
     * The ELO score of Team A after the match
56
     * @var int
57
     */
58
    protected $team_a_elo_new;
59
60
    /**
61
     * The ELO score of Team B after the match
62
     * @var int
63
     */
64
    protected $team_b_elo_new;
65
66
    /**
67
     * The map ID used in the match if the league supports more than one map
68
     * @var int
69
     */
70
    protected $map;
71
72
    /**
73
     * A JSON string of events that happened during a match, such as captures and substitutions
74
     * @var string
75
     */
76
    protected $match_details;
77
78
    /**
79
     * The port of the server where the match took place
80
     * @var int
81
     */
82
    protected $port;
83
84
    /**
85
     * The server location of there the match took place
86
     * @var string
87
     */
88
    protected $server;
89
90
    /**
91
     * The file name of the replay file of the match
92
     * @var string
93
     */
94
    protected $replay_file;
95
96
    /**
97
     * The absolute value of the ELO score difference
98
     * @var int
99
     */
100
    protected $elo_diff;
101
102
    /**
103
     * The timestamp representing when the match information was last updated
104
     * @var TimeDate
105
     */
106
    protected $updated;
107
108
    /**
109
     * The duration of the match in minutes
110
     * @var int
111
     */
112
    protected $duration;
113
114
    /**
115
     * The ID of the person (i.e. referee) who last updated the match information
116
     * @var string
117
     */
118
    protected $entered_by;
119
120
    /**
121
     * The status of the match. Can be 'entered', 'disabled', 'deleted' or 'reported'
122
     * @var string
123
     */
124
    protected $status;
125
126
    /**
127
     * The name of the database table used for queries
128
     */
129
    const TABLE = "matches";
130
131
    const CREATE_PERMISSION = Permission::ENTER_MATCH;
132
    const EDIT_PERMISSION = Permission::EDIT_MATCH;
133
    const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_MATCH;
134
    const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_MATCH;
135
136
    /**
137
     * {@inheritdoc}
138
     */
139 9
    protected function assignResult($match)
140
    {
141 9
        $this->team_a = $match['team_a'];
142 9
        $this->team_b = $match['team_b'];
143 9
        $this->team_a_points = $match['team_a_points'];
144 9
        $this->team_b_points = $match['team_b_points'];
145 9
        $this->team_a_players = $match['team_a_players'];
146 9
        $this->team_b_players = $match['team_b_players'];
147 9
        $this->team_a_elo_new = $match['team_a_elo_new'];
148 9
        $this->team_b_elo_new = $match['team_b_elo_new'];
149 9
        $this->map = $match['map'];
150 9
        $this->match_details = $match['match_details'];
151 9
        $this->port = $match['port'];
152 9
        $this->server = $match['server'];
153 9
        $this->replay_file = $match['replay_file'];
154 9
        $this->elo_diff = $match['elo_diff'];
155 9
        $this->timestamp = TimeDate::fromMysql($match['timestamp']);
156 9
        $this->updated = TimeDate::fromMysql($match['updated']);
157 9
        $this->duration = $match['duration'];
158 9
        $this->entered_by = $match['entered_by'];
159 9
        $this->status = $match['status'];
160 9
    }
161
162
    /**
163
     * Get the name of the route that shows the object
164
     * @param  string $action The route's suffix
165
     * @return string
166
     */
167 1
    public static function getRouteName($action = 'show')
168
    {
169 1
        return "match_$action";
170
    }
171
172
    /**
173
     * Get a one word description of a match relative to a team (i.e. win, loss, or draw)
174
     *
175
     * @param int $teamID The team ID we want the noun for
176
     *
177
     * @return string Either "win", "loss", or "draw" relative to the team
178
     */
179 1
    public function getMatchDescription($teamID)
180
    {
181 1
        if ($this->getScore($teamID) > $this->getOpponentScore($teamID)) {
182 1
            return "win";
183 1
        } elseif ($this->getScore($teamID) < $this->getOpponentScore($teamID)) {
184 1
            return "loss";
185
        }
186
187 1
        return "tie";
188
    }
189
190
    /**
191
     * Get a one letter description of a match relative to a team (i.e. W, L, or T)
192
     *
193
     * @param int $teamID The team ID we want the noun for
194
     *
195
     * @return string Either "W", "L", or "T" relative to the team
196
     */
197 1
    public function getMatchLetter($teamID)
198
    {
199 1
        return strtoupper(substr($this->getMatchDescription($teamID), 0, 1));
200
    }
201
202
    /**
203
     * Get the score of a specific team
204
     *
205
     * @param int|Team $teamID The team we want the score for
206
     *
207
     * @return int The score that team received
208
     */
209 2 View Code Duplication
    public function getScore($teamID)
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...
210
    {
211 2
        if ($teamID instanceof Team) {
212
            // Oh no! The caller gave us a Team model instead of an ID!
213 1
            $teamID = $teamID->getId();
214
        }
215
216 2
        if ($this->getTeamA()->getId() == $teamID) {
217 2
            return $this->getTeamAPoints();
218
        }
219
220 1
        return $this->getTeamBPoints();
221
    }
222
223
    /**
224
     * Get the score of the opponent relative to a team
225
     *
226
     * @param int $teamID The opponent of the team we want the score for
227
     *
228
     * @return int The score of the opponent
229
     */
230 2 View Code Duplication
    public function getOpponentScore($teamID)
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...
231
    {
232 2
        if ($teamID instanceof Team) {
233
            $teamID = $teamID->getId();
234
        }
235
236 2
        if ($this->getTeamA()->getId() != $teamID) {
237 1
            return $this->getTeamAPoints();
238
        }
239
240 2
        return $this->getTeamBPoints();
241
    }
242
243
    /**
244
     * Get the opponent of a match relative to a team ID
245
     *
246
     * @param int $teamID The team who is known in a match
247
     *
248
     * @return Team The opponent team
249
     */
250 8
    public function getOpponent($teamID)
251
    {
252 8
        if ($this->getTeamA()->getId() == $teamID) {
253 6
            return $this->getTeamB();
254
        }
255
256 4
        return $this->getTeamA();
257
    }
258
259
    /**
260
     * Get the timestamp of the last update of the match
261
     *
262
     * @return TimeDate The match's update timestamp
263
     */
264 1
    public function getUpdated()
265
    {
266 1
        return $this->updated->copy();
267
    }
268
269
    /**
270
     * Set the timestamp of the match
271
     *
272
     * @param  mixed The match's new timestamp
273
     * @return $this
274
     */
275
    public function setTimestamp($timestamp)
276
    {
277
        $this->timestamp = TimeDate::from($timestamp);
278
        $this->update("timestamp", $this->timestamp->toMysql());
279
280
        return $this;
281
    }
282
283
    /**
284
     * Get the first team involved in the match
285
     * @return Team Team A's id
286
     */
287 9
    public function getTeamA()
288
    {
289 9
        return Team::get($this->team_a);
290
    }
291
292
    /**
293
     * Get the second team involved in the match
294
     * @return Team Team B's id
295
     */
296 9
    public function getTeamB()
297
    {
298 9
        return Team::get($this->team_b);
299
    }
300
301
    /**
302
     * Get the list of players on Team A who participated in this match
303
     * @return Player[]|null Returns null if there were no players recorded for this match
304
     */
305 1
    public function getTeamAPlayers()
306
    {
307 1
        return $this->parsePlayers($this->team_a_players);
308
    }
309
310
    /**
311
     * Get the list of players on Team B who participated in this match
312
     * @return Player[]|null Returns null if there were no players recorded for this match
313
     */
314 1
    public function getTeamBPlayers()
315
    {
316 1
        return $this->parsePlayers($this->team_b_players);
317
    }
318
319
    /**
320
     * Get the list of players for a team in a match
321
     * @param  Team|int The team or team ID
322
     * @return Player[]|null Returns null if there were no players recorded for this match
323
     */
324 1
    public function getPlayers($team)
325
    {
326 1
        if ($team instanceof Team) {
327 1
            $team = $team->getId();
328
        }
329
330 1
        if ($team == $this->team_a) {
331 1
            return $this->getTeamAPlayers();
332 1
        } elseif ($team == $this->team_b) {
333 1
            return $this->getTeamBPlayers();
334
        }
335
336
        return null;
337
    }
338
339
    /**
340
     * Set the players of the match's teams
341
     *
342
     * @param int[] $teamAPlayers An array of player IDs
343
     * @param int[] $teamBPlayers An array of player IDs
344
     * @return self
345
     */
346
    public function setTeamPlayers($teamAPlayers = array(), $teamBPlayers = array())
347
    {
348
        $this->updateProperty($this->team_a_players, "team_a_players", implode(',', $teamAPlayers));
349
        $this->updateProperty($this->team_b_players, "team_b_players", implode(',', $teamBPlayers));
350
351
        return $this;
352
    }
353
354
    /**
355
     * Get an array of players based on a string representation
356
     * @param string $playerString
357
     * @return Player[]|null Returns null if there were no players recorded for this match
358
     */
359 1
    private static function parsePlayers($playerString)
360
    {
361 1
        if ($playerString == null) {
362 1
            return null;
363
        }
364
365
        return Player::arrayIdToModel(explode(",", $playerString));
366
    }
367
368
    /**
369
     * Get the first team's points
370
     * @return int Team A's points
371
     */
372 4
    public function getTeamAPoints()
373
    {
374 4
        return $this->team_a_points;
375
    }
376
377
    /**
378
     * Get the second team's points
379
     * @return int Team B's points
380
     */
381 4
    public function getTeamBPoints()
382
    {
383 4
        return $this->team_b_points;
384
    }
385
386
    /**
387
     * Set the match team points
388
     *
389
     * @param  int $teamAPoints Team A's points
390
     * @param  int $teamBPoints Team B's points
391
     * @return self
392
     */
393
    public function setTeamPoints($teamAPoints, $teamBPoints)
394
    {
395
        $this->updateProperty($this->team_a_points, "team_a_points", $teamAPoints);
396
        $this->updateProperty($this->team_b_points, "team_b_points", $teamBPoints);
397
398
        return $this;
399
    }
400
401
    /**
402
     * Get the ELO difference applied to each team's old ELO
403
     * @return int The ELO difference
404
     */
405 7
    public function getEloDiff()
406
    {
407 7
        return abs($this->elo_diff);
408
    }
409
410
    /**
411
     * Get the first team's new ELO
412
     * @return int Team A's new ELO
413
     */
414 7
    public function getTeamAEloNew()
415
    {
416 7
        return $this->team_a_elo_new;
417
    }
418
419
    /**
420
     * Get the second team's new ELO
421
     * @return int Team B's new ELO
422
     */
423 7
    public function getTeamBEloNew()
424
    {
425 7
        return $this->team_b_elo_new;
426
    }
427
428
    /**
429
     * Get the first team's old ELO
430
     * @return int
431
     */
432 6
    public function getTeamAEloOld()
433
    {
434 6
        return $this->team_a_elo_new - $this->elo_diff;
435
    }
436
437
    /**
438
     * Get the second team's old ELO
439
     * @return int
440
     */
441 6
    public function getTeamBEloOld()
442
    {
443 6
        return $this->team_b_elo_new + $this->elo_diff;
444
    }
445
446
    /**
447
     * Get the team's new ELO
448
     * @param  Team $team The team whose new ELO to return
449
     * @return int|null   The new ELO, or null if the team provided has not
450
     *                    participated in the match
451
     */
452 1
    public function getTeamEloNew(Team $team)
453
    {
454 1
        if ($team->getId() == $this->team_a) {
455 1
            return $this->getTeamAEloNew();
456 1
        } elseif ($team->getId() == $this->team_b) {
457 1
            return $this->getTeamBEloNew();
458
        }
459
460
        return null;
461
    }
462
463
    /**
464
     * Get the team's old ELO
465
     * @param  Team $team The team whose old ELO to return
466
     * @return int|null   The old ELO, or null if the team provided has not
467
     *                    participated in the match
468
     */
469 1
    public function getTeamEloOld(Team $team)
470
    {
471 1
        if ($team->getId() == $this->team_a) {
472 1
            return $this->getTeamAEloOld();
473 1
        } elseif ($team->getId() == $this->team_b) {
474 1
            return $this->getTeamBEloOld();
475
        }
476
477
        return null;
478
    }
479
480
    /**
481
     * Get the map where the match was played on
482
     * @return Map Returns an invalid map if no map was found
483
     */
484 1
    public function getMap()
485
    {
486 1
        return Map::get($this->map);
487
    }
488
489
    /**
490
     * Set the map where the match was played
491
     * @param  int $map The ID of the map
492
     * @return self
493
     */
494
    public function setMap($map)
495
    {
496
        $this->updateProperty($this->map, "map", $map);
497
    }
498
499
    /**
500
     * Get a JSON decoded array of events that occurred during the match
501
     * @return mixed|null Returns null if there were no events recorded for the match
502
     */
503
    public function getMatchDetails()
504
    {
505
        return json_decode($this->match_details);
506
    }
507
508
    /**
509
     * Get the server address of the server where this match took place
510
     * @return string|null Returns null if there was no server address recorded
511
     */
512
    public function getServerAddress()
513
    {
514
        if ($this->port == null || $this->server == null) {
515
            return null;
516
        }
517
518
        return $this->server . ":" . $this->port;
519
    }
520
521
    /**
522
     * Set the server address of the server where this match took place
523
     *
524
     * @param  string|null $server The server hostname
525
     * @param  int|null    $port   The server port
526
     * @return self
527
     */
528
    public function setServerAddress($server = null, $port = 5154)
529
    {
530
        $this->updateProperty($this->server, "server", $server);
531
        $this->updateProperty($this->port, "port", $port);
532
533
        return $this;
534
    }
535
536
    /**
537
     * Get the name of the replay file for this specific map
538
     * @param  int    $length The length of the replay file name; it will be truncated
539
     * @return string Returns null if there was no replay file name recorded
540
     */
541
    public function getReplayFileName($length = 0)
542
    {
543
        if ($length > 0) {
544
            return substr($this->replay_file, 0, $length);
545
        }
546
547
        return $this->replay_file;
548
    }
549
550
    /**
551
     * Get the match duration
552
     * @return int The duration of the match in minutes
553
     */
554 3
    public function getDuration()
555
    {
556 3
        return $this->duration;
557
    }
558
559
    /**
560
     * Set the match duration
561
     *
562
     * @param  int  $duration The new duration of the match in minutes
563
     * @return self
564
     */
565
    public function setDuration($duration)
566
    {
567
        return $this->updateProperty($this->duration, "duration", $duration);
568
    }
569
570
    /**
571
     * Get the user who entered the match
572
     * @return Player
573
     */
574 2
    public function getEnteredBy()
575
    {
576 2
        return Player::get($this->entered_by);
577
    }
578
579
    /**
580
     * Get the loser of the match
581
     *
582
     * @return Team The team that was the loser or the team with the lower elo if the match was a draw
583
     */
584 8
    public function getLoser()
585
    {
586
        // Get the winner of the match
587 8
        $winner = $this->getWinner();
588
589
        // Get the team that wasn't the winner... Duh
590 8
        return $this->getOpponent($winner->getId());
591
    }
592
593
    /**
594
     * Get the winner of a match
595
     *
596
     * @return Team The team that was the victor or the team with the lower elo if the match was a draw
597
     */
598 8
    public function getWinner()
599
    {
600
        // Get the team that had its ELO increased
601 8
        if ($this->elo_diff > 0) {
602 6
            return $this->getTeamA();
603 2
        } elseif ($this->elo_diff < 0) {
604 2
            return $this->getTeamB();
605
        }
606
607
        // If the ELOs are the same, return Team A because well, fuck you that's why
608
        return $this->getTeamA();
609
    }
610
611
    /**
612
     * Determine whether the match was a draw
613
     * @return bool True if the match ended without any winning teams
614
     */
615 9
    public function isDraw()
616
    {
617 9
        return $this->team_a_points == $this->team_b_points;
618
    }
619
620
    /**
621
     * Find out whether the match involves a team
622
     *
623
     * @param  Team $team The team to check
624
     * @return bool
625
     */
626 1
    public function involvesTeam($team)
627
    {
628 1
        return $team->getId() == $this->team_a || $team->getId() == $this->team_b;
629
    }
630
631
    /**
632
     * Reset the ELOs of the teams participating in the match
633
     *
634
     * @return self
635
     */
636
    public function resetELOs()
637
    {
638
        $this->getTeamA()->changeELO(-$this->elo_diff);
639
        $this->getTeamB()->changeELO(+$this->elo_diff);
640
    }
641
642
    /**
643
     * Calculate the match's contribution to the team activity
644
     *
645
     * @return float
646
     */
647 1
    public function getActivity()
648
    {
649 1
        $daysPassed = $this->getTimestamp()->diffInSeconds();
650 1
        $daysPassed = $daysPassed / TimeDate::SECONDS_PER_MINUTE / TimeDate::MINUTES_PER_HOUR / TimeDate::HOURS_PER_DAY;
651
652 1
        $activity = 0.0116687059537612 * (pow(45 - $daysPassed, (1 / 6)) + atan(31.0 - $daysPassed) / 2.0);
653
654 1
        if (is_nan($activity) || $activity < 0.0) {
655
            return 0.0;
656
        }
657
658 1
        return $activity;
659
    }
660
661
    /**
662
     * Enter a new match to the database
663
     * @param  int             $a          Team A's ID
664
     * @param  int             $b          Team B's ID
665
     * @param  int             $a_points   Team A's match points
666
     * @param  int             $b_points   Team B's match points
667
     * @param  int             $duration   The match duration in minutes
668
     * @param  int|null        $entered_by The ID of the player reporting the match
669
     * @param  string|DateTime $timestamp  When the match was played
670
     * @param  int[]           $a_players  The IDs of the first team's players
671
     * @param  int[]           $b_players  The IDs of the second team's players
672
     * @param  string|null     $server     The address of the server where the match was played
673
     * @param  int|null        $port       The port of the server where the match was played
674
     * @param  string          $replayFile The name of the replay file of the match
675
     * @param  int             $map        The ID of the map where the match was played, only for rotational leagues
676
     * @return Match           An object representing the match that was just entered
677
     */
678 9
    public static function enterMatch(
679
        $a, $b, $a_points, $b_points, $duration, $entered_by, $timestamp = "now",
680
        $a_players = array(), $b_players = array(), $server = null, $port = null,
681
        $replayFile = null, $map = null
682
    ) {
683 9
        $team_a = Team::get($a);
684 9
        $team_b = Team::get($b);
685 9
        $a_elo = $team_a->getElo();
686 9
        $b_elo = $team_b->getElo();
687
688 9
        $diff = self::calculateEloDiff($a_elo, $b_elo, $a_points, $b_points, $duration);
689
690
        // Update team ELOs
691 9
        $team_a->changeElo($diff);
692 9
        $team_b->changeElo(-$diff);
693
694 9
        $match = self::create(array(
695 9
            'team_a'         => $a,
696 9
            'team_b'         => $b,
697 9
            'team_a_points'  => $a_points,
698 9
            'team_b_points'  => $b_points,
699 9
            'team_a_players' => implode(',', $a_players),
700 9
            'team_b_players' => implode(',', $b_players),
701 9
            'team_a_elo_new' => $team_a->getElo(),
702 9
            'team_b_elo_new' => $team_b->getElo(),
703 9
            'elo_diff'       => $diff,
704 9
            'timestamp'      => TimeDate::from($timestamp)->toMysql(),
705 9
            'duration'       => $duration,
706 9
            'entered_by'     => $entered_by,
707 9
            'server'         => $server,
708 9
            'port'           => $port,
709 9
            'replay_file'    => $replayFile,
710 9
            'map'            => $map,
711 9
            'status'         => 'entered'
712 9
        ), 'updated');
713
714 9
        $match->updateMatchCount();
715
716 9
        return $match;
717
    }
718
719
    /**
720
     * Calculate the ELO score difference
721
     *
722
     * Computes the ELO score difference on each team after a match, based on
723
     * GU League's rules.
724
     *
725
     * @param  int $a_elo    Team A's current ELO score
726
     * @param  int $b_elo    Team B's current ELO score
727
     * @param  int $a_points Team A's match points
728
     * @param  int $b_points Team B's match points
729
     * @param  int $duration The match duration in minutes
730
     * @return int The ELO score difference
731
     */
732 9
    public static function calculateEloDiff($a_elo, $b_elo, $a_points, $b_points, $duration)
733
    {
734 9
        $prob = 1.0 / (1 + pow(10, (($b_elo - $a_elo) / 400.0)));
735 9
        if ($a_points > $b_points) {
736 5
            $diff = 50 * (1 - $prob);
737 5
        } elseif ($a_points == $b_points) {
738 4
            $diff = 50 * (0.5 - $prob);
739
        } else {
740 1
            $diff = 50 * (0 - $prob);
741
        }
742
743
        // Apply ELO modifiers from `config.yml`
744 9
        $durations = Service::getParameter('bzion.league.duration');
745 9
        $diff *= (isset($durations[$duration])) ? $durations[$duration] : 1;
746
747 9
        if (abs($diff) < 1 && $diff != 0) {
748
            // ELOs such as 0.75 should round up to 1...
749 2
            return ($diff > 0) ? 1 : -1;
750
        }
751
752
        // ...everything else is rounded down (-3.7 becomes -3 and 48.1 becomes 48)
753 7
        return intval($diff);
754
    }
755
756
    /**
757
     * Find if a match's stored ELO is correct
758
     */
759
    public function isEloCorrect()
760
    {
761
        return $this->elo_diff === $this->calculateEloDiff(
762
            $this->getTeamAEloOld(),
763
            $this->getTeamBEloOld(),
764
            $this->getTeamAPoints(),
765
            $this->getTeamBPoints(),
766
            $this->getDuration()
767
        );
768
    }
769
770
    /**
771
     * Recalculate the match's elo and adjust the team ELO values
772
     */
773
    public function recalculateElo()
774
    {
775
        $a = $this->getTeamA();
776
        $b = $this->getTeamB();
777
778
        $elo = $this->calculateEloDiff(
779
            $a->getElo(),
780
            $b->getElo(),
781
            $this->getTeamAPoints(),
782
            $this->getTeamBPoints(),
783
            $this->getDuration()
784
        );
785
786
        $this->updateProperty($this->elo_diff, "elo_diff", $elo);
787
788
        $a->changeElo($elo);
789
        $b->changeElo(-$elo);
790
791
        $this->updateProperty($this->team_a_elo_new, "team_a_elo_new", $a->getElo());
792
        $this->updateProperty($this->team_b_elo_new, "team_b_elo_new", $b->getElo());
793
    }
794
795
    /**
796
     * Get all the matches in the database
797
     */
798 1
    public static function getMatches()
799
    {
800 1
        return self::getQueryBuilder()->active()->getModels();
801
    }
802
803
    /**
804
     * Get a query builder for matches
805
     * @return MatchQueryBuilder
806
     */
807 3
    public static function getQueryBuilder()
808
    {
809 3
        return new MatchQueryBuilder('Match', array(
810
            'columns' => array(
811
                'firstTeam'        => 'team_a',
812
                'secondTeam'       => 'team_b',
813
                'firstTeamPoints'  => 'team_a_points',
814
                'secondTeamPoints' => 'team_b_points',
815
                'time'             => 'timestamp',
816
                'status'           => 'status'
817 3
            ),
818
        ));
819
    }
820
821
    /**
822
     * {@inheritdoc}
823
     */
824
    public function delete()
825
    {
826
        $this->updateMatchCount(true);
827
828
        return parent::delete();
829
    }
830
831
    /**
832
     * {@inheritdoc}
833
     */
834 3
    public static function getActiveStatuses()
835
    {
836 3
        return array('entered');
837
    }
838
839
    /**
840
     * {@inheritdoc}
841
     */
842 1
    public function getName()
843
    {
844 1
        return sprintf("(+/- %d) %s [%d] vs [%d] %s",
845 1
            $this->getEloDiff(),
846 1
            $this->getWinner()->getName(),
847 1
            $this->getScore($this->getWinner()),
0 ignored issues
show
Bug introduced by
It seems like $this->getWinner() can be null; however, getScore() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
848 1
            $this->getScore($this->getLoser()),
0 ignored issues
show
Bug introduced by
It seems like $this->getLoser() can be null; however, getScore() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
849 1
            $this->getLoser()->getName()
850
        );
851
    }
852
853
    /**
854
     * Update the match count of the teams participating in the match
855
     *
856
     * @param bool $decrement Whether to decrement instead of incrementing the match count
857
     */
858 9
    private function updateMatchCount($decrement = false)
859
    {
860 9
        $diff = ($decrement) ? -1 : 1;
861
862 9
        if ($this->isDraw()) {
863 4
            $this->getTeamA()->changeMatchCount($diff, 'draw');
864 4
            $this->getTeamB()->changeMatchCount($diff, 'draw');
865
        } else {
866 6
            $this->getWinner()->changeMatchCount($diff, 'win');
867 6
            $this->getLoser()->changeMatchCount($diff, 'loss');
868
        }
869 9
    }
870
}
871