MEMBER::isHigherPriorityHouse()   B
last analyzed

Complexity

Conditions 10
Paths 5

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 10

Importance

Changes 0
Metric Value
cc 10
eloc 12
nc 5
nop 1
dl 0
loc 25
rs 7.6666
c 0
b 0
f 0
ccs 12
cts 12
cp 1
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
include_once INCLUDESPATH . "easyparliament/glossary.php";
4
5
use MySociety\TheyWorkForYou\Policies as Policies;
6
7
class MEMBER {
8
    public $valid = false;
9
    public $member_id;
10
    public $person_id;
11
    public $title;
12
    public $given_name;
13
    public $family_name;
14
    public $lordofname;
15
    public $constituency;
16
    public $party;
17
    public $other_parties = [];
18
    public $other_constituencies;
19
    public $memberships = [];
20
    public $houses = [];
21
    public $entered_house = [];
22
    public $left_house = [];
23
    public $extra_info = [];
24
    // Is this MP THEUSERS's MP?
25
    public $the_users_mp = false;
26
    public $house_disp = 0; # Which house we should display this person in
27 1
28
    // Mapping member table 'house' numbers to text.
29 1
    private function houses_pretty() {
30 1
        return [
31 1
            0 => gettext('Royal Family'),
32 1
            1 => gettext('House of Commons'),
33 1
            2 => gettext('House of Lords'),
34 1
            3 => gettext('Northern Ireland Assembly'),
35 1
            4 => gettext('Scottish Parliament'),
36
            5 => gettext('Senedd'),
37
            6 => gettext('London Assembly'),
38
        ];
39
    }
40 36
41
    // Mapping member table reasons to text.
42 36
    private function reasons() {
43 36
        return [
44 36
            'became_peer'		=> gettext('Became peer'),
45 36
            'by_election'		=> gettext('Byelection'),
46 36
            'changed_party'		=> gettext('Changed party'),
47 36
            'whip_removed'      => gettext('Had whip removed'),
48 36
            'whip_restored'    => gettext('Had whip restored'),
49 36
            'changed_name' 		=> gettext('Changed name'),
50 36
            'declared_void'		=> gettext('Declared void'),
51 36
            'died'			=> gettext('Died'),
52 36
            'disqualified'		=> gettext('Disqualified'),
53 36
            'general_election' 	=> gettext('General election'),
54 36
            'general_election_standing' 	=> [gettext('General election (standing again)'), gettext('General election (stood again)')],
55 36
            'general_election_not_standing' 	=> gettext('did not stand for re-election'),
56 36
            'reinstated'		=> gettext('Reinstated'),
57 36
            'resigned'		=> gettext('Resigned'),
58 36
            'recall_petition'   => gettext('Removed from office by a recall petition'),
59
            'still_in_office'	=> gettext('Still in office'),
60
            'dissolution'		=> gettext('Dissolved for election'),
61
            'regional_election'	=> gettext('Election'), # Scottish Parliament
62
            'replaced_in_region'	=> gettext('Appointed, regional replacement'),
63
        ];
64
    }
65
66
    private $db;
67
68
    /*
69
     * Is given house higher priority than current?
70
     *
71
     * Determine if the given house is a higher priority than the currently displayed one.
72
     *
73
     * @param int $house The number of the house to evaluate.
74 36
     *
75
     * @return boolean
76
     */
77 36
78 1
    private function isHigherPriorityHouse(int $house) {
79
        # The monarch always takes priority, so if the house is royal always say "yes"
80
        if ($house == HOUSE_TYPE_ROYAL) {
81
            return true;
82 35
        }
83 2
84
        # If the current house is *not* Lords, and the house to check is, Lords is next
85
        if ($this->house_disp != HOUSE_TYPE_LORDS && $house == HOUSE_TYPE_LORDS) {
86
            return true;
87
        }
88 34
89 34
        # All the following only happen if the house to display isn't yet set.
90 34
        # TODO: This relies on interpreting the default value of 0 as a false, which may be error-prone.
91 32
        if (! (bool) $this->house_disp) {
92 32
            if ($house == HOUSE_TYPE_LONDON_ASSEMBLY # London Assembly
93 34
                || $house == HOUSE_TYPE_SCOTLAND     # MSPs and
94
                || $house == HOUSE_TYPE_WALES        # MSs and
95 34
                || $house == HOUSE_TYPE_NI           # MLAs have lowest priority
96
                || $house == HOUSE_TYPE_COMMONS      # MPs
97
            ) {
98
                return true;
99 22
            }
100
        }
101
102 37
        return false;
103
    }
104
105
    public function __construct($args) {
106
        // $args is a hash like one of:
107
        // member_id 		=> 237
108
        // person_id 		=> 345
109
        // constituency 	=> 'Braintree'
110
        // postcode			=> 'e9 6dw'
111
112 37
        // If just a constituency we currently just get the current member for
113
        // that constituency.
114 37
115
        global $this_page;
116 37
117
        $house = $args['house'] ?? null;
118 37
119 37
        $this->db = new ParlDB();
120 17
121 35
        $person_id = '';
122 3
        if (isset($args['member_id']) && is_numeric($args['member_id'])) {
123 3
            $person_id = $this->member_id_to_person_id($args['member_id']);
124 32
        } elseif (isset($args['name'])) {
125 1
            $con = $args['constituency'] ?? '';
126 1
            $person_id = $this->name_to_person_id($args['name'], $con);
127 31
        } elseif (isset($args['constituency'])) {
128
            $still_in_office = $args['still_in_office'] ?? false;
129 31
            $person_id = $this->constituency_to_person_id($args['constituency'], $house, $still_in_office);
0 ignored issues
show
Unused Code introduced by
The call to MEMBER::constituency_to_person_id() has too many arguments starting with $still_in_office. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

129
            /** @scrutinizer ignore-call */ 
130
            $person_id = $this->constituency_to_person_id($args['constituency'], $house, $still_in_office);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
130 31
        } elseif (isset($args['postcode'])) {
131 31
            $person_id = $this->postcode_to_person_id($args['postcode'], $house);
132
        } elseif (isset($args['person_id']) && is_numeric($args['person_id'])) {
133 31
            $person_id = $args['person_id'];
134 31
            $q = $this->db->query(
135 31
                "SELECT gid_to FROM gidredirect
136
                    WHERE gid_from = :gid_from",
137
                [':gid_from' => "uk.org.publicwhip/person/$person_id"]
138
            )->first();
139
            if ($q) {
140 36
                $person_id = str_replace('uk.org.publicwhip/person/', '', $q['gid_to']);
141
            }
142
        }
143
144
        if (!$person_id) {
145 36
            return;
146
        }
147
148
        // Find the memberships of this person, in reverse chronological order (latest first)
149
        $q = $this->db->query("SELECT member_id, house, title,
150
            given_name, family_name, lordofname, constituency, party, lastupdate,
151
            entered_house, left_house, entered_reason, left_reason, member.person_id
152 36
            FROM member, person_names pn
153
            WHERE member.person_id = :person_id
154
                AND member.person_id = pn.person_id AND pn.type = 'name' AND pn.start_date <= left_house AND left_house <= pn.end_date
155 36
            ORDER BY left_house DESC, house", [
156
            ':person_id' => $person_id,
157
        ]);
158
159 36
        if (!$q->rows() > 0) {
160
            return;
161 36
        }
162 36
163 36
        $this->valid = true;
164 36
165 36
        $this->house_disp = 0;
166 36
        $last_party = null;
167
        foreach ($q as $row) {
168 36
            $house = $row['house'];
169 36
            if (!in_array($house, $this->houses)) {
170 36
                $this->houses[] = $house;
171 36
            }
172 36
            # add the entire row into the memberships array
173 36
            $this->memberships[] = $row;
174
            $const = $row['constituency'] ? gettext($row['constituency']) : '';
175 36
            $party = $row['party'] ? gettext($row['party']) : '';
176 36
            $entered_house = $row['entered_house'];
177 36
            $left_house = $row['left_house'];
178 36
            $entered_reason = $row['entered_reason'];
179 36
            $left_reason = $row['left_reason'];
180 36
181
            if (!isset($this->entered_house[$house]) || $entered_house < $this->entered_house[$house]['date']) {
182
                $this->entered_house[$house] = [
183
                    'date' => $entered_house,
184 36
                    'date_pretty' => $this->entered_house_text($entered_house),
185 36
                    'reason' => $this->entered_reason_text($entered_reason),
186 36
                    'house' => $house,
187 36
                ];
188 36
            }
189 36
190 36
            if (!isset($this->left_house[$house])) {
191 36
                $this->left_house[$house] = [
192
                    'date' => $left_house,
193
                    'date_pretty' => $this->left_house_text($left_house),
194
                    'reason' => $this->left_reason_text($left_reason, $left_house, $house),
195 36
                    'constituency' => $const,
196 36
                    'party' => $this->party_text($party),
197 36
                    'house' => $house,
198 36
                ];
199
            }
200 36
201 36
            if ($this->isHigherPriorityHouse($house)) {
202 36
                $this->house_disp = $house;
203 36
                $this->constituency = $const;
204 36
                $this->party = $party;
205 36
206
                $this->member_id = $row['member_id'];
207
                $this->title = $row['title'];
208 36
                $this->given_name = $row['given_name'];
209 20
                $this->family_name = $row['family_name'];
210 20
                $this->lordofname = $row['lordofname'];
211 20
                $this->person_id = $row['person_id'];
212
            }
213
214 36
            if (($last_party && $party && $party != $last_party) || $left_reason == 'changed_party') {
215
                $this->other_parties[] = [
216 36
                    'from' => $this->party_text($party),
217 1
                    'date' => $left_house,
218
                ];
219
            }
220 36
            $last_party = $party;
221
222
            if ($const != $this->constituency) {
223
                $this->other_constituencies[$const] = true;
224
            }
225
        }
226
        $this->other_parties = array_reverse($this->other_parties);
227 36
228 36
        // Loads extra info from DB - you now have to call this from outside
229
        // when you need it, as some uses of MEMBER are lightweight (e.g.
230 17
        // in searchengine.php)
231 17
        // $this->load_extra_info();
232
233 17
        $this->set_users_mp();
234 17
    }
