Failed Conditions
Branch master (215e8c)
by Johannes
04:26
created

Postcode::postcodeFetchFromMapit()   C

Complexity

Conditions 13
Paths 19

Size

Total Lines 59
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 0
Metric Value
cc 13
eloc 44
nc 19
nop 1
dl 0
loc 59
ccs 0
cts 44
cp 0
crap 182
rs 6.4268
c 0
b 0
f 0

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
namespace MySociety\TheyWorkForYou\Utility;
3
4
/**
5
 * Postcode Utilities
6
 *
7
 * Utility functions related to postcodes
8
 */
9
class Postcode
10
{
11
12
    /**
13
     * Postcode To Constituency
14
     */
15
16 2
    public static function postcodeToConstituency($postcode) {
17 2
        return self::postcodeToConstituenciesInternal($postcode, true);
18
    }
19
20
    /**
21
     * Postcode To Constituencies
22
     */
23
24 1
    public static function postcodeToConstituencies($postcode) {
25 1
        return self::postcodeToConstituenciesInternal($postcode, false);
26
    }
27
28
    /**
29
     * Postcode To Constituencies (Internal)
30
     *
31
     * @param boolean $mp_only
32
     */
33
34 3
    private static function postcodeToConstituenciesInternal($postcode, $mp_only) {
35 3
        global $last_postcode, $last_postcode_value;
36
37 3
        $postcode = preg_replace('#[^a-z0-9]#i', '', $postcode);
38 3
        $postcode = self::canonicalisePostcode($postcode);
39
40 3
        if ($last_postcode == $postcode) {
41 1
            $return_value = $mp_only ? $last_postcode_value['WMC'] : $last_postcode_value;
42 1
            twfy_debug ("TIME", "Postcode $postcode looked up last time, is " . ( is_array($return_value) ? implode(', ', $return_value) : $return_value ));
43 1
            return $return_value;
44
        }
45
46 3
        if (!validate_postcode($postcode)) {
47 1
            return '';
48
        }
49
50 2
        $ret = self::postcodeFetchFromDb($postcode);
51 2
        if (!$ret) {
52
            $ret = self::postcodeFetchFromMapit($postcode);
53
        }
54
55 2
        if (is_string($ret)) return $ret;
56
57 2
        $last_postcode = $postcode;
58 2
        $last_postcode_value = $ret;
59 2
        return $mp_only ? $ret['WMC'] : $ret;
60
    }
61
62
    /**
63
     * Fetch Postcode Information from DB
64
     *
65
     * @param string $postcode
66
     */
67
68 2
    private static function postcodeFetchFromDb($postcode) {
69 2
        $db = new \ParlDB;
70 2
        $q = $db->query('select name from postcode_lookup where postcode = :postcode', array(
71
            ':postcode' => $postcode
72 2
            ));
73
74 2
        if ($q->rows > 0) {
75 2
            $name = $q->field(0, 'name');
76 2
            if (self::postcodeIsScottish($postcode)) {
77 1
                $name = explode('|', $name);
78 1 View Code Duplication
                if (count($name)==3)
79 1
                    return array('WMC' => $name[0], 'SPC' => $name[1], 'SPE' => $name[2]);
80 2
            } elseif (self::postcodeIsNi($postcode)) {
81 1
                $name = explode('|', $name);
82 1 View Code Duplication
                if (count($name)==2)
83 1
                    return array('WMC' => $name[0], 'NIE' => $name[1]);
84
            } else {
85 1
                return array('WMC' => $name);
86
            }
87
        }
88
    }
89
90
    /**
91
     * Fetch Postcode Information from MapIt
92
     *
93
     * @param string $postcode
94
     */
95
96
    private static function postcodeFetchFromMapit($postcode) {
97
        if (!defined('OPTION_MAPIT_URL') || !OPTION_MAPIT_URL) {
98
            return '';
99
        }
100
        $filename = 'postcode/' . rawurlencode($postcode);
101
        $ch = curl_init(OPTION_MAPIT_URL . $filename);
102
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
103
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
104
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
105
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
106
        $file = curl_exec($ch);
107
        if (curl_errno($ch)) {
108
            $errno = curl_errno($ch);
109
            trigger_error("Postcode database: " . $errno . ' ' . curl_error($ch), E_USER_WARNING);
110
            return 'CONNECTION_TIMED_OUT';
111
        }
112
        curl_close($ch);
113
114
        $r = json_decode($file, true);
115
        if (!$r) {
116
            trigger_error("Postcode database is not working. Content:\n".$file.", request: ". $filename, E_USER_WARNING);
117
            return '';
118
        }
119
        if (isset($r['error']) || !isset($r['areas'])) {
120
            return '';
121
        }
122
        $areas = array();
123
        foreach ($r['areas'] as $row) {
124
            if (in_array($row['type'], array('WMC', 'SPC', 'SPE', 'NIE')))
125
                $areas[$row['type']] = utf8_decode($row['name']);
126
        }
127
128
        if (!isset($areas['WMC'])) {
129
            return '';
130
        }
131
132
        # Normalise name - assume SP and NI are already so...
133
        $normalised = Constituencies::normaliseConstituencyName(strtolower($areas['WMC']));
134
        if ($normalised) {
135
            $areas['WMC'] = $normalised;
136
            if (self::postcodeIsScottish($postcode)) {
137
                $serialized = "$areas[WMC]|$areas[SPC]|$areas[SPE]";
138
            } elseif (self::postcodeIsNi($postcode)) {
139
                $serialized = "$areas[WMC]|$areas[NIE]";
140
            } else {
141
                $serialized = $normalised;
142
            }
143
            $db = new \ParlDB;
144
            $db->query('replace into postcode_lookup values(:postcode, :serialized)',
145
                array(
146
                    ':postcode' => $postcode,
147
                    ':serialized' => $serialized
148
                ));
149
        } else {
150
            return '';
151
        }
152
153
        return $areas;
154
    }
155
156
    /**
157
     * Canonicalise Postcode
158
     *
159
     * Take a postcode and turn it into a tidied, uppercased canonical version.
160
     */
161
162 6
    public static function canonicalisePostcode($pc) {
163 6
        $pc = str_replace(' ', '', $pc);
164 6
        $pc = trim($pc);
165 6
        $pc = strtoupper($pc);
166 6
        $pc = preg_replace('#(\d[A-Z]{2})#', ' $1', $pc);
167 6
        return $pc;
168
    }
169
170
    /**
171
     * Is Postcode Scottish?
172
     */
173
174 3
    public static function postcodeIsScottish($pc) {
175 3
        if (!preg_match('#^([A-Z]{1,2})(\d+) (\d)([A-Z]{2})#', self::canonicalisePostcode($pc), $m))
176 3
            return false;
177
178
        # Check for Scottish postal areas
179 2
        if (in_array($m[1], array('AB', 'DD', 'EH', 'FK', 'G', 'HS', 'IV', 'KA', 'KW', 'KY', 'ML', 'PA', 'PH', 'ZE')))
180 2
            return true;
181
182 1
        if ($m[1]=='DG') {
183
            if ($m[2]==16 && $m[3]==5 && in_array($m[4], array('HT','HU','HZ','JA','JB'))) return false; # A few postcodes in England
184
            return true;
185
        }
186
187
        # Damn postcodes crossing country boundaries
188 1
        if ($m[1]=='TD') {
189
            if ($m[2]!=15 && $m[2]!=12 && $m[2]!=9) return true; # TD1-8, 10-11, 13-14 all in Scotland
190
            if ($m[2]==9) {
191
                if ($m[3]!=0) return true; # TD9 1-9 all in Scotland
192
                if (!in_array($m[4], array('TJ','TP','TR','TS','TT','TU','TW'))) return true; # Nearly all of TD9 0 in Scotland
193
            }
194
            $m[5] = substr($m[4], 0, 1);
195
            if ($m[2]==12) { # $m[3] will be 4 currently.
196
                if ($m[4]=='XE') return true;
197
                if (in_array($m[5], array('A','B','D','E','H','J','L','N','W','Y'))) return true; # These bits of TD12 4 are in Scotland, others (Q, R, S, T, U, X) in England
198
            }
199
            # TD15 is mostly England
200
            if ($m[2]==15) {
201
                if ($m[3]!=1) return false; # TD15 2 and 9 are in England
202
                if (in_array($m[4], array('BT','SU','SZ','UF','UG','UH','UJ','UL','US','UZ','WY','WZ'))) return true;
203
                if ($m[5]=='T' && $m[4]!='TA' && $m[4]!='TB') return true; # Most of TD15 1T* in Scotland
204
                if ($m[5]=='X' && $m[4]!='XX') return true; # TD15 1XX in England, rest of TD15 1X* in Scotland
205
            }
206
        }
207
208
        # Not in Scotland
209 1
        return false;
210
    }
211
212
    /**
213
     * Is Postcode Northern Irish?
214
     */
215
216 3
    public static function postcodeIsNi($pc) {
217 3
        $prefix = substr(self::canonicalisePostcode($pc), 0, 2);
218 3
        if ($prefix == 'BT')
219 3
            return true;
220 2
        return false;
221
    }
222
223
}
224
225