Completed
Push — fm-support ( 67f3c2...5f26cf )
by Vladimir
04:53
created

Match::getTeamBColor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
773 9
            $team_a = Team::get($a);
774 9
            $team_b = Team::get($b);
775 9
            $a_elo = $team_a->getElo();
776 9
            $b_elo = $team_b->getElo();
777
778 9
            $diff = self::calculateEloDiff($a_elo, $b_elo, $a_points, $b_points, $duration);
779
780
            // Update team ELOs
781 9
            $team_a->changeElo($diff);
782 9
            $team_b->changeElo(-$diff);
783
784 9
            $matchData = array_merge($matchData, array(
785 9
                'team_a'         => $a,
786 9
                'team_b'         => $b,
787 9
                'team_a_elo_new' => $team_a->getElo(),
788 9
                'team_b_elo_new' => $team_b->getElo(),
789 9
                'elo_diff'       => $diff
790
            ));
791 9
            $matchDataTypes .= 'iiiii';
792
        }
793
794 9
        $match = self::create($matchData, $matchDataTypes, 'updated');
795
796
        if ($matchType === Match::OFFICIAL) {
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
797
            $match->updateMatchCount();
798
        }
799
800
        return $match;
801
    }
802
803
    /**
804
     * Calculate the ELO score difference
805
     *
806
     * Computes the ELO score difference on each team after a match, based on
807
     * GU League's rules.
808
     *
809
     * @param  int $a_elo    Team A's current ELO score
810
     * @param  int $b_elo    Team B's current ELO score
811
     * @param  int $a_points Team A's match points
812
     * @param  int $b_points Team B's match points
813
     * @param  int $duration The match duration in minutes
814
     * @return int The ELO score difference
815
     */
816 9
    public static function calculateEloDiff($a_elo, $b_elo, $a_points, $b_points, $duration)
817
    {
818 9
        $prob = 1.0 / (1 + pow(10, (($b_elo - $a_elo) / 400.0)));
819 9
        if ($a_points > $b_points) {
820 5
            $diff = 50 * (1 - $prob);
821 4
        } elseif ($a_points == $b_points) {
822 3
            $diff = 50 * (0.5 - $prob);
823
        } else {
824 1
            $diff = 50 * (0 - $prob);
825
        }
826
827
        // Apply ELO modifiers from `config.yml`
828 9
        $durations = Service::getParameter('bzion.league.duration');
829 9
        $diff *= (isset($durations[$duration])) ? $durations[$duration] : 1;
830
831 9
        if (abs($diff) < 1 && $diff != 0) {
832
            // ELOs such as 0.75 should round up to 1...
833 2
            return ($diff > 0) ? 1 : -1;
834
        }
835
836
        // ...everything else is rounded down (-3.7 becomes -3 and 48.1 becomes 48)
837 7
        return intval($diff);
838
    }
839
840
    /**
841
     * Find if a match's stored ELO is correct
842
     */
843
    public function isEloCorrect()
844
    {
845
        return $this->elo_diff === $this->calculateEloDiff(
846
            $this->getTeamAEloOld(),
847
            $this->getTeamBEloOld(),
848
            $this->getTeamAPoints(),
849
            $this->getTeamBPoints(),
850
            $this->getDuration()
851
        );
852
    }
853
854
    /**
855
     * Recalculate the match's elo and adjust the team ELO values
856
     */
857
    public function recalculateElo()
858
    {
859
        $a = $this->getTeamA();
860
        $b = $this->getTeamB();
861
862
        $elo = $this->calculateEloDiff(
863
            $a->getElo(),
864
            $b->getElo(),
865
            $this->getTeamAPoints(),
866
            $this->getTeamBPoints(),
867
            $this->getDuration()
868
        );
869
870
        $this->updateProperty($this->elo_diff, "elo_diff", $elo, "i");
871
872
        $a->changeElo($elo);
873
        $b->changeElo(-$elo);
874
875
        $this->updateProperty($this->team_a_elo_new, "team_a_elo_new", $a->getElo(), "i");
876
        $this->updateProperty($this->team_b_elo_new, "team_b_elo_new", $b->getElo(), "i");
877
    }
878
879
    /**
880
     * Get all the matches in the database
881
     */
882 1
    public static function getMatches()
883
    {
884 1
        return self::getQueryBuilder()->active()->getModels();
885
    }
886
887
    /**
888
     * Get a query builder for matches
889
     * @return MatchQueryBuilder
890
     */
891 2
    public static function getQueryBuilder()
892
    {
893 2
        return new MatchQueryBuilder('Match', array(
894
            'columns' => array(
895
                'firstTeam'        => 'team_a',
896
                'secondTeam'       => 'team_b',
897
                'firstTeamPoints'  => 'team_a_points',
898
                'secondTeamPoints' => 'team_b_points',
899
                'time'             => 'timestamp',
900
                'status'           => 'status'
901 2
            ),
902
        ));
903
    }
904
905
    /**
906
     * {@inheritdoc}
907
     */
908
    public function delete()
909
    {
910
        $this->updateMatchCount(true);
911
912
        return parent::delete();
913
    }
914
915
    /**
916
     * {@inheritdoc}
917
     */
918 2
    public static function getActiveStatuses()
919
    {
920 2
        return array('entered');
921
    }
922
923
    /**
924
     * {@inheritdoc}
925
     */
926
    public function getName()
927
    {
928
        return sprintf("(+/- %d) %s [%d] vs [%d] %s",
929
            $this->getEloDiff(),
930
            $this->getWinner()->getName(),
931
            $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...
932
            $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...
933
            $this->getLoser()->getName()
934
        );
935
    }
936
937
    /**
938
     * Update the match count of the teams participating in the match
939
     *
940
     * @param bool $decrement Whether to decrement instead of incrementing the match count
941
     */
942
    private function updateMatchCount($decrement = false)
943
    {
944
        $diff = ($decrement) ? -1 : 1;
945
946
        if ($this->isDraw()) {
947
            $this->getTeamA()->changeMatchCount($diff, 'draw');
948
            $this->getTeamB()->changeMatchCount($diff, 'draw');
949
        } else {
950
            $this->getWinner()->changeMatchCount($diff, 'win');
951
            $this->getLoser()->changeMatchCount($diff, 'loss');
952
        }
953
    }
954
}
955