235 17
236
    public function date_in_memberships($house, $date) {
237
        // Given a date, see if they had any memberships during that time
238
        foreach ($this->memberships as $membership) {
239
            if ($membership['entered_house'] <= $date && $membership['left_house'] >= $date) {
240
                if ($membership['house'] == $house) {
241
                    return true;
242 17
                }
243 17
            }
244
        }
245
        return false;
246
    }
247
248
    public function member_agreements(int $policyID, int $house = HOUSE_TYPE_COMMONS, Policies $policiesList = null) {
249
        // agreements that a member has been present for on a specific policy.
250
        // Pass in a Policies object to avoid reloading the list of policies.
251
        // Ideally one that has been initalised without a specific policy id.
252
        if (!$policiesList) {
253
            $policiesList = new Policies($policyID);
254
        }
255 1
        $rel_agreements = $policiesList->all_policy_agreements[$policyID] ?? [];
256 1
        $rel_agreements = array_filter($rel_agreements, function ($agreement) use ($house) {
257
            return $this->date_in_memberships($house, $agreement['date']);
258
        });
259
        return $rel_agreements;
260 1
    }
261
262
    public function member_id_to_person_id($member_id) {
263
        $q = $this->db->query(
264 1
            "SELECT person_id FROM member
265 1
                    WHERE member_id = :member_id",
266
            [':member_id' => $member_id]
267
        )->first();
268
        if (!$q) {
269 1
            $q = $this->db->query(
270
                "SELECT person_id FROM gidredirect, member
271 1
                    WHERE gid_from = :gid_from AND
272 1
                        CONCAT('uk.org.publicwhip/member/', member_id) = gid_to",
273
                [':gid_from' => "uk.org.publicwhip/member/$member_id"]
274
            )->first();
275
        }
276 1
        if ($q) {
277
            return $q['person_id'];
278 1
        } else {
279
            throw new MySociety\TheyWorkForYou\MemberException('Sorry, there is no member with a member ID of "' . _htmlentities($member_id) . '".');
280 1
        }
281
    }
