Search::searchByUsage()   F
last analyzed

Complexity

Conditions 25
Paths 578

Size

Total Lines 128
Code Lines 87

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 650

Importance

Changes 0
Metric Value
cc 25
eloc 87
nc 578
nop 2
dl 0
loc 128
rs 0.586
c 0
b 0
f 0
ccs 0
cts 88
cp 0
crap 650

How to fix   Long Method    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
namespace MySociety\TheyWorkForYou\Utility;
4
5
/**
6
 * Search Utilities
7
 *
8
* Utility functions related to search and search strings
9
 */
10
11
class Search {
12
    public static function searchByUsage($search, $house = 0) {
13
        $data = [];
14
        $SEARCHENGINE = new \SEARCHENGINE($search);
15
        $data['pagetitle'] = $SEARCHENGINE->query_description_short();
16
        $SEARCHENGINE = new \SEARCHENGINE($search . ' groupby:speech');
17
        $count = $SEARCHENGINE->run_count(0, 5000, 'date');
18
        if ($count <= 0) {
19
            $data['error'] = 'No results';
20
21
            return $data;
22
        }
23
        $SEARCHENGINE->run_search(0, 5000, 'date');
24
        $gids = $SEARCHENGINE->get_gids();
25
        if (count($gids) <= 0) {
26
            $data['error'] = 'No results';
27
28
            return $data;
29
        }
30
        if (count($gids) == 5000) {
31
            $data['limit_reached'] = true;
32
        }
33
34
        # Fetch all the speakers of the results, count them up and get min/max date usage
35
        $speaker_count = [];
36
        $gids = join('","', $gids);
37
        $db = new \ParlDB();
38
        $q = $db->query('SELECT person_id,hdate FROM hansard WHERE gid IN ("' . $gids . '")');
39
        foreach ($q as $row) {
40
            $person_id = $row['person_id'];
41
            $hdate = $row['hdate'];
42
            if (!isset($speaker_count[$person_id])) {
43
                $speaker_count[$person_id] = 0;
44
                $maxdate[$person_id] = '1001-01-01';
45
                $mindate[$person_id] = '9999-12-31';
46
            }
47
            $speaker_count[$person_id]++;
48
            if ($hdate < $mindate[$person_id]) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $mindate does not seem to be defined for all execution paths leading up to this point.
Loading history...
49
                $mindate[$person_id] = $hdate;
50
            }
51
            if ($hdate > $maxdate[$person_id]) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $maxdate does not seem to be defined for all execution paths leading up to this point.
Loading history...
52
                $maxdate[$person_id] = $hdate;
53
            }
54
        }
55
56
        # Fetch details of all the speakers
57
        $speakers = [];
58
        $pids = [];
59
        if (count($speaker_count)) {
60
            $person_ids = join(',', array_keys($speaker_count));
61
            $q = $db->query('SELECT member_id, member.person_id, title, given_name, family_name, lordofname,
62
                                constituency, house, party,
63
                                moffice_id, dept, position, from_date, to_date, left_house
64
                            FROM member LEFT JOIN moffice ON member.person_id = moffice.person
65
                                JOIN person_names pn ON member.person_id = pn.person_id AND pn.type="name" AND pn.start_date <= left_house AND left_house <= pn.end_date
66
                            WHERE member.person_id IN (' . $person_ids . ')
67
                            ' . ($house ? " AND house=$house" : '') . '
68
                            ORDER BY left_house DESC');
69
            foreach ($q as $row) {
70
                $mid = $row['member_id'];
71
                if (!isset($pids[$mid])) {
72
                    $title = $row['title'];
73
                    $first = $row['given_name'];
74
                    $last = $row['family_name'];
75
                    $lordofname = $row['lordofname'];
76
                    $house = $row['house'];
77
                    $party = $row['party'];
78
                    $full_name = ucfirst(member_full_name($house, $title, $first, $last, $lordofname));
79
                    $pid = $row['person_id'];
80
                    $pids[$mid] = $pid;
81
                    $speakers[$pid]['house'] = $house;
82
                    $speakers[$pid]['left'] = $row['left_house'];
83
                }
84
                $dept = $row['dept'];
85
                $posn = $row['position'];
86
                $moffice_id = $row['moffice_id'];
87
                if ($dept && $row['to_date'] == '9999-12-31') {
88
                    $speakers[$pid]['office'][$moffice_id] = prettify_office($posn, $dept);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pid does not seem to be defined for all execution paths leading up to this point.
Loading history...
89
                }
90
                if (!isset($speakers[$pid]['name'])) {
91
                    $speakers[$pid]['name'] = $full_name . ($house == 1 ? ' MP' : '');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $full_name does not seem to be defined for all execution paths leading up to this point.
Loading history...
92
                }
93
                if (!isset($speakers[$pid]['party']) && $party) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $party does not seem to be defined for all execution paths leading up to this point.
Loading history...
94
                    $speakers[$pid]['party'] = $party;
95
                }
96
            }
97
        }
