]> git.openstreetmap.org Git - nominatim.git/blob - lib/AddressDetails.php
Merge pull request #1732 from lonvia/improve-geocodejson-output
[nominatim.git] / lib / AddressDetails.php
1 <?php
2
3 namespace Nominatim;
4
5 require_once(CONST_BasePath.'/lib/ClassTypes.php');
6
7 /**
8  * Detailed list of address parts for a single result
9  */
10 class AddressDetails
11 {
12     private $aAddressLines;
13
14     public function __construct(&$oDB, $iPlaceID, $sHousenumber, $mLangPref)
15     {
16         if (is_array($mLangPref)) {
17             $mLangPref = $oDB->getArraySQL($oDB->getDBQuotedList($mLangPref));
18         }
19
20         if (!isset($sHousenumber)) {
21             $sHousenumber = -1;
22         }
23
24         $sSQL = 'SELECT *,';
25         $sSQL .= ' get_name_by_language(name,'.$mLangPref.') as localname';
26         $sSQL .= ' FROM get_addressdata('.$iPlaceID.','.$sHousenumber.')';
27         $sSQL .= ' ORDER BY rank_address DESC, isaddress DESC';
28
29         $this->aAddressLines = $oDB->getAll($sSQL);
30     }
31
32     private static function isAddress($aLine)
33     {
34         return $aLine['isaddress'] || $aLine['type'] == 'country_code';
35     }
36
37     public function getAddressDetails($bAll = false)
38     {
39         if ($bAll) {
40             return $this->aAddressLines;
41         }
42
43         return array_filter($this->aAddressLines, array(__CLASS__, 'isAddress'));
44     }
45
46     public function getLocaleAddress()
47     {
48         $aParts = array();
49         $sPrevResult = '';
50
51         foreach ($this->aAddressLines as $aLine) {
52             if ($aLine['isaddress'] && $sPrevResult != $aLine['localname']) {
53                 $sPrevResult = $aLine['localname'];
54                 $aParts[] = $sPrevResult;
55             }
56         }
57
58         return join(', ', $aParts);
59     }
60
61     public function getAddressNames()
62     {
63         $aAddress = array();
64         $aFallback = array();
65
66         foreach ($this->aAddressLines as $aLine) {
67             if (!self::isAddress($aLine)) {
68                 continue;
69             }
70
71             $bFallback = false;
72             $aTypeLabel = ClassTypes\getInfo($aLine);
73
74             if ($aTypeLabel === false) {
75                 $aTypeLabel = ClassTypes\getFallbackInfo($aLine);
76                 $bFallback = true;
77             }
78
79             $sName = null;
80             if (isset($aLine['localname']) && $aLine['localname']!=='') {
81                 $sName = $aLine['localname'];
82             } elseif (isset($aLine['housenumber']) && $aLine['housenumber']!=='') {
83                 $sName = $aLine['housenumber'];
84             }
85
86             if (isset($sName)) {
87                 $sTypeLabel = strtolower(isset($aTypeLabel['simplelabel']) ? $aTypeLabel['simplelabel'] : $aTypeLabel['label']);
88                 $sTypeLabel = str_replace(' ', '_', $sTypeLabel);
89                 if (!isset($aAddress[$sTypeLabel])
90                     || isset($aFallback[$sTypeLabel])
91                     || $aLine['class'] == 'place'
92                 ) {
93                     $aAddress[$sTypeLabel] = $sName;
94                     if ($bFallback) {
95                         $aFallback[$sTypeLabel] = $bFallback;
96                     }
97                 }
98             }
99         }
100
101         return $aAddress;
102     }
103
104     /**
105      * Annotates the given json with geocodejson address information fields.
106      *
107      * @param array  $aJson  Json hash to add the fields to.
108      *
109      * Geocodejson has the following fields:
110      *  street, locality, postcode, city, district,
111      *  county, state, country
112      *
113      * Postcode and housenumber are added by type, district is not used.
114      * All other fields are set according to address rank.
115      */
116     public function addGeocodeJsonAddressParts(&$aJson)
117     {
118         foreach ($this->aAddressLines as $aLine) {
119             if (!$aLine['isaddress']) {
120                 continue;
121             }
122
123             if (!isset($aLine['localname']) || $aLine['localname'] == '') {
124                 continue;
125             }
126
127             $iRank = (int)$aLine['rank_address'];
128
129             if ($aLine['type'] == 'postcode' || $aLine['type'] == 'postal_code') {
130                 $aJson['postcode'] = $aLine['localname'];
131             } else if ($aLine['type'] == 'house_number') {
132                 $aJson['housenumber'] = $aLine['localname'];
133             } else if ($iRank > 25 && $iRank < 28) {
134                 $aJson['street'] = $aLine['localname'];
135             } else if ($iRank >= 22 && $iRank <= 25) {
136                 $aJson['locality'] = $aLine['localname'];
137             } else if ($iRank >= 17 && $iRank <= 21) {
138                 $aJson['district'] = $aLine['localname'];
139             } else if ($iRank >= 13 && $iRank <= 16) {
140                 $aJson['city'] = $aLine['localname'];
141             } else if ($iRank >= 10 && $iRank <= 12) {
142                 $aJson['county'] = $aLine['localname'];
143             } else if ($iRank >= 5 && $iRank <= 9) {
144                 $aJson['state'] = $aLine['localname'];
145             } else if ($iRank == 4) {
146                 $aJson['country'] = $aLine['localname'];
147             }
148         }
149     }
150
151     public function getAdminLevels()
152     {
153         $aAddress = array();
154         foreach (array_reverse($this->aAddressLines) as $aLine) {
155             if (self::isAddress($aLine)
156                 && isset($aLine['admin_level'])
157                 && $aLine['admin_level'] < 15
158                 && !isset($aAddress['level'.$aLine['admin_level']])
159             ) {
160                 $aAddress['level'.$aLine['admin_level']] = $aLine['localname'];
161             }
162         }
163         return $aAddress;
164     }
165
166     public function debugInfo()
167     {
168         return $this->aAddressLines;
169     }
170 }