282 1
283
    public function postcode_to_person_id($postcode, $house = null) {
284
        twfy_debug('MP', "postcode_to_person_id converting postcode to person");
285
        $constituency = strtolower(MySociety\TheyWorkForYou\Utility\Postcode::postcodeToConstituency($postcode));
286
        return $this->constituency_to_person_id($constituency, $house);
287 1
    }
288
289 1
    public function constituency_to_person_id($constituency, $house = null) {
290 1
        if ($constituency == '') {
291
            throw new MySociety\TheyWorkForYou\MemberException('Sorry, no constituency was found.');
292
        }
293
294
        if ($constituency == 'Orkney ') {
295
            $constituency = 'Orkney & Shetland';
296 3
        }
297 3
298 3
        $normalised = MySociety\TheyWorkForYou\Utility\Constituencies::normaliseConstituencyName($constituency);
299
        if ($normalised) {
300
            $constituency = $normalised;
301
        }
302 3
303 3
        $params = [];
304 3
305
        $left = "left_reason = 'still_in_office'";
306
        if ($dissolution = MySociety\TheyWorkForYou\Dissolution::db()) {
307
            $left = "($left OR $dissolution[query])";
308
            $params = $dissolution['params'];
309
        }
310
        $query = "SELECT person_id FROM member
311
                WHERE constituency = :constituency
312
                AND $left";
313
314
        $params[':constituency'] = $constituency;
315
316
        if ($house) {
317
            $query .= ' AND house = :house';
318
            $params[':house'] = $house;
319 3
        }
320 3
        $query .= ' ORDER BY left_house DESC';
321 3
322 3
        $q = $this->db->query($query, $params)->first();
323
324 3
        if ($q) {
325
            return $q['person_id'];
326
        } else {
327 3
            throw new MySociety\TheyWorkForYou\MemberException('Sorry, there is no current member for the "' . _htmlentities(ucwords($constituency)) . '" constituency.');
328 3
        }
329 3
    }
