Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
AddressValues
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
7 / 7
12
100.00% covered (success)
100.00%
1 / 1
 getCommonRouteTypes
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getRouteTypes
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 getDirections
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getStates
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStateCodes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStateNames
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUnitTypes
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Parser\Address;
16
17/**
18 * Address values class
19 *
20 * @author     Mark Maher
21 * @copyright  Copyright (c) 2021
22 * @version    2.0.0
23 */
24class AddressValues
25{
26    /**
27     * A list of common route type designators provided by USPS
28     * @var array $commonRouteTypes
29     * */
30    protected static array $commonRouteTypes = [
31        "avenue", "boulevard", "circle", "drive", "highway", "lane", "park", "park drive", "park dr", "parkway drive",
32        "parkway dr", "parkway", "place", "place drive", "place dr", "road", "route", "square", "street", "terrace",
33        "trace", "ave", "av", "blvd", "boul", "cir", "dr", "hwy", "ln ", "pk", "pky", "pl", "rd", "rte", "sq", "st",
34        "terr", "trce",
35    ];
36
37    /**
38     * A list of route type designators provided by USPS
39     * @var array $routeTypes
40     * */
41    protected static array $routeTypes = [
42        "allee" => "aly","alley" => "aly","ally" => "aly","aly" => "aly","anex" => "anx","annex" => "anx",
43        "annx" => "anx","anx" => "anx","arc" => "arc","arcade" => "arc","bayoo" => "byu",
44        "bayou" => "byu","bch" => "bch","beach" => "bch","bend" => "bnd","bg" => "bg","bgs" => "bgs","blf" => "blf",
45        "blfs" => "blfs","bluf" => "blf","bluff" => "blf","bluffs" => "blfs","blvd" => "blvd","bnd" => "bnd",
46        "bot" => "btm","bottm" => "btm","bottom" => "btm",
47        "br" => "br","branch" => "br","brdge" => "brg","brg" => "brg","bridge" => "brg","brk" => "brk","brks" => "brks",
48        "brnch" => "br","brook" => "brk","brooks" => "brks","btm" => "btm","burg" => "bg","burgs" => "bgs",
49        "byp" => "byp","bypa" => "byp","bypas" => "byp","bypass" => "byp","byps" => "byp","byu" => "byu",
50        "camp" => "cp","canyn" => "cyn","canyon" => "cyn","cape" => "cpe","causeway" => "cswy","causway" => "cswy",
51        "cen" => "ctr","cent" => "ctr","center" => "ctr","centers" => "ctrs","centr" => "ctr","centre" => "ctr",
52        "ck" => "crk","clb" => "clb","clf" => "clf","clfs" => "clfs","cliff" => "clf","cliffs" => "clfs",
53        "club" => "clb","cmn" => "cmn","cmp" => "cp","cnter" => "ctr","cntr" => "ctr","cnyn" => "cyn",
54        "common" => "cmn","cor" => "cor","corner" => "cor","corners" => "cors","cors" => "cors","course" => "crse",
55        "court" => "ct","courts" => "cts","cove" => "cv","coves" => "cvs","cp" => "cp","cpe" => "cpe","cr" => "crk",
56        "crcl" => "cir","crcle" => "cir","crecent" => "cres","creek" => "crk","cres" => "cres","crescent" => "cres",
57        "cresent" => "cres","crest" => "crst","crk" => "crk","crossing" => "xing","crossroad" => "xrd",
58        "crscnt" => "cres","crse" => "crse","crsent" => "cres","crsnt" => "cres","crssing" => "xing","crssng" => "xing",
59        "crst" => "crst","crt" => "ct","cswy" => "cswy","ct" => "ct","ctr" => "ctr","ctrs" => "ctrs","cts" => "cts",
60        "curv" => "curv","curve" => "curv","cv" => "cv","cvs" => "cvs","cyn" => "cyn","dale" => "dl","dam" => "dm",
61        "div" => "dv","divide" => "dv","dl" => "dl","dm" => "dm","dv" => "dv","dvd" => "dv","est" => "est","estate" => "est",
62        "estates" => "ests","ests" => "ests","exp" => "expy","expr" => "expy","express" => "expy","expressway" => "expy",
63        "expw" => "expy","expy" => "expy","ext" => "ext","extension" => "ext","extensions" => "exts","extn" => "ext",
64        "extnsn" => "ext","exts" => "exts","falls" => "fls","ferry" => "fry","field" => "fld","fields" => "flds",
65        "flat" => "flt","flats" => "flts","fld" => "fld","flds" => "flds","fls" => "fls","flt" => "flt","flts" => "flts",
66        "ford" => "frd","fords" => "frds","forest" => "frst","forests" => "frst","forg" => "frg","forge" => "frg",
67        "forges" => "frgs","fork" => "frk","forks" => "frks","fort" => "ft","frd" => "frd","frds" => "frds",
68        "freeway" => "fwy","freewy" => "fwy","frg" => "frg","frgs" => "frgs","frk" => "frk","frks" => "frks",
69        "frry" => "fry","frst" => "frst","frt" => "ft","frway" => "fwy","frwy" => "fwy","fry" => "fry","ft" => "ft",
70        "fwy" => "fwy","garden" => "gdn","gardens" => "gdns","gardn" => "gdn","gateway" => "gtwy","gatewy" => "gtwy",
71        "gatway" => "gtwy","gdn" => "gdn","gdns" => "gdns","glen" => "gln","glens" => "glns","gln" => "gln",
72        "glns" => "glns","grden" => "gdn","grdn" => "gdn","grdns" => "gdns","green" => "grn","greens" => "grns",
73        "grn" => "grn","grns" => "grns","grov" => "grv","grove" => "grv","groves" => "grvs","grv" => "grv",
74        "grvs" => "grvs","gtway" => "gtwy","gtwy" => "gtwy","harb" => "hbr","harbor" => "hbr","harbors" => "hbrs",
75        "harbr" => "hbr","haven" => "hvn","havn" => "hvn","hbr" => "hbr","hbrs" => "hbrs","height" => "hts",
76        "heights" => "hts","hgts" => "hts","hill" => "hl","hills" => "hls",
77        "hiway" => "hwy","hiwy" => "hwy","hl" => "hl","hls" => "hls","hllw" => "holw","hollow" => "holw",
78        "hollows" => "holw","holw" => "holw","holws" => "holw","hrbor" => "hbr","ht" => "hts","hts" => "hts",
79        "hvn" => "hvn","hway" => "hwy","hwy" => "hwy","inlet" => "inlt","inlt" => "inlt","is" => "is","island" => "is",
80        "islands" => "iss","isle" => "isle","isles" => "isle","islnd" => "is","islnds" => "iss","iss" => "iss",
81        "jct" => "jct","jction" => "jct","jctn" => "jct","jctns" => "jcts","jcts" => "jcts","junction" => "jct",
82        "junctions" => "jcts","junctn" => "jct","juncton" => "jct","key" => "ky","keys" => "kys","knl" => "knl",
83        "knls" => "knls","knol" => "knl","knoll" => "knl","knolls" => "knls","ky" => "ky","kys" => "kys","la" => "ln",
84        "lake" => "lk","lakes" => "lks","landing" => "lndg","lck" => "lck",
85        "lcks" => "lcks","ldg" => "ldg","ldge" => "ldg","lf" => "lf","lgt" => "lgt","lgts" => "lgts","light" => "lgt",
86        "lights" => "lgts","lk" => "lk","lks" => "lks","ln" => "ln","lndg" => "lndg","lndng" => "lndg","loaf" => "lf",
87        "lock" => "lck","locks" => "lcks","lodg" => "ldg","lodge" => "ldg","loop" => "loop","loops" => "loop","manor" => "mnr",
88        "manors" => "mnrs","mdw" => "mdw","mdws" => "mdws","meadow" => "mdw","meadows" => "mdws","medows" => "mdws",
89        "mill" => "ml","mills" => "mls","mission" => "msn","missn" => "msn","ml" => "ml","mls" => "mls","mnr" => "mnr",
90        "mnrs" => "mnrs","mnt" => "mt","mntain" => "mtn","mntn" => "mtn","mntns" => "mtns","motorway" => "mtwy",
91        "mount" => "mt","mountain" => "mtn","mountains" => "mtns","mountin" => "mtn","msn" => "msn","mssn" => "msn",
92        "mt" => "mt","mtin" => "mtn","mtn" => "mtn","mtns" => "mtns","mtwy" => "mtwy","nck" => "nck","neck" => "nck",
93        "opas" => "opas","orch" => "orch","orchard" => "orch","orchrd" => "orch","oval" => "oval","overpass" => "opas",
94        "ovl" => "oval",
95        "pass" => "pass","passage" => "psge","path" => "path","paths" => "path","pike" => "pike","pikes" => "pike",
96        "pine" => "pne","pines" => "pnes","pk" => "park","plain" => "pln","plaines" => "plns","plains" => "plns",
97        "plaza" => "plz","pln" => "pln","plns" => "plns","plz" => "plz","plza" => "plz","pne" => "pne","pnes" => "pnes",
98        "point" => "pt","points" => "pts","port" => "prt","ports" => "prts","pr" => "pr","prairie" => "pr",
99        "prarie" => "pr","prk" => "park","prr" => "pr","prt" => "prt","prts" => "prts","psge" => "psge","pt" => "pt",
100        "pts" => "pts","rad" => "radl","radial" => "radl","radiel" => "radl","radl" => "radl","ranch" => "rnch",
101        "ranches" => "rnch","rapid" => "rpd","rapids" => "rpds","rd" => "rd","rdg" => "rdg","rdge" => "rdg",
102        "rdgs" => "rdgs","rds" => "rds","rest" => "rst","ridge" => "rdg","ridges" => "rdgs","riv" => "riv",
103        "river" => "riv","rivr" => "riv","rnch" => "rnch","rnchs" => "rnch","rpd" => "rpd","rpds" => "rpds",
104        "rst" => "rst","rte" => "rte","rvr" => "riv",
105        "row" => "row","shl" => "shl","shls" => "shls","shoal" => "shl","shoals" => "shls","shoar" => "shr",
106        "shoars" => "shrs","shore" => "shr","shores" => "shrs","shr" => "shr","shrs" => "shrs","skwy" => "skwy",
107        "skyway" => "skwy","smt" => "smt","spg" => "spg","spgs" => "spgs","spng" => "spg","spngs" => "spgs",
108        "spring" => "spg","springs" => "spgs","sprng" => "spg","sprngs" => "spgs","spur" => "spur","spurs" => "spur",
109        "sq" => "sq","sqr" => "sq","sqre" => "sq","sqrs" => "sqs","sqs" => "sqs","sta" => "sta","station" => "sta",
110        "statn" => "sta","stn" => "sta",
111        "str" => "st","stra" => "stra","strav" => "stra","strave" => "stra","straven" => "stra","stravenue" => "stra",
112        "stravn" => "stra","stream" => "strm","street" => "st","streets" => "sts","streme" => "strm","strm" => "strm",
113        "strt" => "st","strvn" => "stra","strvnue" => "stra","sts" => "sts","sumit" => "smt","sumitt" => "smt",
114        "summit" => "smt","throughway" => "trwy","tpk" => "tpke",
115        "tpke" => "tpke","tr" => "trl","track" => "trak","tracks" => "trak",
116        "trafficway" => "trfy","trail" => "trl","trails" => "trl","trak" => "trak","trce" => "trce","trfy" => "trfy",
117        "trk" => "trak","trks" => "trak","trl" => "trl","trls" => "trl","trnpk" => "tpke","trpk" => "tpke","trwy" => "trwy",
118        "tunel" => "tunl","tunl" => "tunl","tunls" => "tunl","tunnel" => "tunl","tunnels" => "tunl","tunnl" => "tunl",
119        "turnpike" => "tpke","turnpk" => "tpke","underpass" => "upas","un" => "un","union" => "un","unions" => "uns",
120        "uns" => "uns","upas" => "upas","valley" => "vly","valleys" => "vlys","vally" => "vly","vdct" => "via","via" => "via",
121        "viadct" => "via","viaduct" => "via","view" => "vw","views" => "vws","vill" => "vlg","villag" => "vlg",
122        "village" => "vlg","villages" => "vlgs","ville" => "vl","villg" => "vlg","villiage" => "vlg","vis" => "vis",
123        "vist" => "vis","vista" => "vis","vl" => "vl","vlg" => "vlg","vlgs" => "vlgs","vlly" => "vly","vly" => "vly",
124        "vlys" => "vlys","vst" => "vis","vsta" => "vis","vw" => "vw","vws" => "vws","walk" => "walk","walks" => "walk",
125        "way" => "way","well" => "wl","wells" => "wls","wl" => "wl","wls" => "wls","wy" => "way","xing" => "xing","xrd" => "xrd"
126    ];
127
128    /**
129     * A list of possible directional indicators
130     * @var array $directions
131     * */
132    protected static array $directions = [
133        'WSW'   => 'West-Southwest',
134        'ESE'   => 'East-Southeast',
135        'SSW'   => 'South-Southwest',
136        'SSE'   => 'South-Southeast',
137        'WNW'   => 'West-Northwest',
138        'ENE'   => 'East-Northeast',
139        'NNW'   => 'North-Northwest',
140        'NNE'   => 'North-Northeast',
141        'SW'    => 'Southwest',
142        'SE'    => 'Southeast',
143        'NW'    => 'Northwest',
144        'NE'    => 'Northeast',
145        ' N '   => 'North',
146        ' S '   => 'South',
147        ' E '   => 'East',
148        ' W '   => 'West',
149        'N.'    => 'North',
150        'S.'    => 'South',
151        'E.'    => 'East',
152        'W.'    => 'West',
153    ];
154
155    /**
156     * A list of states and state codes
157     * @var array $states
158     * */
159    protected static array $states = [
160        'US' => [
161            'AL' => 'Alabama',
162            'AK' => 'Alaska',
163            'AZ' => 'Arizona',
164            'AR' => 'Arkansas',
165            'CA' => 'California',
166            'CO' => 'Colorado',
167            'CT' => 'Connecticut',
168            'DE' => 'Delaware',
169            'DC' => 'District of Columbia',
170            'FL' => 'Florida',
171            'GA' => 'Georgia',
172            'HI' => 'Hawaii',
173            'ID' => 'Idaho',
174            'IL' => 'Illinois',
175            'IN' => 'Indiana',
176            'IA' => 'Iowa',
177            'KS' => 'Kansas',
178            'KY' => 'Kentucky',
179            'LA' => 'Louisiana',
180            'ME' => 'Maine',
181            'MD' => 'Maryland',
182            'MA' => 'Massachusetts',
183            'MI' => 'Michigan',
184            'MN' => 'Minnesota',
185            'MS' => 'Mississippi',
186            'MO' => 'Missouri',
187            'MT' => 'Montana',
188            'NE' => 'Nebraska',
189            'NV' => 'Nevada',
190            'NH' => 'New Hampshire',
191            'NJ' => 'New Jersey',
192            'NM' => 'New Mexico',
193            'NY' => 'New York',
194            'NC' => 'North Carolina',
195            'ND' => 'North Dakota',
196            'OH' => 'Ohio',
197            'OK' => 'Oklahoma',
198            'OR' => 'Oregon',
199            'PA' => 'Pennsylvania',
200            'PR' => 'Puerto Rico',
201            'RI' => 'Rhode Island',
202            'SC' => 'South Carolina',
203            'SD' => 'South Dakota',
204            'TN' => 'Tennessee',
205            'TX' => 'Texas',
206            'UT' => 'Utah',
207            'VT' => 'Vermont',
208            'VA' => 'Virginia',
209            'WA' => 'Washington',
210            'WV' => 'West Virginia',
211            'WI' => 'Wisconsin',
212            'WY' => 'Wyoming',
213        ],
214        'CA' => [
215            'AB' => 'Alberta',
216            'BC' => 'British Columbia',
217            'MB' => 'Manitoba',
218            'NB' => 'New Brunswick',
219            'NL' => 'Newfoundland and Labrador',
220            'NT' => 'Northwest Territories',
221            'NS' => 'Nova Scotia',
222            'NU' => 'Nunavut',
223            'ON' => 'Ontario',
224            'PE' => 'Prince Edward Island',
225            'QC' => 'Quebec',
226            'SK' => 'Saskatchewan',
227            'YT' => 'Yukon',
228        ]
229    ];
230
231    /**
232     * Cached, length-sorted result of getCommonRouteTypes()
233     * @var ?array $commonRouteTypesSorted
234     * */
235    protected static ?array $commonRouteTypesSorted = null;
236
237    /**
238     * Cached, length-sorted result of getRouteTypes(true)
239     * @var ?array $routeTypesMerged
240     * */
241    protected static ?array $routeTypesMerged = null;
242
243    /**
244     * Cached, length-sorted result of getDirections()
245     * @var ?array $directionsMerged
246     * */
247    protected static ?array $directionsMerged = null;
248
249    /**
250     * Cached, length-sorted result of getUnitTypes()
251     * @var ?array $unitTypesMerged
252     * */
253    protected static ?array $unitTypesMerged = null;
254
255    /**
256     * A list of possibly unit types
257     * @var array $unitTypes
258     * */
259    protected static array $unitTypes = [
260        'APARTMENT'  => 'APT',
261        'APT'        => 'APT',
262        'BASEMENT'   => 'BSMT',
263        'BSMT'       => 'BSMT',
264        'BLDG'       => 'BLDG',
265        'BUILDING'   => 'BLDG',
266        'DEPARTMENT' => 'DEPT',
267        'DEPT'       => 'DEPT',
268        'FL'         => 'FL',
269        'FLR'        => 'FL',
270        'FLOOR'      => 'FL',
271        'FRNT'       => 'FRNT',
272        'FRONT'      => 'FRNT',
273        'HANGAR'     => 'HNGR',
274        'HNGR'       => 'HNGR',
275        'LBBY'       => 'LBBY',
276        'LOBBY'      => 'LBBY',
277        'LOT'        => 'LOT',
278        'LOWER'      => 'LOWR',
279        'LOWR'       => 'LOWER',
280        'NO'         => 'NUMBER',
281        'OFC'        => 'OFC',
282        'OFFICE'     => 'OFC',
283        'PENTHOUSE'  => 'PH',
284        'PH'         => 'PH',
285        'PIER'       => 'PIER',
286        'REAR'       => 'REAR',
287        'RM'         => 'RM',
288        'ROOM'       => 'RM',
289        'SIDE'       => 'SIDE',
290        'SLIP'       => 'SLIP',
291        'SPACE'      => 'SPC',
292        'SPC'        => 'SPC',
293        'STE'        => 'STE',
294        'STOP'       => 'STOP',
295        'SUITE'      => 'STE',
296        'TRAILER'    => 'TRLR',
297        'TRLR'       => 'TRLR',
298        'UNIT'       => 'UNIT',
299        'UPPER'      => 'UPPR',
300        'UPPR'       => 'UPPR',
301        '#'          => '#',
302    ];
303
304
305    /**
306     * Getter method for accessing common route types list
307     *
308     * @return array
309     */
310    public function getCommonRouteTypes(): array
311    {
312        if (self::$commonRouteTypesSorted === null) {
313            $routes = self::$commonRouteTypes;
314
315            usort($routes, function($a, $b) {
316                return strlen($b) - strlen($a);
317            });
318
319            self::$commonRouteTypesSorted = $routes;
320        }
321
322        return self::$commonRouteTypesSorted;
323    }
324
325    /**
326     * Getter method for accessing route types list
327     *
328     * @param  bool $merge
329     * @return array
330     */
331    public function getRouteTypes(bool $merge = false): array
332    {
333        if (!$merge) {
334            return self::$routeTypes;
335        }
336
337        if (self::$routeTypesMerged === null) {
338            $keys   = array_keys(self::$routeTypes);
339            $values = array_values(self::$routeTypes);
340            $routes = array_unique(array_merge($keys, $values));
341
342            usort($routes, function($a, $b) {
343                return strlen($b) - strlen($a);
344            });
345
346            self::$routeTypesMerged = $routes;
347        }
348
349        return self::$routeTypesMerged;
350    }
351
352    /**
353     * Getter method for accessing directionals associative array
354     *
355     * @return array
356     */
357    public function getDirections(): array
358    {
359        if (self::$directionsMerged === null) {
360            $directions = array_unique(array_merge(array_values(self::$directions), array_keys(self::$directions)));
361            usort($directions, function ($a, $b) {return strlen($b) - strlen($a);});
362            self::$directionsMerged = $directions;
363        }
364
365        return self::$directionsMerged;
366    }
367
368    /**
369     * Getter method for accessing states associative array
370     *
371     * @param  string $country
372     * @return array
373     */
374    public function getStates(string $country = 'US'): array
375    {
376        return self::$states[$country];
377    }
378
379    /**
380     * Getter method for accessing two-letter state abbreviations
381     *
382     * @param  string $country
383     * @return array
384     */
385    public function getStateCodes(string $country = 'US'): array
386    {
387        return array_keys(self::$states[$country]);
388    }
389
390    /**
391     * Getter method for accessing full state names
392     *
393     * @param  string $country
394     * @return array
395     */
396    public function getStateNames(string $country = 'US'): array
397    {
398        return array_values(self::$states[$country]);
399    }
400
401    /**
402     * Getter method for accessing unit types list
403     *
404     * @return array
405     */
406    public function getUnitTypes(): array
407    {
408        if (self::$unitTypesMerged === null) {
409            $unitTypes = array_merge(array_values(self::$unitTypes), array_keys(self::$unitTypes));
410            usort($unitTypes, function ($a, $b) {return strlen($b) - strlen($a);});
411            self::$unitTypesMerged = array_unique($unitTypes);
412        }
413
414        return self::$unitTypesMerged;
415    }
416
417}