Completed
Push — feature/match-info-restructure ( cfa28e )
by Vladimir
15:22 queued 29s
created

MatchesTableRestructure::down()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 40
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 40
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 21
nc 2
nop 0
1
<?php
2
3
use Phinx\Migration\AbstractMigration;
4
5
class MatchesTableRestructure extends AbstractMigration
6
{
7
    //
8
    // This table will be used to store participation of players in matches. This is to take the place of a comma
9
    // separated column in the `matches` table for faster JOIN operations versus string operations.
10
    //
11
12
    public function up()
13
    {
14
        $playerParticipationTable = $this->table('match_participation', [
15
            'id' => false,
16
            'primary_key' => ['match_id', 'user_id']
17
        ]);
18
        $playerParticipationTable
19
            ->addColumn('match_id', 'integer', [
20
                'signed' => false,
21
                'limit' => 10,
22
                'null' => false,
23
                'comment' => 'The ID of the match this player participated in',
24
            ])
25
            ->addColumn('user_id', 'integer', [
26
                'signed' => false,
27
                'limit' => 10,
28
                'null' => false,
29
                'comment' => 'The ID of the player who participated in this match',
30
            ])
31
            ->addColumn('team_id', 'integer', [
32
                'signed' => false,
33
                'limit' => 10,
34
                'null' => true,
35
                'comment' => 'The ID of the team this player played for at the time of this match'
36
            ])
37
            ->addColumn('callsign', 'string', [
38
                'null' => true,
39
                'comment' => 'The callsign used by the player during this match.',
40
            ])
41
            ->addColumn('ip_address', 'string', [
42
                'limit' => 46,
43
                'null' => true,
44
                'comment' => 'The IP address used by the player in this match',
45
            ])
46
            // Integer operations in SQL are faster than strings; so for team loyalty, we can simplify it to 0 or 1
47
            ->addColumn('team_loyalty', 'integer', [
48
                'after' => 'callsign',
49
                'limit' => 1,
50
                'null' => false,
51
                'comment' => 'The team color this player played for: 0 will be for "TEAM A" and 1 will be for "TEAM B"'
52
            ])
53
            ->addForeignKey('match_id', 'matches', 'id', ['delete' => 'CASCADE'])
54
            ->addForeignKey('user_id', 'players', 'id', ['delete' => 'CASCADE'])
55
            ->addForeignKey('team_id', 'teams', 'id', ['delete' => 'SET_NULL'])
56
            ->create()
57
        ;
58
59
        $statement = $this->query("SELECT * FROM matches WHERE (team_a_players IS NOT NULL AND team_a_players != '') OR (team_b_players IS NOT NULL AND team_b_players != '')");
60
        $matches = $statement->fetchAll();
0 ignored issues
show
Bug introduced by
The method fetchAll cannot be called on $statement (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
61
        $insertData = [];
62
63
        foreach ($matches as $match)
64
        {
65
            $team_a_players = explode(',', $match['team_a_players']);
66
            $team_b_players = explode(',', $match['team_b_players']);
67
68
            $dataBuilder = function(array $playerIDs, $isTeamA) use (&$insertData, $match) {
69
                foreach ($playerIDs as $playerID) {
70
                    if (empty($playerID)) {
71
                        continue;
72
                    }
73
74
                    $workspace = [
75
                        'match_id' => $match['id'],
76
                        'user_id' => $playerID,
77
                        'team_loyalty' => (int)$isTeamA,
78
                    ];
79
80 View Code Duplication
                    if ($match['team_a'] !== null && $isTeamA) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
81
                        $workspace['team_id'] = $match['team_a'];
82
                    } elseif ($match['team_b'] !== null && !$isTeamA) {
83
                        $workspace['team_id'] = $match['team_b'];
84
                    }
85
86
                    $insertData[] = $workspace;
87
                }
88
            };
89
90
            $dataBuilder($team_a_players, true);
91
            $dataBuilder($team_b_players, false);
92
        }
93
94
        $playerParticipationTable->insert($insertData);
95
        $playerParticipationTable->saveData();
96
97
        $matchesTable = $this->table('matches');
98
        $matchesTable
99
            ->removeColumn('team_a_players')
100
            ->removeColumn('team_b_players')
101
            ->update()
102
        ;
103
    }
104
105
    public function down()
106
    {
107
        $matchesTable = $this->table('matches');
108
        $matchesTable
109
            ->addColumn('team_a_players', 'string', [
110
                'after' => 'team_b_points',
111
                'limit' => 256,
112
                'null' => true,
113
                'comment' => 'A comma-separated list of BZIDs of players who where on Team 1'
114
            ])
115
            ->addColumn('team_b_players', 'string', [
116
                'after' => 'team_a_players',
117
                'limit' => 256,
118
                'null' => true,
119
                'comment' => 'A comma-separated list of BZIDs of players who where on Team 2'
120
            ])
121
            ->update()
122
        ;
123
124
        $statement = $this->query('
125
            SELECT
126
              match_id, 
127
              GROUP_CONCAT(IF(team_loyalty, user_id, NULL)) AS team_a_players,
128
              GROUP_CONCAT(IF(team_loyalty, NULL, user_id)) AS team_b_players
129
            FROM
130
              match_participation
131
            GROUP BY
132
              match_id;
133
        ');
134
        $results = $statement->fetchAll();
0 ignored issues
show
Bug introduced by
The method fetchAll cannot be called on $statement (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
135
136
        foreach ($results as $result) {
137
            $this->execute(sprintf("
138
                UPDATE matches SET team_a_players = '%s', team_b_players = '%s' WHERE id = %d
139
            ", $result['team_a_players'], $result['team_b_players'], $result['match_id']));
140
        }
141
142
        $playerParticipationTable = $this->table('match_participation');
143
        $playerParticipationTable->drop();
144
    }
145
}
146