330 3
331 3
    public function name_to_person_id($name, $const = '') {
332
        global $this_page;
333 3
        if ($name == '') {
334
            throw new MySociety\TheyWorkForYou\MemberException('Sorry, no name was found.');
335
        }
336
337
        $params = [];
338
        $q = "SELECT person_id FROM person_names WHERE type = 'name' ";
339
        if ($this_page == 'peer') {
340
            $success = preg_match('#^(.*?) (.*?) of (.*?)$#', $name, $m);
341
            if (!$success) {
342
                $success = preg_match('#^(.*?)() of (.*?)$#', $name, $m);
343
            }
344
            if (!$success) {
345
                $success = preg_match('#^(.*?) (.*?)()$#', $name, $m);
346
            }
347 3
            if (!$success) {
348 3
                throw new MySociety\TheyWorkForYou\MemberException('Sorry, that name was not recognised.');
349
            }
350 3
            $params[':title'] = $m[1];
351 2
            $params[':family_name'] = $m[2];
352
            $params[':lordofname'] = $m[3];
353
            $q .= "AND title = :title AND family_name = :family_name AND lordofname = :lordofname";
354
        } elseif ($this_page == 'msp' || $this_page == 'mla' || strstr($this_page, 'mp')) {
355 1
            $success = preg_match('#^(.*?) (.*?) (.*?)$#', $name, $m);
356 1
            if (!$success) {
357 1
                $success = preg_match('#^(.*?)() (.*)$#', $name, $m);
358 1
            }
359
            if (!$success) {
360 1
                throw new MySociety\TheyWorkForYou\MemberException('Sorry, that name was not recognised.');
361
            }
362 1
            $params[':given_name'] = $m[1];
363 1
            $params[':middle_name'] = $m[2];
364
            $params[':family_name'] = $m[3];
365 1
            $params[':first_and_middle_names'] = $m[1] . ' ' . $m[2];
366
            $params[':middle_and_last_names'] = $m[2] . ' ' . $m[3];
367 1
            # Note this works only because MySQL ignores trailing whitespace
368
            $q .= "AND (
369 1
                (given_name=:first_and_middle_names AND family_name=:family_name)
370
                OR (given_name=:given_name AND family_name=:middle_and_last_names)
371 1
                OR (title=:given_name AND given_name=:middle_name AND family_name=:family_name)
372
            )";
373 1
        } elseif ($this_page == 'royal') {
374
            twfy_debug('MP', $name);
375
            if (stripos($name, 'elizabeth') !== false) {
376 1
                $q .= "AND person_id=13935";
377
            } elseif (stripos($name, 'charles') !== false) {
378
                $q .= "AND person_id=26065";
379 1
            }
380 1
        }
381 1
382 1
        $q = $this->db->query($q, $params);
383
        if (!$q->rows()) {
384
            throw new MySociety\TheyWorkForYou\MemberException('Sorry, we could not find anyone with that name.');
385
        } elseif ($q->rows() == 1) {
386 1
            return $q->first()['person_id'];
387
        }
388 1
389 1
        # More than one person ID matching the given name
390 1
        $person_ids = [];
391 1
        foreach ($q as $row) {
392 1
            $pid = $row['person_id'];
393
            $person_ids[$pid] = 1;
394 1
        }
395
        $pids = array_keys($person_ids);
396
397
        $params = [];
398
        if ($this_page == 'peer') {
399
            $params[':house'] = HOUSE_TYPE_LORDS;
400
        } elseif ($this_page == 'msp') {
401
            $params[':house'] = HOUSE_TYPE_SCOTLAND;
402
        } elseif ($this_page == 'ms') {
403
            $params[':house'] = HOUSE_TYPE_WALES;
404 36
        } elseif ($this_page == 'mla') {
405
            $params[':house'] = HOUSE_TYPE_NI;
406 36
        } elseif ($this_page == 'royal') {
407 36
            $params[':house'] = HOUSE_TYPE_ROYAL;
408
        } elseif ($this_page == 'london-assembly-member') {
409
            $params[':house'] = HOUSE_TYPE_LONDON_ASSEMBLY;
410
        } else {
411
            $params[':house'] = HOUSE_TYPE_COMMONS;
412
        }
