Passed
Push — master ( 0643ea...01e983 )
by Struan
04:28
created

Party::fetchPolicyPositionsByMethod()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 2
dl 0
loc 19
rs 9.9
c 0
b 0
f 0
ccs 12
cts 12
cp 1
crap 4
1
<?php
2
/**
3
 * Party Class
4
 *
5
 * @package TheyWorkForYou
6
 */
7
8
namespace MySociety\TheyWorkForYou;
9
10
/**
11
 * Party
12
 */
13
14
class Party {
15
16
    public $name;
17
18
    private $db;
19
20 9
    public function __construct($name) {
21
        // treat Labour and Labour/Co-operative the same as that's how
22
        // people view them and it'll confuse the results otherwise
23 9
        if ( $name == 'Labour/Co-operative' ) {
24 3
            $name = 'Labour';
25
        }
26 9
        $this->name = $name;
27 9
        $this->db = new \ParlDB;
28 9
    }
29
30 1
    public function getCurrentMemberCount($house) {
31 1
        $member_count = $this->db->query(
32 1
            "SELECT count(*) as num_members
33
            FROM member
34
            WHERE
35
                party = :party
36
                AND house = :house
37
                AND entered_house <= :date
38
                AND left_house >= :date",
39
            array(
40 1
                ':party' => $this->name,
41 1
                ':house' => $house,
42 1
                ':date' => date('Y-m-d'),
43
            )
44 1
        )->first();
45 1
        if ($member_count) {
46 1
            $num_members = $member_count['num_members'];
47 1
            return $num_members;
48
        } else {
49
            return 0;
50
        }
51
    }
52
53 3
    public function getAllPolicyPositions($policies) {
54 3
        $positions = $this->fetchPolicyPositionsByMethod($policies, "policy_position");
55
56 3
        return $positions;
57
    }
58
59 3
    public function policy_position($policy_id) {
60 3
        $position = $this->db->query(
61 3
            "SELECT score, divisions, date_min, date_max
62
            FROM partypolicy
63
            WHERE
64
                party = :party
65
                AND house = 1
66
                AND policy_id = :policy_id",
67
            array(
68 3
                ':party' => $this->name,
69 3
                ':policy_id' => $policy_id
70
            )
71 3
        )->first();
72
73 3
        if ($position) {
74 2
            $position['position'] = score_to_strongly($position['score']);
75 2
            return $position;
76
        } else {
77 2
            return null;
78
        }
79
    }
80
81 2
    public function calculateAllPolicyPositions($policies) {
82 2
        $positions = $this->fetchPolicyPositionsByMethod($policies, "calculate_policy_position");
83
84 2
        return $positions;
85
    }
86
87 3
    public function calculate_policy_position($policy_id) {
88
89
        // This could be done as a join but it turns out to be
90
        // much slower to do that
91 3
        $divisions = $this->db->query(
92 3
            "SELECT division_id, division_date, policy_vote
93
            FROM policydivisions
94
                JOIN divisions USING(division_id)
95
            WHERE policy_id = :policy_id
96
            AND house = 'commons'",
97
            array(
98 3
                ':policy_id' => $policy_id
99
            )
100
        );
101
102 3
        $score = 0;
103 3
        $max_score = 0;
104 3
        $total_votes = 0;
105 3
        $date_min = '';
106 3
        $date_max = '';
107 3
        $num_divisions = 0;
108
109 3
        $party_where = 'party = :party';
110
        $params = array(
111 3
            ':party' => $this->name
112
        );
113
114 3
        if ( $this->name == 'Labour' ) {
115 2
            $party_where = '( party = :party OR party = :party2 )';
116
            $params = array(
117 2
                ':party' => $this->name,
118 2
                ':party2' => 'Labour/Co-operative'
119
            );
120
        }
121
122 3
        foreach ($divisions as $division) {
123 3
            $division_id = $division['division_id'];
124 3
            $weights = $this->get_vote_scores($division['policy_vote']);
125 3
            $date = $division['division_date'];
126
127 3
            $params[':division_id'] = $division_id;
128
129 3
            $votes = $this->db->query(
130
                "SELECT count(*) as num_votes, vote
131
                FROM persondivisionvotes
132
                JOIN member ON persondivisionvotes.person_id = member.person_id
133
                WHERE
134 3
                    $party_where
135
                    AND member.house = 1
136
                    AND division_id = :division_id
137
                    AND left_house = '9999-12-31'
138
                GROUP BY vote",
139 3
                $params
140
            );
141
142 3
            $num_votes = 0;
143 3
            foreach ($votes as $vote) {
144 3
                $vote_dir = $vote['vote'];
145 3
                if ( $vote_dir == '' ) continue;
146 3
                if ( $vote_dir == 'tellno' ) $vote_dir = 'no';
147 3
                if ( $vote_dir == 'tellaye' ) $vote_dir = 'aye';
148
149 3
                $num_votes += $vote['num_votes'];
150 3
                $score += ($vote['num_votes'] * $weights[$vote_dir]);
151
            }
152
            # For range, only care if there were results
153 3
            if ($votes->rows()) {
154 3
                if (!$date_min || $date_min > $date) $date_min = $date;
155 3
                if (!$date_max || $date_max < $date) $date_max = $date;
156 3
                $num_divisions++;
157
            }
158
159 3
            $total_votes += $num_votes;
160 3
            $max_score += $num_votes * max( array_values( $weights ) );
161
        }
162
163 3
        if ( $total_votes == 0 ) {
0 ignored issues
show
introduced by
The condition $total_votes == 0 is always true.
Loading history...
164 2
            return null;
165
        }
166
167
        // this implies that all the divisions in the policy have a policy
168
        // position of absent so we set weight to -1 to indicate we can't
169
        // really say what the parties position is.
170 3
        if ( $max_score == 0 ) {
171 1
            $weight = -1;
172
        } else {
173 2
            $weight = 1 - ( $score/$max_score );
174
        }
175 3
        $score_desc = score_to_strongly($weight);
176
177
        return [
178 3
            'score' => $weight,
179 3
            'position' => $score_desc,
180 3
            'divisions' => $num_divisions,
181 3
            'date_min' => $date_min,
182 3
            'date_max' => $date_max,
183
        ];
184
    }
185
186 1
    public function cache_position( $position ) {
187 1
        $this->db->query(
188 1
            "REPLACE INTO partypolicy
189
                (party, house, policy_id, score, divisions, date_min, date_max)
190
                VALUES (:party, 1, :policy_id, :score, :divisions, :date_min, :date_max)",
191
            array(
192 1
                ':score' => $position['score'],
193 1
                ':party' => $this->name,
194 1
                ':policy_id' => $position['policy_id'],
195 1
                ':divisions' => $position['divisions'],
196 1
                ':date_min' => $position['date_min'],
197 1
                ':date_max' => $position['date_max'],
198
            )
199
        );
200 1
    }
201
202 5
    private function fetchPolicyPositionsByMethod($policies, $method) {
203 5
        $positions = array();
204
205 5
        if ($this->name == 'Independent') {
206 1
            return $positions;
207
        }
208
209 4
        foreach ( $policies->getPolicies() as $policy_id => $policy_text ) {
210 4
            $data = $this->$method($policy_id);
211 4
            if ( $data === null ) {
212 4
                continue;
213
            }
214
215 3
            $data['policy_id'] = $policy_id;
216 3
            $data['desc'] = $policy_text;
217 3
            $positions[$policy_id] = $data;
218
        }
219
220 4
        return $positions;
221
    }
222
223 3
    private function get_vote_scores($vote) {
224 3
        $absent = 1;
225 3
        $both = 1;
226 3
        $agree = 10;
227
228 3
        if ( stripos($vote, '3') !== FALSE ) {
229
            $agree = 50;
230
            $absent = 25;
231
            $both = 25;
232
        }
233
234
        $scores = array(
235 3
            'absent' => $absent,
236 3
            'both' => $both
237
        );
238
239 3
        if ( stripos($vote, 'aye') !== FALSE ) {
240 2
            $scores['aye'] = $agree;
241 2
            $scores['no'] = 0;
242 1
        } else if ( stripos($vote, 'no') !== FALSE ) {
243
            $scores['no'] = $agree;
244
            $scores['aye'] = 0;
245
        } else {
246 1
            $scores['both'] = 0;
247 1
            $scores['absent'] = 0;
248 1
            $scores['no'] = 0;
249 1
            $scores['aye'] = 0;
250
        }
251
252 3
        return $scores;
253
    }
254
255 1
    public static function getParties() {
256 1
        $db = new \ParlDB;
257
258 1
        $party_list = $db->query(
259 1
            "SELECT DISTINCT party FROM member WHERE party <> ''"
260
        );
261
262 1
        $parties = array();
263 1
        foreach ($party_list as $row) {
264 1
            $party = $row['party'];
265
            if (
266 1
                !$party
267 1
                || $party == 'Independent'
268 1
                || $party == 'Crossbench'
269
            ) {
270 1
                continue;
271
            }
272 1
            $parties[] = $party;
273
        }
274
275 1
        return $parties;
276
    }
277
}
278