98
        if (isset($speaker_count[0])) {
99
            $speakers[0] = ['party' => '', 'name' => 'Headings, procedural text, etc.', 'house' => 0, 'count' => 0];
100
        }
101
        $party_count = [];
102
        $ok = 0;
103
        foreach ($speakers as $pid => &$speaker) {
104
            $speaker['count'] = $speaker_count[$pid];
105
            $speaker['pmaxdate'] = $maxdate[$pid];
106
            $speaker['pmindate'] = $mindate[$pid];
107
            $ok = 1;
108
            if (isset($speaker['party'])) {
109
                if (!isset($party_count[$speaker['party']])) {
110
                    $party_count[$speaker['party']] = 0;
111
                }
112
                $party_count[$speaker['party']] += $count;
113
            }
114
        }
115
116
        uasort($speakers, function ($a, $b) {
117
118
            if ($a['count'] > $b['count']) {
119
                return -1;
120
            }
121
122
            if ($a['count'] < $b['count']) {
123
                return 1;
124
            }
125
126
            return 0;
127
128
        });
129
130
        arsort($party_count);
131
        if (!$ok) {
132
            $data['error'] = 'No results';
133
            return $data;
134
        }
135
136
        $data['party_count'] = $party_count;
137
        $data['speakers'] = $speakers;
138
139
        return $data;
140
    }
141
142
    /**
143
     * Return query result from looking for MPs
144
     */
145
146
    public static function searchMemberDbLookup($searchstring, $current_only = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $current_only is not used and could be removed. ( Ignorable by Annotation )

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

146
    public static function searchMemberDbLookup($searchstring, /** @scrutinizer ignore-unused */ $current_only = false) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
147 2
        if (!$searchstring) {
148 2
            return [];
149
        }
150
        $searchwords = explode(' ', $searchstring, 3);
151 2
        $params = [];
152 2
        if (count($searchwords) == 1) {
153 2
            $params[':like_0'] = '%' . $searchwords[0] . '%';
154 1
            $where = "given_name LIKE :like_0 OR family_name LIKE :like_0 OR lordofname LIKE :like_0";
155 1
        } elseif (count($searchwords) == 2) {
156 1
            // We don't do anything special if there are more than two search words.
157
            // And here we're assuming the user's put the names in the right order.
158
            $params[':like_0'] = '%' . $searchwords[0] . '%';
159 1
            $params[':like_1'] = '%' . $searchwords[1] . '%';
160 1
            $params[':like_0_and_1'] = '%' . $searchwords[0] . ' ' . $searchwords[1] . '%';
161 1
            $params[':like_0_and_1_hyphen'] = '%' . $searchwords[0] . '-' . $searchwords[1] . '%';
162 1
            $where = "(given_name LIKE :like_0 AND family_name LIKE :like_1)";
163 1
            $where .= " OR (given_name LIKE :like_1 AND family_name LIKE :like_0)";
164 1
            $where .= " OR (title LIKE :like_0 AND family_name LIKE :like_1)";
165 1
            $where .= " OR given_name LIKE :like_0_and_1 OR given_name LIKE :like_0_and_1_hyphen";
166 1
            $where .= " OR family_name LIKE :like_0_and_1 OR family_name LIKE :like_0_and_1_hyphen";
167 1
            $where .= " OR lordofname LIKE :like_0_and_1";
168 1
            if (strtolower($searchwords[0]) == 'nick') {
169 1
                $where .= " OR (given_name LIKE '%nicholas%' AND family_name LIKE :like_1)";
170 1
            }
171
        } else {
172
            $searchwords[2] = str_replace('of ', '', $searchwords[2]);
173
            $params[':like_0'] = '%' . $searchwords[0] . '%';
174
            $params[':like_1'] = '%' . $searchwords[1] . '%';
175
            $params[':like_2'] = '%' . $searchwords[2] . '%';
176
            $params[':like_0_and_1'] = '%' . $searchwords[0] . ' ' . $searchwords[1] . '%';
177
            $params[':like_1_and_2'] = '%' . $searchwords[1] . ' ' . $searchwords[2] . '%';
178
            $params[':like_1_and_2_hyphen'] = '%' . $searchwords[1] . '-' . $searchwords[2] . '%';
179
            $where = "(given_name LIKE :like_0_and_1 AND family_name LIKE :like_2)";
180
            $where .= " OR (given_name LIKE :like_0 AND family_name LIKE :like_1_and_2)";
181
            $where .= " OR (given_name LIKE :like_0 AND family_name LIKE :like_1_and_2_hyphen)";
182
            $where .= " OR (title LIKE :like_0 AND family_name LIKE :like_1_and_2)";
183
            $where .= " OR (title LIKE :like_0 AND family_name LIKE :like_1_and_2_hyphen)";
184
            $where .= " OR (title LIKE :like_0 AND given_name LIKE :like_1 AND family_name LIKE :like_2)";
185
            $where .= " OR (title LIKE :like_0 AND family_name LIKE :like_1 AND lordofname LIKE :like_2)";
186
        }
187
188
        $db = new \ParlDB();
189 2
        $q = $db->query("SELECT person_id FROM person_names WHERE type='name' AND ($where)", $params);
190 2
191
        # Check for redirects
192
        $pids = [];
193 2
        foreach ($q as $row) {
194 2
            $pid = $row['person_id'];
195 2
            $redirect = $db->query(
196 2
                "SELECT gid_to FROM gidredirect WHERE gid_from = :gid_from",
197 2
                [':gid_from' => "uk.org.publicwhip/person/$pid"]
198 2
            )->first();
199 2
            if ($redirect) {
200
                $pid = str_replace('uk.org.publicwhip/person/', '', $redirect['gid_to']);
201
            }
202 2
            $pids[] = $pid;
203
        }
204
205 2
        return array_unique($pids);
206
    }