413
414
        $pids_str = join(',', $pids);
415 36
        $q = "SELECT person_id, min(constituency) AS constituency
416
            FROM member WHERE person_id IN ($pids_str) AND house = :house";
417
        if ($const) {
418
            $params[':constituency'] = $const;
419 1
            $q .= ' AND constituency=:constituency';
420 1
        }
421 1
        $q .= ' GROUP BY person_id';
422 1
423 1
        $q = $this->db->query($q, $params);
424
        if ($q->rows() > 1) {
425
            $person_ids = [];
426 1
            foreach ($q as $row) {
427
                $person_ids[$row['person_id']] = $row['constituency'];
428 1
            }
429 1
            throw new MySociety\TheyWorkForYou\MemberMultipleException($person_ids);
430 1
        } elseif ($q->rows() > 0) {
431
            return $q->first()['person_id'];
432
        } elseif ($const) {
433 1
            return $this->name_to_person_id($name);
434
        } else {
435
            throw new MySociety\TheyWorkForYou\MemberException('Sorry, there is no current member with that name.');
436 1
        }
437 1
    }
438 1
439
    public function set_users_mp() {
440
        // Is this MP THEUSER's MP?
441
        global $THEUSER;
442
        if (is_object($THEUSER) && $THEUSER->postcode_is_set() && $this->current_member(1)) {
443
            $pc = $THEUSER->postcode();
444 1
            twfy_debug('MP', "set_users_mp converting postcode to person");
445
            $constituency = strtolower(MySociety\TheyWorkForYou\Utility\Postcode::postcodeToConstituency($pc));
446
            if ($constituency == strtolower($this->constituency())) {
447 1
                $this->the_users_mp = true;
448 1
            }
449 1
        }
450
    }
451
452
    // Grabs extra information (e.g. external links) from the database
453
    # DISPLAY is whether it's to be displayed on MP page.
