Completed
Push — feature/player-elo ( 2693b2...03d3b5 )
by Vladimir
04:10
created

PlayerEloCalculations::down()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
use Phinx\Migration\AbstractMigration;
4
5
class PlayerEloCalculations extends AbstractMigration
6
{
7
    /**
8
     * {@inheritdoc}
9
     */
10
    public function up()
11
    {
12
        $kernel = new AppKernel('prod', false);
13
        $kernel->boot();
14
        $qb = new MatchQueryBuilder('Match', [
15
            'columns' => [
16
                'team_a_players' => 'team_a_players',
17
                'team_b_players' => 'team_b_players',
18
                'timestamp' => 'timestamp',
19
            ],
20
        ]);
21
22
        $query = $qb
23
            ->where('team_a_players')->isNotNull()
24
            ->where('team_a_players')->notEquals('')
25
            ->where('team_b_players')->isNotNull()
26
            ->where('team_b_players')->notEquals('')
27
            ->sortBy('timestamp')
28
            ->limit(1000)
29
        ;
30
31
        $pageCount = $query->countPages();
32
        $lastSeason = [];
33
34
        for ($i = 1; $i <= $pageCount; $i++) {
35
            $matches = $query
36
                ->fromPage($i)
37
                ->getModels($fast = true)
38
            ;
39
40
            /** @var Match $match */
41
            foreach ($matches as $match) {
42
                $seasonInfo = Season::getSeason($match->getTimestamp());
43
44
                // Clear the model cache every season since Elos are cached internally
45
                if ($seasonInfo != $lastSeason) {
46
                    $lastSeason = $seasonInfo;
47
                    Service::getModelCache()->clear();
48
                }
49
50
                $teamA = $match->getTeamAPlayers();
51
                $teamB = $match->getTeamBPlayers();
52
53
                if (empty($teamA) || empty($teamB)) {
54
                    continue;
55
                }
56
57
                $getElo = function($n) use ($seasonInfo) {
58
                    /** @var Player $n */
59
                    return $n->getElo($seasonInfo['season'], $seasonInfo['year']);
60
                };
61
62
                $teamA_Avg = array_sum(array_map($getElo, $teamA)) / count($teamA);
63
                $teamB_Avg = array_sum(array_map($getElo, $teamB)) / count($teamB);
64
65
                $diff = Match::calculateEloDiff(
66
                    $teamA_Avg, $teamB_Avg, $match->getTeamAPoints(), $match->getTeamBPoints(), $match->getDuration()
67
                );
68
69
                // We need to disable transactions so our Player::adjustElo() fxn won't hold up execution
70
                $this->getAdapter()->commitTransaction();
71
72
                $this->query("UPDATE matches SET player_elo_diff = {$diff} WHERE id = {$match->getId()} LIMIT 1;");
73
74
                $walkFxn = function ($v, $k, $positive) use ($diff, $match, &$batch, $seasonInfo) {
75
                    /** @var Player $v */
76
77
                    $eloDiff = ($positive) ? $diff : -$diff;
78
79
                    if ($v->isValid()) {
80
                        $v->adjustElo($eloDiff, $match);
81
                    }
82
                };
83
84
                array_walk($teamA, $walkFxn, true);
85
                array_walk($teamB, $walkFxn, false);
86
87
                $this->getAdapter()->beginTransaction();
88
            }
89
        }
90
    }
91
92
    public function down()
93
    {
94
        $seasonElos = $this->table('player_elo');
95
        $seasonElos->truncate();
96
    }
97
}
98