1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Maps; |
4
|
|
|
|
5
|
|
|
use DataValues\Geo\Parsers\GeoCoordinateParser; |
6
|
|
|
use DataValues\Geo\Values\LatLongValue; |
7
|
|
|
use Maps\Geocoders\CachingGeocoder; |
8
|
|
|
use Maps\Geocoders\Geocoder; |
9
|
|
|
use MWException; |
10
|
|
|
use ValueParsers\ParseException; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Class for geocoder functionality of the Maps extension. |
14
|
|
|
* |
15
|
|
|
* FIXME: this is procedural spaghetti |
16
|
|
|
* |
17
|
|
|
* @since 0.4 |
18
|
|
|
* |
19
|
|
|
* @licence GNU GPL v2+ |
20
|
|
|
* @author Jeroen De Dauw < [email protected] > |
21
|
|
|
*/ |
22
|
|
|
final class Geocoders { |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Associative with geoservice identifiers as keys containing the class |
26
|
|
|
* name of the geocoders. This is used for registration of a geocoder |
27
|
|
|
* without immediately instantiating it. |
28
|
|
|
* |
29
|
|
|
* @since 0.7 |
30
|
|
|
* |
31
|
|
|
* @var array of string => string |
32
|
|
|
*/ |
33
|
|
|
public static $registeredGeocoders = []; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Can geocoding happen, ie are there any geocoders available. |
37
|
|
|
* |
38
|
|
|
* @since 1.0.3 |
39
|
|
|
* @var boolean |
40
|
|
|
*/ |
41
|
|
|
protected static $canGeocode = false; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Returns if this class can do geocoding operations. |
45
|
|
|
* Ie. if there are any geocoders available. |
46
|
|
|
* |
47
|
|
|
* @since 0.7 |
48
|
|
|
* |
49
|
|
|
* @return boolean |
50
|
|
|
*/ |
51
|
|
|
public static function canGeocode() { |
52
|
|
|
self::init(); |
53
|
|
|
return self::$canGeocode; |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* Gets a list of available geocoders. |
58
|
|
|
* |
59
|
|
|
* @since 1.0.3 |
60
|
|
|
* |
61
|
|
|
* @return array |
62
|
|
|
*/ |
63
|
|
|
public static function getAvailableGeocoders() { |
64
|
|
|
self::init(); |
65
|
|
|
return array_keys( self::$registeredGeocoders ); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Initiate the geocoding functionality. |
70
|
|
|
* |
71
|
|
|
* @since 1.0.3 |
72
|
|
|
* |
73
|
|
|
* @return boolean Indicates if init happened |
74
|
|
|
*/ |
75
|
|
|
public static function init() { |
76
|
|
|
static $initiated = false; |
77
|
|
|
|
78
|
|
|
if ( $initiated ) { |
79
|
|
|
return false; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
$initiated = true; |
83
|
|
|
|
84
|
|
|
// Register the geocoders. |
85
|
|
|
\Hooks::run( 'GeocoderFirstCallInit' ); |
86
|
|
|
|
87
|
|
|
// Determine if there are any geocoders. |
88
|
|
|
self::$canGeocode = count( self::$registeredGeocoders ) > 0; |
89
|
|
|
|
90
|
|
|
return true; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* This function first determines whether the provided string is a pair or coordinates |
95
|
|
|
* or an address. If it's the later, an attempt to geocode will be made. The function will |
96
|
|
|
* return the coordinates or false, in case a geocoding attempt was made but failed. |
97
|
|
|
* |
98
|
|
|
* @since 0.7 |
99
|
|
|
* |
100
|
|
|
* @param string $coordsOrAddress |
101
|
|
|
* @param string $geoService |
102
|
|
|
* @param boolean $checkForCoords |
103
|
|
|
* |
104
|
|
|
* @return LatLongValue|false |
105
|
|
|
*/ |
106
|
|
|
public static function attemptToGeocode( $coordsOrAddress, $geoService = '', $checkForCoords = true ) { |
107
|
|
|
if ( $checkForCoords ) { |
108
|
|
|
$coordinateParser = new GeoCoordinateParser(); |
|
|
|
|
109
|
|
|
|
110
|
|
|
try { |
111
|
|
|
return $coordinateParser->parse( $coordsOrAddress ); |
112
|
|
|
} |
113
|
|
|
catch ( ParseException $parseException ) { |
114
|
|
|
return self::geocode( $coordsOrAddress, $geoService ); |
115
|
|
|
} |
116
|
|
|
} else { |
117
|
|
|
return self::geocode( $coordsOrAddress, $geoService ); |
118
|
|
|
} |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Geocodes an address with the provided geocoding service and returns the result |
123
|
|
|
* as an array, or false when the geocoding failed. |
124
|
|
|
* |
125
|
|
|
* @since 0.7 |
126
|
|
|
* |
127
|
|
|
* @param string $address |
128
|
|
|
* @param string $geoService |
129
|
|
|
* |
130
|
|
|
* @return LatLongValue|false |
131
|
|
|
* @throws MWException |
132
|
|
|
*/ |
133
|
|
|
public static function geocode( $address, $geoService = '' ) { |
134
|
|
|
if ( !is_string( $address ) ) { |
135
|
|
|
throw new MWException( 'Parameter $address must be a string at ' . __METHOD__ ); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
if ( !self::canGeocode() ) { |
139
|
|
|
return false; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
$geocoder = self::getValidGeocoderInstance( $geoService ); |
143
|
|
|
|
144
|
|
|
// This means there was no suitable geocoder found, so return false. |
145
|
|
|
if ( $geocoder === false ) { |
146
|
|
|
return false; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
$coordinates = self::getDecoratedGeocoder( $geocoder )->geocode( $address ); |
|
|
|
|
150
|
|
|
|
151
|
|
|
if( $coordinates == null ) { |
152
|
|
|
return false; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
return $coordinates; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
private static function getDecoratedGeocoder( Geocoder $geocoder ) { |
|
|
|
|
159
|
|
|
if ( $GLOBALS['egMapsEnableGeoCache'] ) { |
160
|
|
|
return new CachingGeocoder( |
161
|
|
|
$geocoder, |
162
|
|
|
wfGetCache( CACHE_ANYTHING ) |
163
|
|
|
); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
return $geocoder; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Registers a geocoder linked to an identifier. |
171
|
|
|
* |
172
|
|
|
* @since 0.7 |
173
|
|
|
* |
174
|
|
|
* @param string $geocoderIdentifier |
175
|
|
|
* @param string|\Maps\Geocoders\Geocoder $geocoder |
176
|
|
|
*/ |
177
|
|
|
public static function registerGeocoder( $geocoderIdentifier, $geocoder ) { |
178
|
|
|
self::$registeredGeocoders[$geocoderIdentifier] = $geocoder; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Returns the instance of the geocoder linked to the provided identifier |
183
|
|
|
* or the default one when it's not valid. False is returned when there |
184
|
|
|
* are no geocoders available. |
185
|
|
|
* |
186
|
|
|
* @since 0.7 |
187
|
|
|
* |
188
|
|
|
* @param string $geocoderIdentifier |
189
|
|
|
* |
190
|
|
|
* @return Geocoder|bool |
191
|
|
|
*/ |
192
|
|
|
private static function getValidGeocoderInstance( $geocoderIdentifier ) { |
193
|
|
|
return self::getGeocoderInstance( self::getValidGeocoderIdentifier( $geocoderIdentifier ) ); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Returns the instance of a geocoder. This function assumes there is a |
198
|
|
|
* geocoder linked to the identifier you provide - if you are not sure |
199
|
|
|
* it does, use getValidGeocoderInstance instead. |
200
|
|
|
* |
201
|
|
|
* @since 0.7 |
202
|
|
|
* |
203
|
|
|
* @param string $geocoderIdentifier |
204
|
|
|
* |
205
|
|
|
* @return Geocoder|bool |
206
|
|
|
*/ |
207
|
|
|
private static function getGeocoderInstance( $geocoderIdentifier ) { |
208
|
|
|
if ( !array_key_exists( $geocoderIdentifier, self::$registeredGeocoders ) ) { |
209
|
|
|
return false; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
return self::$registeredGeocoders[$geocoderIdentifier]; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Returns a valid geocoder idenifier. If the given one is a valid main identifier, |
217
|
|
|
* it will simply be returned. If it's an alias, it will be turned into the correponding |
218
|
|
|
* main identifier. If it's not recognized at all (or empty), the default will be used. |
219
|
|
|
* Only call this function when there are geocoders available, else an erro will be thrown. |
220
|
|
|
* |
221
|
|
|
* @since 0.7 |
222
|
|
|
* |
223
|
|
|
* @param string $geocoderIdentifier |
224
|
|
|
* |
225
|
|
|
* @return string|bool |
226
|
|
|
* @throws MWException |
227
|
|
|
*/ |
228
|
|
|
private static function getValidGeocoderIdentifier( $geocoderIdentifier ) { |
229
|
|
|
global $egMapsDefaultGeoService; |
230
|
|
|
static $validatedDefault = false; |
231
|
|
|
|
232
|
|
|
if ( $geocoderIdentifier === '' || !array_key_exists( $geocoderIdentifier, self::$registeredGeocoders ) ) { |
233
|
|
|
if ( !$validatedDefault ) { |
234
|
|
|
if ( !array_key_exists( $egMapsDefaultGeoService, self::$registeredGeocoders ) ) { |
235
|
|
|
$services = array_keys( self::$registeredGeocoders ); |
236
|
|
|
$egMapsDefaultGeoService = array_shift( $services ); |
237
|
|
|
if ( is_null( $egMapsDefaultGeoService ) ) { |
238
|
|
|
throw new MWException( 'Tried to geocode while there are no geocoders available at ' . __METHOD__ ); |
239
|
|
|
} |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
if ( !array_key_exists( $egMapsDefaultGeoService, self::$registeredGeocoders ) ) { |
244
|
|
|
return false; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
$geocoderIdentifier = $egMapsDefaultGeoService; |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
return $geocoderIdentifier; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
} |
254
|
|
|
|
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.