454
    public function load_extra_info($display = false, $force = false) {
455 1
        $memcache = new MySociety\TheyWorkForYou\Memcache();
456
        $memcache_key = 'extra_info:' . $this->person_id . ($display ? '' : ':plain');
457 1
        $this->extra_info = $memcache->get($memcache_key);
458
        if (!DEVSITE && !$force && $this->extra_info) {
459 1
            return;
460 1
        }
461 1
        $this->extra_info = [];
462
463
        $q = $this->db->query(
464
            'SELECT * FROM moffice WHERE person=:person_id ORDER BY from_date DESC, moffice_id',
465 1
            [':person_id' => $this->person_id]
466
        );
467
        $this->extra_info['office'] = $q->fetchAll();
468
469
        // Info specific to member id (e.g. attendance during that period of office)
470
        $q = $this->db->query(
471
            "SELECT data_key, data_value
472
                        FROM 	memberinfo
473
                        WHERE	member_id = :member_id",
474
            [':member_id' => $this->member_id]
475
        );
476
        foreach ($q as $row) {
477
            $this->extra_info[$row['data_key']] = $row['data_value'];
478
            #		if ($row['joint'] > 1)
479
            #			$this->extra_info[$row['data_key'].'_joint'] = true;
480
        }
481
482 1
        // Info specific to person id (e.g. their permanent page on the Guardian website)
483
        $q = $this->db->query(
484
            "SELECT data_key, data_value
485
                        FROM 	personinfo
486
                        WHERE	person_id = :person_id",
487 1
            [':person_id' => $this->person_id]
488
        );
489
        foreach ($q as $row) {
490
            $this->extra_info[$row['data_key']] = $row['data_value'];
491
            #	    if ($row['count'] > 1)
492
            #	    	$this->extra_info[$row['data_key'].'_joint'] = true;
493
        }
494
495
        // Info specific to constituency (e.g. election results page on Guardian website)
496 1
        if ($this->house(HOUSE_TYPE_COMMONS)) {
497 1
498
            $q = $this->db->query(
499
                "SELECT data_key, data_value FROM consinfo
500 1
            WHERE constituency = :constituency",
501
                [':constituency' => $this->constituency]
502
            );
503
            foreach ($q as $row) {
504
                $this->extra_info[$row['data_key']] = $row['data_value'];
505
            }
506
        }
507 1
508 1
        if (array_key_exists('public_whip_rebellions', $this->extra_info)) {
509 1
            $rebellions = $this->extra_info['public_whip_rebellions'];
510 1
            $rebel_desc = "<unknown>";
511 1
            if ($rebellions == 0) {
512 1
                $rebel_desc = "never";
513 1
            } elseif ($rebellions <= 1) {
514 1
                $rebel_desc = "hardly ever";
515 1
            } elseif ($rebellions <= 3) {
516 1
                $rebel_desc = "occasionally";
517 1
            } elseif ($rebellions <= 5) {
518 1
                $rebel_desc = "sometimes";
519
            } elseif ($rebellions > 5) {
520
                $rebel_desc = "quite often";
521
            }
522 1
            $this->extra_info['public_whip_rebel_description'] = $rebel_desc;
523 1
        }
524
525
        if ($this->house(HOUSE_TYPE_LORDS) && isset($this->extra_info['public_whip_division_attendance'])) {
526
            $this->extra_info['Lpublic_whip_division_attendance'] = $this->extra_info['public_whip_division_attendance'];
527
            unset($this->extra_info['public_whip_division_attendance']);
528
        }
529
530
        if ($display && array_key_exists('register_member_interests_html', $this->extra_info) && ($this->extra_info['register_member_interests_html'] != '')) {
531 6
            $args =  [
532 6
                "sort" => "regexp_replace",
533 6
            ];
534 4
            $GLOSSARY = new GLOSSARY($args);
535
            $this->extra_info['register_member_interests_html'] =
536 6
        $GLOSSARY->glossarise($this->extra_info['register_member_interests_html']);
537
        }
538
539
        $q = $this->db->query('select count(*) as c from alerts where criteria like "%speaker:' . $this->person_id . '%" and confirmed and not deleted')->first();
540
        $this->extra_info['number_of_alerts'] = $q['c'];
541 33
542 33
        # Public Bill Committees
543
        $q = $this->db->query(
544
            'select bill_id,
545
            min(session) AS session,
546
            min(title) AS title,
547
            sum(attending) as a, sum(chairman) as c
548
            from pbc_members, bills
549 36
            where bill_id = bills.id and person_id = :person_id
550 36
            group by bill_id order by session desc',
551 36
            [':person_id' => $this->person_id()]
552 8
        );
553
        $this->extra_info['pbc'] = [];
554 36
        foreach ($q as $row) {
555 7
            $bill_id = $row['bill_id'];
556
            $c = $this->db->query('select count(*) as c from hansard where major=6 and minor=:bill_id and htype=10', [':bill_id' => $bill_id])->first();
557 29
            $c = $c['c'];
558
            $title = $row['title'];
559
            $attending = $row['a'];
560
            $chairman = $row['c'];
561 2
            $this->extra_info['pbc'][$bill_id] = [
562 2
                'title' => $title, 'session' => $row['session'],
563 2
                'attending' => $attending, 'chairman' => ($chairman > 0), 'outof' => $c,
564 2
            ];
565
        }
566 1
567
        $memcache->set($memcache_key, $this->extra_info);
568
    }
569
570
    // Functions for accessing things about this Member.
571
572 36
    public function member_id() {
573 36
        return $this->member_id;
574
    }
575
    public function person_id() {
576 36
        return $this->person_id;
577 36
    }
578 1
    public function given_name() {
579 35
        return $this->given_name;
580
    }
581 35
    public function family_name() {
582 35
        return $this->family_name;
583
    }
584
    public function full_name($no_mp_title = false) {
585
        $title = $this->title;
586
        if ($no_mp_title && ($this->house_disp == HOUSE_TYPE_COMMONS || $this->house_disp == HOUSE_TYPE_NI || $this->house_disp == HOUSE_TYPE_SCOTLAND || $this->house_disp == HOUSE_TYPE_WALES)) {
587
            $title = '';
588 1
        }
589 1
        return member_full_name($this->house_disp, $title, $this->given_name, $this->family_name, $this->lordofname);
590 1
    }
591 1
    public function houses() {
592
        return $this->houses;
593 1
    }
594
    public function house($house) {
595
        return in_array($house, $this->houses) ? true : false;
596
    }
597
    public function house_text($house) {
598
        return $this->houses_pretty()[$house];
599 36
    }
600 36
    public function constituency() {
601
        return $this->constituency;
602
    }
603 36
    public function party() {
604 36
        return $this->party;
605 2
    }