207
208
    public static function searchMemberDbLookupWithNames($searchstring, $current_only = false) {
209
        $pids = self::searchMemberDbLookup($searchstring, $current_only);
210
211
        if (!count($pids)) {
212
            return $pids;
213
        }
214
215
        $pids_str = join(',', $pids);
216
217
        $where = '';
218
        if ($current_only) {
219
            $where = "AND left_house='9999-12-31'";
220
        }
221
222
        # This is not totally accurate (e.g. minimum entered date may be from a
223
        # different house, or similar), but should be good enough.
224
        $db = new \ParlDB();
225
        $q = $db->query("SELECT member.person_id,
226
                                title, given_name, family_name, lordofname,
227
                                constituency, party,
228
                                (SELECT MIN(entered_house) FROM member m WHERE m.person_id=member.person_id) min_entered_house,
229
                                left_house, house
230
                        FROM member, person_names pn
231
                        WHERE member.person_id IN ($pids_str) $where
232
                            AND member.person_id = pn.person_id AND pn.type = 'name'
233
                            AND pn.start_date <= member.left_house AND member.left_house <= pn.end_date
234
                            AND left_house = (SELECT MAX(left_house) FROM member m WHERE m.person_id=member.person_id)
235
                        GROUP BY person_id
236
                        ORDER BY family_name, lordofname, given_name, person_id");
237
238
        return $q->fetchAll();
239
    }
240
241
    /**
242
     * Search Constituencies
243
     *
244
     * Given a search term, find constituencies by name or postcode.
245
     *
246
     * @param string $searchterm The term to search for.
247
     *
248
     * @return array A list of the array of constituencies, then a boolean
249
     *               saying whether it was a postcode used.
250
     */
251
252 1
    public static function searchConstituenciesByQuery($searchterm) {
253 1
        if (validate_postcode($searchterm)) {
254
            // Looks like a postcode - can we find the constituency?
255
            $constituency = Postcode::postcodeToConstituency($searchterm);
256
            if ($constituency) {
257
                return [ [$constituency], true ];
258
            }
259
        }
260
261
        // No luck so far - let's see if they're searching for a constituency.
262 1
        $try = strtolower($searchterm);
263 1
        $query = "select distinct
264
                (select name from constituency where cons_id = o.cons_id and main_name) as name
265
            from constituency AS o where name like :try
266
            and from_date <= date(now()) and date(now()) <= to_date";
267 1
        $db = new \ParlDB();
268 1
        $q = $db->query($query, [':try' => '%' . $try . '%']);
269
270 1
        $constituencies = [];
271 1
        foreach ($q as $row) {
272 1
            $constituencies[] = $row['name'];
273
        }
274
275 1
        return [ $constituencies, false ];
276
    }
277
278
    /**
279
     * get list of names of speaker IDs from search string
280
     *
281
     * @param string      $searchstring       The search string with the speaker:NNN text
282
     *
283
     * @return array Array with the speaker id string as key and speaker name as value
284
     */
285
286
    public static function speakerNamesForIDs($searchstring) {
287
        $criteria = explode(' ', $searchstring);
288
        $speakers = [];
289
290
        foreach ($criteria as $c) {
291
            if (preg_match('#^speaker:(\d+)#', $c, $m)) {
292
                $MEMBER = new \MEMBER(['person_id' => $m[1]]);
293
                $speakers[$m[1]] = $MEMBER->full_name();
294
            }
295
        }
296
297
        return $speakers;
298
    }
299
300
    /**
301
     * replace speaker:NNNN with speaker:Name in search string
302
     *
303
     * @param string      $searchstring       The search string with the speaker:NNN text
304
     *
305
     * @return string The search string with replaced speaker IDs
306
     */
307
    public static function speakerIDsToNames($searchstring) {
308
        $speakers = self::speakerNamesForIDs($searchstring);
309
310
        foreach ($speakers as $id => $name) {
311
            $searchstring = str_replace('speaker:' . $id, "speaker:$name", $searchstring);
312
        }
313
314
        return $searchstring;
315
    }
316
}
317