MEMBER   F
last analyzed

Complexity

Total Complexity 181

Size/Duplication

Total Lines 818
Duplicated Lines 0 %

Test Coverage

Coverage 68.42%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 499
dl 0
loc 818
rs 2
c 2
b 0
f 0
ccs 299
cts 437
cp 0.6842
wmc 181

39 Methods

Rating   Name   Duplication   Size   Complexity  
A postcode_to_person_id() 0 4 1
B constituency_to_person_id() 0 39 7
A set_users_mp() 0 9 5
A given_name() 0 2 1
A _previous_future_mps_query() 0 38 5
A entered_reason_text() 0 5 2
A entered_reason() 0 2 1
A member_id() 0 2 1
A party_text() 0 9 3
A left_reason_text() 0 16 4
A extra_info() 0 2 1
A houses() 0 2 1
A party() 0 2 1
A house() 0 2 2
A person_id() 0 2 1
A left_house() 0 9 3
A left_house_text() 0 12 6
A house_text() 0 2 1
A entered_house() 0 9 3
A houses_pretty() 0 9 1
A member_id_to_person_id() 0 18 3
A constituency() 0 2 1
A the_users_mp() 0 2 1
A left_reason() 0 2 1
A current_member() 0 10 4
A previous_mps() 0 2 1
A member_agreements() 0 12 2
A current_member_anywhere() 0 10 3
A date_in_memberships() 0 10 5
A full_name() 0 6 6
A future_mps() 0 2 1
A reasons() 0 19 1
B entered_house_text() 0 13 9
A family_name() 0 2 1
B isHigherPriorityHouse() 0 25 10
F __construct() 0 129 24
F load_extra_info() 0 114 21
B url() 0 42 9
F name_to_person_id() 0 105 28

How to fix   Complexity   

Complex Class

Complex classes like MEMBER often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MEMBER, and based on these observations, apply Extract Interface, too.

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
            'changed_name' 		=> gettext('Changed name'),
48 36
            'declared_void'		=> gettext('Declared void'),
49 36
            'died'			=> gettext('Died'),
50 36
            'disqualified'		=> gettext('Disqualified'),
51 36
            'general_election' 	=> gettext('General election'),
52 36
            'general_election_standing' 	=> [gettext('General election (standing again)'), gettext('General election (stood again)')],
53 36
            'general_election_not_standing' 	=> gettext('did not stand for re-election'),
54 36
            'reinstated'		=> gettext('Reinstated'),
55 36
            'resigned'		=> gettext('Resigned'),
56 36
            'recall_petition'   => gettext('Removed from office by a recall petition'),
57 36
            'still_in_office'	=> gettext('Still in office'),
58 36
            'dissolution'		=> gettext('Dissolved for election'),
59
            'regional_election'	=> gettext('Election'), # Scottish Parliament
60
            'replaced_in_region'	=> gettext('Appointed, regional replacement'),
61
        ];
62
    }
63
64
    private $db;
65
66
    /*
67
     * Is given house higher priority than current?
68
     *
69
     * Determine if the given house is a higher priority than the currently displayed one.
70
     *
71
     * @param int $house The number of the house to evaluate.
72
     *
73
     * @return boolean
74 36
     */
75
76
    private function isHigherPriorityHouse(int $house) {
77 36
        # The monarch always takes priority, so if the house is royal always say "yes"
78 1
        if ($house == HOUSE_TYPE_ROYAL) {
79
            return true;
80
        }
81
82 35
        # If the current house is *not* Lords, and the house to check is, Lords is next
83 2
        if ($this->house_disp != HOUSE_TYPE_LORDS && $house == HOUSE_TYPE_LORDS) {
84
            return true;
85
        }
86
87
        # All the following only happen if the house to display isn't yet set.
88 34
        # TODO: This relies on interpreting the default value of 0 as a false, which may be error-prone.
89 34
        if (! (bool) $this->house_disp) {
90 34
            if ($house == HOUSE_TYPE_LONDON_ASSEMBLY # London Assembly
91 32
                || $house == HOUSE_TYPE_SCOTLAND     # MSPs and
92 32
                || $house == HOUSE_TYPE_WALES        # MSs and
93 34
                || $house == HOUSE_TYPE_NI           # MLAs have lowest priority
94
                || $house == HOUSE_TYPE_COMMONS      # MPs
95 34
            ) {
96
                return true;
97
            }
98
        }
99 22
100
        return false;
101
    }
102 37
103
    public function __construct($args) {
104
        // $args is a hash like one of:
105
        // member_id 		=> 237
106
        // person_id 		=> 345
107
        // constituency 	=> 'Braintree'
108
        // postcode			=> 'e9 6dw'
109
110
        // If just a constituency we currently just get the current member for
111
        // that constituency.
112 37
113
        global $this_page;
114 37
115
        $house = $args['house'] ?? null;
116 37
117
        $this->db = new ParlDB();
118 37
119 37
        $person_id = '';
120 17
        if (isset($args['member_id']) && is_numeric($args['member_id'])) {
121 35
            $person_id = $this->member_id_to_person_id($args['member_id']);
122 3
        } elseif (isset($args['name'])) {
123 3
            $con = $args['constituency'] ?? '';
124 32
            $person_id = $this->name_to_person_id($args['name'], $con);
125 1
        } elseif (isset($args['constituency'])) {
126 1
            $still_in_office = $args['still_in_office'] ?? false;
127 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

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

636
        } 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

636
        } 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

636
        } elseif (checkdate($month, $day, /** @scrutinizer ignore-type */ $year) && $year != '9999') {
Loading history...
637
            return format_date($entered_house, LONGDATEFORMAT);
638
        } else {
639
            return "n/a";
640
        }
641
    }
642
643
    public function left_house($house = null) {
644
        if (isset($house)) {
645 1
            if (array_key_exists($house, $this->left_house)) {
646 1
                return $this->left_house[$house];
647 1
            } else {
648 1
                return null;
649 1
            }
650
        }
651 1
        return $this->left_house;
652 1
    }
653
654
    public function left_house_text($left_house) {
655
        if (!$left_house) {
656
            return '';
657
        }
658
        [$year, $month, $day] = explode('-', $left_house);
659 6
        if (checkdate($month, $day, $year) && $year != '9999') {
0 ignored issues
show
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

659
        if (checkdate($month, $day, /** @scrutinizer ignore-type */ $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

659
        if (checkdate($month, /** @scrutinizer ignore-type */ $day, $year) && $year != '9999') {
Loading history...
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

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