606 34
    public function party_text($party = null) {
607
        global $parties;
608
        if (!$party) {
609
            $party = $this->party;
610 34
        }
611
        if (isset($parties[$party])) {
612
            return $parties[$party];
613
        } else {
614
            return $party;
615 36
        }
616 36
    }
617 34
618
    public function entered_house($house = null) {
619 2
        if (isset($house)) {
620
            if (array_key_exists($house, $this->entered_house)) {
621
                return $this->entered_house[$house];
622
            } else {
623
                return null;
624 36
            }
625 36
        }
626 36
        return $this->entered_house;
627 36
    }
628
629
    public function entered_house_text($entered_house) {
630
        if (!$entered_house) {
631
            return '';
632
        }
633
        [$year, $month, $day] = explode('-', $entered_house);
634
        if ($month == 1 && $day == 1 && $this->house(HOUSE_TYPE_LORDS)) {
635
            return $year;
636 36
        } elseif ($month == 0 && $day == 0) {
637
            return $year;
638
        } elseif (checkdate($month, $day, $year) && $year != '9999') {
0 ignored issues
show
Bug introduced by
$month of type string is incompatible with the type integer expected by parameter $month of checkdate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

638
        } elseif (checkdate(/** @scrutinizer ignore-type */ $month, $day, $year) && $year != '9999') {
Loading history...
Bug introduced by
$day of type string is incompatible with the type integer expected by parameter $day of checkdate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

638
        } elseif (checkdate($month, /** @scrutinizer ignore-type */ $day, $year) && $year != '9999') {
Loading history...
Bug introduced by
$year of type string is incompatible with the type integer expected by parameter $year of checkdate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

638
        } elseif (checkdate($month, $day, /** @scrutinizer ignore-type */ $year) && $year != '9999') {
Loading history...
639
            return format_date($entered_house, LONGDATEFORMAT);
640
        } else {
641
            return "n/a";
642
        }
643
    }
644
645 1
    public function left_house($house = null) {
646 1
        if (isset($house)) {
647 1
            if (array_key_exists($house, $this->left_house)) {
648 1
                return $this->left_house[$house];
649 1
            } else {
650
                return null;
651 1
            }
652 1
        }
653
        return $this->left_house;
654
    }
655
656
    public function left_house_text($left_house) {
657
        if (!$left_house) {
658
            return '';
659 6
        }
660 6
        [$year, $month, $day] = explode('-', $left_house);
661
        if (checkdate($month, $day, $year) && $year != '9999') {
0 ignored issues
show
Bug introduced by
$month of type string is incompatible with the type integer expected by parameter $month of checkdate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

661
        if (checkdate(/** @scrutinizer ignore-type */ $month, $day, $year) && $year != '9999') {
Loading history...
Bug introduced by
$day of type string is incompatible with the type integer expected by parameter $day of checkdate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

661
        if (checkdate($month, /** @scrutinizer ignore-type */ $day, $year) && $year != '9999') {
Loading history...
Bug introduced by
$year of type string is incompatible with the type integer expected by parameter $year of checkdate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

661
        if (checkdate($month, $day, /** @scrutinizer ignore-type */ $year) && $year != '9999') {
Loading history...
662
            return format_date($left_house, LONGDATEFORMAT);
663 6
        } elseif ($month == 0 && $day == 0) {
664 1
            # Left house date is stored as 1942-00-00 to mean "at some point in 1941"
665 1
            return $year - 1;
666
        } else {
667 5
            return "n/a";
668 1
        }
669 1
    }
670
671 4
    public function entered_reason() {
672 1
        return $this->entered_reason;
0 ignored issues
show
Bug introduced by
The property entered_reason does not exist on MEMBER. Did you mean entered_house?
Loading history...
673 1
    }
674
    public function entered_reason_text($entered_reason) {
675 3
        if (isset($this->reasons()[$entered_reason])) {
676
            return $this->reasons()[$entered_reason];
677
        } else {
678
            return $entered_reason;
679 3
        }
680
    }
681
682
    public function left_reason() {
683 3
        return $this->left_reason;
0 ignored issues
show
Bug Best Practice introduced by
The property left_reason does not exist on MEMBER. Did you maybe forget to declare it?
Loading history...
684 1
    }
685 1
    public function left_reason_text($left_reason, $left_house, $house) {
686
        if (isset($this->reasons()[$left_reason])) {
687
            $left_reason = $this->reasons()[$left_reason];
688 2
            if (is_array($left_reason)) {
689 2
                $q = $this->db->query("SELECT MAX(left_house) AS max FROM member WHERE house=$house")->first();
690
                $max = $q['max'];
691
                if ($max == $left_house) {
692 6
                    return $left_reason[0];
693 6
                } else {
694
                    return $left_reason[1];
695
                }
696
            } else {
697
                return $left_reason;
698
            }
699
        } else {
700 6
            return $left_reason;
701
        }
702
    }
703
704
    public function extra_info() {
705
        return $this->extra_info;
706
    }
707
708
    public function current_member($house = 0) {
709
        $current = [];
710
        foreach (array_keys($this->houses_pretty()) as $h) {
711
            $lh = $this->left_house($h);
712
            $current[$h] = ($lh && $lh['date'] == '9999-12-31');
713
        }
714
        if ($house) {
715
            return $current[$house];
716
        }
717
        return $current;
718
    }
719
720
    public function the_users_mp() {
721
        return $this->the_users_mp;
722
    }
723
724
    public function url($absolute = false) {
725
        $house = $this->house_disp;
726
727
        switch ($house) {
728
            case HOUSE_TYPE_LORDS:
729
                $URL = new \MySociety\TheyWorkForYou\Url('peer');
730
                break;
731
732
            case HOUSE_TYPE_NI:
733
                $URL = new \MySociety\TheyWorkForYou\Url('mla');
734
                break;
735
736
            case HOUSE_TYPE_SCOTLAND:
737
                $URL = new \MySociety\TheyWorkForYou\Url('msp');
738
                break;
739
740
            case HOUSE_TYPE_WALES:
741
                $URL = new \MySociety\TheyWorkForYou\Url('ms');
742
                break;
743
744
            case HOUSE_TYPE_LONDON_ASSEMBLY:
745
                $URL = new \MySociety\TheyWorkForYou\Url('london-assembly-member');
746
                break;
747
748
            case HOUSE_TYPE_ROYAL:
749
                $URL = new \MySociety\TheyWorkForYou\Url('royal');
750
                break;
751
752
            default:
753
                $URL = new \MySociety\TheyWorkForYou\Url('mp');
754
                break;
755
        }
756
757
        $member_url = make_member_url($this->full_name(true), $this->constituency(), $house, $this->person_id());
758
        if ($absolute) {
759
            $protocol = 'https://';
760
            if (DEVSITE) {
761
                $protocol = 'http://';
762
            }
763
            return $protocol . DOMAIN . $URL->generate('none') . $member_url;
764
        } else {
765
            return $URL->generate('none') . $member_url;
766
        }
767
    }
768
769
    private function _previous_future_mps_query($direction) {
770
        $entered_house = $this->entered_house(HOUSE_TYPE_COMMONS);
771
        if (is_null($entered_house)) {
772
            return '';
773
        }
774
        if ($direction == '>') {
775
            $order = '';
776
        } else {
777
            $order = 'DESC';
778
        }
779
        $q = $this->db->query(
780
            'SELECT *
781
            FROM member, person_names pn
782
            WHERE member.person_id = pn.person_id AND pn.type = "name"
783
                AND pn.start_date <= member.left_house AND member.left_house <= pn.end_date
784
                AND house = :house AND constituency = :cons
785
                AND member.person_id != :pid AND entered_house ' . $direction . ' :date ORDER BY entered_house ' . $order,
786
            [
787
                ':house' => HOUSE_TYPE_COMMONS,
788
                ':cons' => $this->constituency(),
789
                ':pid' => $this->person_id(),
790
                ':date' => $entered_house['date'],
791
            ]
792
        );
793
        $mships = [];
794
        $last_pid = null;
795
        foreach ($q as $row) {
796
            $pid = $row['person_id'];
797
            $name = $row['given_name'] . ' ' . $row['family_name'];
798
            if ($last_pid != $pid) {
799
                $mships[] = [
800
                    'href' => WEBPATH . 'mp/?pid=' . $pid,
801
                    'text' => $name,
802
                ];
803
                $last_pid = $pid;
804
            }
805
        }
806
        return $mships;
807
    }
808
809
    public function previous_mps() {
810
        return $this->_previous_future_mps_query('<');
811
    }
812
813
    public function future_mps() {
814
        return $this->_previous_future_mps_query('>');
815
    }
816
817
    public function current_member_anywhere() {
818
        $is_current = false;
819
        $current_memberships = $this->current_member();
820
        foreach ($current_memberships as $current_memberships) {
821
            if ($current_memberships === true) {
822
                $is_current = true;
823
            }
824
        }
825
826
        return $is_current;
827
    }
828
}
829