Index: trunk/extensions/Maps/ParserHooks/Maps_Geocode.php |
— | — | @@ -118,7 +118,7 @@ |
119 | 119 | * @return string |
120 | 120 | */ |
121 | 121 | public function render( array $parameters ) { |
122 | | - if ( MapsMapper::geocoderIsAvailable() ) { |
| 122 | + if ( MapsGeocoders::canGeocode() ) { |
123 | 123 | $geovalues = MapsGeocoders::attemptToGeocodeToString( |
124 | 124 | $parameters['location'], |
125 | 125 | $parameters['service'], |
Index: trunk/extensions/Maps/Includes/Maps_Geocoders.php |
— | — | @@ -13,51 +13,59 @@ |
14 | 14 | final class MapsGeocoders { |
15 | 15 | |
16 | 16 | /** |
17 | | - * The geocoder cache, holding geocoded data when enabled. |
| 17 | + * Accociative with geoservice identifiers as keys containing instances of |
| 18 | + * the geocoder classes. |
| 19 | + * |
| 20 | + * Note: This list only contains the instances, so is not to be used for |
| 21 | + * looping over all available services, as not all of them are guaranteed |
| 22 | + * to have an instance already, use $registeredServices for this purpouse. |
| 23 | + * |
| 24 | + * @since 0.7 |
| 25 | + * |
| 26 | + * @var array of string => MapsGeocoder |
| 27 | + */ |
| 28 | + protected static $geocoders = array(); |
| 29 | + |
| 30 | + /** |
| 31 | + * Accociative with geoservice identifiers as keys containing the class |
| 32 | + * name of the geocoders. This is used for registration of a geocoder |
| 33 | + * without immedialty instantiating it. |
| 34 | + * |
| 35 | + * @since 0.7 |
| 36 | + * |
| 37 | + * @var array of string => string |
| 38 | + */ |
| 39 | + protected static $registeredGeocoders = array(); |
| 40 | + |
| 41 | + /** |
| 42 | + * The global geocoder cache, holding geocoded data when enabled. |
18 | 43 | * |
19 | 44 | * @since 0.7 |
20 | 45 | * |
21 | 46 | * @var array |
22 | 47 | */ |
23 | | - private static $mGeocoderCache = array(); |
| 48 | + private static $globalGeocoderCache = array(); |
24 | 49 | |
25 | 50 | /** |
26 | | - * Initialization function for Maps geocoder functionality. |
| 51 | + * Returns if this class can do geocoding operations. |
| 52 | + * Ie. if there are any geocoders available. |
27 | 53 | * |
28 | | - * @since 0.4 |
| 54 | + * @since 0.7 |
29 | 55 | * |
30 | | - * @return true |
| 56 | + * @return boolean |
31 | 57 | */ |
32 | | - public static function initialize() { |
33 | | - global $wgAutoloadClasses, $egMapsDir, $egMapsGeoServices, $egMapsAvailableGeoServices, $egMapsDefaultGeoService, $egMapsGeoOverrides; |
| 58 | + public static function canGeocode() { |
| 59 | + static $canGeocode = null; |
34 | 60 | |
35 | | - $egMapsGeoServices = array(); |
36 | | - $egMapsGeoOverrides = array(); |
37 | | - |
38 | | - $geoDir = dirname( __FILE__ ) . '/Geocoders/'; |
39 | | - // TODO: replace by autoloading |
40 | | - include_once $geoDir . 'Maps_GoogleGeocoder.php'; // Google |
41 | | - include_once $geoDir . 'Maps_YahooGeocoder.php'; // Yahoo! |
42 | | - include_once $geoDir . 'Maps_GeonamesGeocoder.php'; // GeoNames |
43 | | - |
44 | | - // Remove the supported geocoding services that are not in the $egMapsAvailableGeoServices array. |
45 | | - $supportedServices = array_keys( $egMapsGeoServices ); |
46 | | - foreach ( $supportedServices as $supportedService ) { |
47 | | - if ( !in_array( $supportedService, $egMapsAvailableGeoServices ) ) { |
48 | | - unset( $egMapsGeoServices[$supportedService] ); |
49 | | - } |
| 61 | + if ( is_null( $canGeocode ) ) { |
| 62 | + // Register the geocoders. |
| 63 | + wfRunHooks( 'GeocoderFirstCallInit' ); |
| 64 | + |
| 65 | + // Determine if there are any geocoders. |
| 66 | + $canGeocode = count( self::$registeredGeocoders ) > 0; |
50 | 67 | } |
51 | 68 | |
52 | | - // Re-populate the $egMapsAvailableGeoServices with it's original services that are supported. |
53 | | - $egMapsAvailableGeoServices = array_keys( $egMapsGeoServices ); |
54 | | - |
55 | | - // Enure that the default geoservice is one of the enabled ones. |
56 | | - if ( !in_array( $egMapsDefaultGeoService, $egMapsAvailableGeoServices ) ) { |
57 | | - reset( $egMapsAvailableGeoServices ); |
58 | | - $egMapsDefaultGeoService = key( $egMapsAvailableGeoServices ); |
59 | | - } |
60 | | - |
61 | | - return true; |
| 69 | + return $canGeocode; |
62 | 70 | } |
63 | 71 | |
64 | 72 | /** |
— | — | @@ -127,38 +135,82 @@ |
128 | 136 | * @since 0.7 |
129 | 137 | * |
130 | 138 | * @param string $address |
131 | | - * @param string $service |
| 139 | + * @param string $geoService |
132 | 140 | * @param string $mappingService |
133 | 141 | * |
134 | 142 | * @return array with coordinates or false |
135 | 143 | */ |
136 | | - public static function geocode( $address, $service = '', $mappingService = false ) { |
137 | | - global $egMapsGeoServices, $wgAutoloadClasses, $egMapsDir, $IP, $egMapsEnableGeoCache; |
| 144 | + public static function geocode( $address, $geoService = '', $mappingService = false ) { |
| 145 | + if ( !self::canGeocode() ) { |
| 146 | + return false; |
| 147 | + } |
138 | 148 | |
139 | | - // If the adress is already in the cache and the cache is enabled, return the coordinates. |
140 | | - if ( $egMapsEnableGeoCache && array_key_exists( $address, self::$mGeocoderCache ) ) { |
141 | | - return self::$mGeocoderCache[$address]; |
| 149 | + $geocoder = self::getValidGeocoderInstance( $geoService, $mappingService ); |
| 150 | + |
| 151 | + // This means there was no suitable geocoder found, so return false. |
| 152 | + if ( $geocoder === false ) { |
| 153 | + return false; |
142 | 154 | } |
143 | | - |
144 | | - $service = self::getValidGeoService( $service, $mappingService ); |
145 | 155 | |
146 | | - // Call the geocode function in the specific geocoder class. |
147 | | - $coordinates = call_user_func( array( $egMapsGeoServices[$service], 'geocode' ), $address ); |
| 156 | + if ( $geocoder->hasGlobalCacheSupport() ) { |
| 157 | + $cacheResult = self::cacheRead( $address ); |
| 158 | + |
| 159 | + // This means the cache returned an already computed set of coordinates. |
| 160 | + if ( $cacheResult !== false ) { |
| 161 | + return $cacheResult; |
| 162 | + } |
| 163 | + } |
148 | 164 | |
| 165 | + // Do the actual geocoding via the geocoder. |
| 166 | + $coordinates = $geocoder->geocode( $address ); |
| 167 | + |
149 | 168 | // If there address could not be geocoded, and contains comma's, try again without the comma's. |
150 | 169 | // This is cause several geocoding services such as geonames do not handle comma's well. |
151 | 170 | if ( !$coordinates && strpos( $address, ',' ) !== false ) { |
152 | | - $coordinates = call_user_func( |
153 | | - array( $egMapsGeoServices[$service], 'geocode' ), str_replace( ',', '', $address ) |
154 | | - ); |
| 171 | + $coordinates = $geocoder->geocode( str_replace( ',', '', $address ) ); |
155 | 172 | } |
156 | 173 | |
| 174 | + self::cacheWrite( $address, $coordinates ); |
| 175 | + |
| 176 | + return $coordinates; |
| 177 | + } |
| 178 | + |
| 179 | + /** |
| 180 | + * Returns already coordinates already known from previous geocoding operations, |
| 181 | + * or false if there is no match found in the cache. |
| 182 | + * |
| 183 | + * @since 0.7 |
| 184 | + * |
| 185 | + * @param string $address |
| 186 | + * |
| 187 | + * @return array or false |
| 188 | + */ |
| 189 | + protected static function cacheRead( $address ) { |
| 190 | + global $egMapsEnableGeoCache; |
| 191 | + |
| 192 | + if ( $egMapsEnableGeoCache && array_key_exists( $address, self::$globalGeocoderCache ) ) { |
| 193 | + return self::$globalGeocoderCache[$address]; |
| 194 | + } |
| 195 | + else { |
| 196 | + return false; |
| 197 | + } |
| 198 | + } |
| 199 | + |
| 200 | + /** |
| 201 | + * Writes the geocoded result to the cache if the cache is on. |
| 202 | + * |
| 203 | + * @since 0.7 |
| 204 | + * |
| 205 | + * @param string $address |
| 206 | + * @param array $coordinates |
| 207 | + */ |
| 208 | + protected static function cacheWrite( $address, array $coordinates ) { |
| 209 | + global $egMapsEnableGeoCache; |
| 210 | + |
157 | 211 | // Add the obtained coordinates to the cache when there is a result and the cache is enabled. |
158 | 212 | if ( $egMapsEnableGeoCache && $coordinates ) { |
159 | | - self::$mGeocoderCache[$address] = $coordinates; |
| 213 | + self::$globalGeocoderCache[$address] = $coordinates; |
160 | 214 | } |
161 | | - |
162 | | - return $coordinates; |
163 | 215 | } |
164 | 216 | |
165 | 217 | /** |
— | — | @@ -180,39 +232,118 @@ |
181 | 233 | } |
182 | 234 | |
183 | 235 | /** |
184 | | - * Makes sure that the geo service is one of the available ones. |
185 | | - * Also enforces licencing restrictions when no geocoding service is explicitly provided. |
| 236 | + * Registeres a geocoder linked to an identifier. |
| 237 | + * |
| 238 | + * @since 0.7 |
| 239 | + * |
| 240 | + * @param string $geocoderIdentifier |
| 241 | + * @param string $geocoderClassName |
| 242 | + */ |
| 243 | + public static function registerGeocoder( $geocoderIdentifier, $geocoderClassName ) { |
| 244 | + self::$registeredGeocoders[$geocoderIdentifier] = $geocoderClassName; |
| 245 | + } |
| 246 | + |
| 247 | + /** |
| 248 | + * Returns the instance of the geocoder linked to the provided identifier |
| 249 | + * or the default one when it's not valid. False is returned when there |
| 250 | + * are no geocoders available. |
| 251 | + * |
| 252 | + * @since 0.7 |
| 253 | + * |
| 254 | + * @param string $geocoderIdentifier |
| 255 | + * |
| 256 | + * @return MapsGeocoder or false |
| 257 | + */ |
| 258 | + protected static function getValidGeocoderInstance( $geocoderIdentifier ) { |
| 259 | + return self::getGeocoderInstance( self::getValidGeocoderIdentifier( $geocoderIdentifier ) ); |
| 260 | + } |
| 261 | + |
| 262 | + /** |
| 263 | + * Returns the instance of a geocoder. This function assumes there is a |
| 264 | + * geocoder linked to the identifier you provide - if you are not sure |
| 265 | + * it does, use getValidGeocoderInstance instead. |
| 266 | + * |
| 267 | + * @since 0.7 |
| 268 | + * |
| 269 | + * @param string $geocoderIdentifier |
| 270 | + * |
| 271 | + * @return MapsGeocoder or false |
| 272 | + */ |
| 273 | + protected static function getGeocoderInstance( $geocoderIdentifier ) { |
| 274 | + if ( !array_key_exists( $geocoderIdentifier, self::$geocoders ) ) { |
| 275 | + if ( array_key_exists( $geocoderIdentifier, self::$registeredGeocoders ) ) { |
| 276 | + $geocoder = new self::$registeredGeocoders[$geocoderIdentifier]( $geocoderIdentifier ); |
| 277 | + |
| 278 | + //if ( $service instanceof iMappingService ) { |
| 279 | + self::$geocoders[$geocoderIdentifier] = $geocoder; |
| 280 | + //} |
| 281 | + //else { |
| 282 | + // throw new Exception( 'The geocoder linked to identifier ' . $geocoderIdentifier . ' does not implement .' ); |
| 283 | + //} |
| 284 | + } |
| 285 | + else { |
| 286 | + throw new Exception( 'There is geocoder linked to identifier ' . $geocoderIdentifier . '.' ); |
| 287 | + } |
| 288 | + } |
| 289 | + |
| 290 | + return self::$geocoders[$geocoderIdentifier]; |
| 291 | + } |
| 292 | + |
| 293 | + /** |
| 294 | + * Returns a valid geocoder idenifier. If the given one is a valid main identifier, |
| 295 | + * it will simply be returned. If it's an alias, it will be turned into the correponding |
| 296 | + * main identifier. If it's not recognized at all (or empty), the default will be used. |
| 297 | + * Only call this function when there are geocoders available, else an erro will be thrown. |
| 298 | + * |
| 299 | + * TODO: implement overrides |
186 | 300 | * |
187 | 301 | * @since 0.7 |
188 | 302 | * |
189 | | - * @param string $service |
| 303 | + * @param string $geocoderIdentifier |
190 | 304 | * @param string $mappingService |
191 | 305 | * |
192 | | - * @return string |
| 306 | + * @return string or false |
193 | 307 | */ |
194 | | - private static function getValidGeoService( $service, $mappingService ) { |
195 | | - global $egMapsAvailableGeoServices, $egMapsDefaultGeoService, $egMapsGeoOverrides, $egMapsUserGeoOverrides; |
| 308 | + protected static function getValidGeocoderIdentifier( $geocoderIdentifier /*, $mappingService */ ) { |
| 309 | + global $egMapsDefaultGeoService, $egMapsUserGeoOverrides; |
| 310 | + static $validatedDefault = false; |
196 | 311 | |
197 | | - if ( $service == '' ) { |
198 | | - if ( $egMapsUserGeoOverrides && $mappingService ) { |
199 | | - // If no service has been provided, check if there are overrides for the default. |
200 | | - foreach ( $egMapsAvailableGeoServices as $geoService ) { |
201 | | - if ( array_key_exists( $geoService, $egMapsGeoOverrides ) && in_array( $mappingService, $egMapsGeoOverrides[$geoService] ) ) { |
202 | | - $service = $geoService; // Use the override. |
203 | | - break; |
| 312 | + // Get rid of any aliases. |
| 313 | + $geocoderIdentifier = self::getMainGeocoderIndentifier( $geocoderIdentifier ); |
| 314 | + |
| 315 | + if ( $geocoderIdentifier == '' || !array_key_exists( $geocoderIdentifier, self::$registeredGeocoders ) ) { |
| 316 | + if ( !$validatedDefault ) { |
| 317 | + if ( !array_key_exists( $egMapsDefaultGeoService, self::$registeredGeocoders ) ) { |
| 318 | + $egMapsDefaultGeoService = array_shift( array_keys( self::$registeredGeocoders ) ); |
| 319 | + if ( is_null( $egMapsDefaultGeoService ) ) { |
| 320 | + throw new Exception( 'Tried to geocode while there are no geocoders available at ' . __METHOD__ ); |
204 | 321 | } |
205 | 322 | } |
206 | 323 | } |
207 | | - |
208 | | - // If no overrides where applied, use the default mapping service. |
209 | | - if ( $service == '' ) $service = $egMapsDefaultGeoService; |
| 324 | + |
| 325 | + if ( array_key_exists( $egMapsDefaultGeoService, self::$registeredGeocoders ) ) { |
| 326 | + $geocoderIdentifier = $egMapsDefaultGeoService; |
| 327 | + } |
| 328 | + else { |
| 329 | + return false; |
| 330 | + } |
210 | 331 | } |
211 | | - else { |
212 | | - // If a service is provided, but is not supported, use the default. |
213 | | - if ( !in_array( $service, $egMapsAvailableGeoServices ) ) $service = $egMapsDefaultGeoService; |
214 | | - } |
215 | | - |
216 | | - return $service; |
217 | | - } |
| 332 | + |
| 333 | + return $geocoderIdentifier; |
| 334 | + } |
218 | 335 | |
| 336 | + /** |
| 337 | + * Gets the main geocoder identifier by resolving aliases. |
| 338 | + * |
| 339 | + * @since 0.7 |
| 340 | + * |
| 341 | + * @param string $geocoderIdentifier |
| 342 | + * |
| 343 | + * @return string |
| 344 | + */ |
| 345 | + protected static function getMainGeocoderIndentifier( $geocoderIdentifier ) { |
| 346 | + // TODO: implement actual function |
| 347 | + return $geocoderIdentifier; |
| 348 | + } |
| 349 | + |
219 | 350 | } |
\ No newline at end of file |
Index: trunk/extensions/Maps/Includes/Geocoders/Maps_GoogleGeocoder.php |
— | — | @@ -1,45 +1,59 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | /** |
5 | | - * Google Geocoding Service (v2) |
6 | | - * More info: http://code.google.com/apis/maps/documentation/services.html#Geocoding_Direct |
| 5 | + * Class for geocoding requests with the Google Geocoding Service (v2). |
| 6 | + * |
| 7 | + * Webservice documentation: http://code.google.com/apis/maps/documentation/services.html#Geocoding_Direct |
7 | 8 | * |
8 | 9 | * @file Maps_GoogleGeocoder.php |
9 | 10 | * @ingroup Maps |
| 11 | + * @ingroup Geocoders |
10 | 12 | * |
11 | 13 | * @author Jeroen De Dauw |
12 | 14 | * @author Sergey Chernyshev |
13 | 15 | */ |
14 | | - |
15 | | -if ( !defined( 'MEDIAWIKI' ) ) { |
16 | | - die( 'Not an entry point.' ); |
17 | | -} |
18 | | - |
19 | | -$wgAutoloadClasses['MapsGoogleGeocoder'] = __FILE__; |
20 | | -$egMapsGeoServices['google'] = 'MapsGoogleGeocoder'; |
21 | | -$egMapsGeoOverrides['google'] = array( 'googlemaps2', 'googlemaps3' ); |
22 | | - |
23 | 16 | final class MapsGoogleGeocoder extends MapsGeocoder { |
24 | 17 | |
25 | 18 | /** |
26 | | - * @see MapsBaseGeocoder::geocode() |
27 | | - * |
| 19 | + * Registeres the geocoder. |
| 20 | + * |
| 21 | + * No LST in pre-5.3 PHP *sigh*. |
| 22 | + * This is to be refactored as soon as php >=5.3 becomes acceptable. |
| 23 | + * |
| 24 | + * @since 0.7 |
| 25 | + */ |
| 26 | + public static function register() { |
| 27 | + MapsGeocoders::registerGeocoder( 'google', __CLASS__ ); |
| 28 | + return true; |
| 29 | + } |
| 30 | + |
| 31 | + /** |
| 32 | + * @see MapsGeocoder::getRequestUrl |
| 33 | + * |
| 34 | + * @since 0.7 |
| 35 | + * |
28 | 36 | * @param string $address |
29 | | - */ |
30 | | - public static function geocode( $address ) { |
| 37 | + * |
| 38 | + * @return string |
| 39 | + */ |
| 40 | + protected function getRequestUrl( $address ) { |
31 | 41 | global $egGoogleMapsKey; |
32 | | - |
33 | | - // In case the google maps api key is not set, return false0 |
34 | | - if ( empty( $egGoogleMapsKey ) ) return false; |
35 | | - |
36 | | - // Create the request url |
37 | | - $requestURL = 'http://maps.google.com/maps/geo?q=' . urlencode( $address ) . '&output=csv&key=' . urlencode( $egGoogleMapsKey ); |
38 | | - |
39 | | - $result = Http::get( $requestURL ); |
40 | | - |
41 | | - // Check the Google Geocoder API Response code to ensure success0 |
42 | | - if ( substr( $result, 0, 3 ) == '200' ) { |
43 | | - $result = explode( ',', $result ); |
| 42 | + return 'http://maps.google.com/maps/geo?q=' . urlencode( $address ) . '&output=csv&key=' . urlencode( $egGoogleMapsKey ); |
| 43 | + } |
| 44 | + |
| 45 | + /** |
| 46 | + * @see MapsGeocoder::parseResponse |
| 47 | + * |
| 48 | + * @since 0.7 |
| 49 | + * |
| 50 | + * @param string $address |
| 51 | + * |
| 52 | + * @return array |
| 53 | + */ |
| 54 | + protected function parseResponse( $response ) { |
| 55 | + // Check the Google Geocoder API Response code to ensure success. |
| 56 | + if ( substr( $response, 0, 3 ) == '200' ) { |
| 57 | + $result = explode( ',', $response ); |
44 | 58 | |
45 | 59 | // $precision = $result[1]; |
46 | 60 | |
— | — | @@ -48,8 +62,20 @@ |
49 | 63 | 'lon' => $result[3] |
50 | 64 | ); |
51 | 65 | } |
52 | | - else { // When the request fails, return false0 |
| 66 | + else { // When the request fails, return false. |
53 | 67 | return false; |
54 | | - } |
| 68 | + } |
55 | 69 | } |
| 70 | + |
| 71 | + /** |
| 72 | + * @see MapsGeocoder::getOverrides |
| 73 | + * |
| 74 | + * @since 0.7 |
| 75 | + * |
| 76 | + * @return array |
| 77 | + */ |
| 78 | + public function getOverrides() { |
| 79 | + return array( 'googlemaps2', 'googlemaps3' ); |
| 80 | + } |
| 81 | + |
56 | 82 | } |
\ No newline at end of file |
Index: trunk/extensions/Maps/Includes/Geocoders/Maps_GeonamesGeocoder.php |
— | — | @@ -1,47 +1,65 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | /** |
| 5 | + * Class for geocoding requests with the GeoNames webservice. |
| 6 | + * |
5 | 7 | * GeoNames Web Services Documentation: http://www.geonames.org/export/geonames-search.html |
6 | 8 | * |
7 | 9 | * @file Maps_GeonamesGeocoder.php |
8 | 10 | * @ingroup Maps |
| 11 | + * @ingroup Geocoders |
9 | 12 | * |
10 | 13 | * @author Jeroen De Dauw |
11 | 14 | * Thanks go to Joel Natividad for pointing me to the GeoNames services. |
12 | 15 | */ |
13 | | - |
14 | | -if ( !defined( 'MEDIAWIKI' ) ) { |
15 | | - die( 'Not an entry point.' ); |
16 | | -} |
17 | | - |
18 | | -$wgAutoloadClasses['MapsGeonamesGeocoder'] = __FILE__; |
19 | | -$egMapsGeoServices['geonames'] = 'MapsGeonamesGeocoder'; |
20 | | - |
21 | 16 | final class MapsGeonamesGeocoder extends MapsGeocoder { |
22 | 17 | |
23 | 18 | /** |
24 | | - * @see MapsBaseGeocoder::geocode() |
25 | | - * |
26 | | - * @param string $address |
| 19 | + * Registeres the geocoder. |
27 | 20 | * |
28 | | - * NOTE: The service is now also available in JSON, so it might be nice to change to that. |
| 21 | + * No LST in pre-5.3 PHP *sigh*. |
| 22 | + * This is to be refactored as soon as php >=5.3 becomes acceptable. |
| 23 | + * |
| 24 | + * @since 0.7 |
29 | 25 | */ |
30 | | - public static function geocode( $address ) { |
31 | | - // Create the request url |
32 | | - $requestURL = 'http://ws.geonames.org/search?q=' . urlencode( $address ) . '&maxRows=1&style=SHORT'; |
33 | | - |
34 | | - $result = Http::get( $requestURL ); |
| 26 | + public static function register() { |
| 27 | + MapsGeocoders::registerGeocoder( 'geonames', __CLASS__ ); |
| 28 | + return true; |
| 29 | + } |
35 | 30 | |
36 | | - $lon = self::getXmlElementValue( $result, 'lng' ); |
37 | | - $lat = self::getXmlElementValue( $result, 'lat' ); |
| 31 | + /** |
| 32 | + * @see MapsGeocoder::getRequestUrl |
| 33 | + * |
| 34 | + * @since 0.7 |
| 35 | + * |
| 36 | + * @param string $address |
| 37 | + * |
| 38 | + * @return string |
| 39 | + */ |
| 40 | + protected function getRequestUrl( $address ) { |
| 41 | + return 'http://ws.geonames.org/search?q=' . urlencode( $address ) . '&maxRows=1&style=SHORT'; |
| 42 | + } |
| 43 | + |
| 44 | + /** |
| 45 | + * @see MapsGeocoder::parseResponse |
| 46 | + * |
| 47 | + * @since 0.7 |
| 48 | + * |
| 49 | + * @param string $address |
| 50 | + * |
| 51 | + * @return array |
| 52 | + */ |
| 53 | + protected function parseResponse( $response ) { |
| 54 | + $lon = self::getXmlElementValue( $response, 'lng' ); |
| 55 | + $lat = self::getXmlElementValue( $response, 'lat' ); |
38 | 56 | |
39 | | - // In case one of the values is not found, return false |
| 57 | + // In case one of the values is not found, return false. |
40 | 58 | if ( !$lon || !$lat ) return false; |
41 | 59 | |
42 | 60 | return array( |
43 | 61 | 'lat' => $lat, |
44 | 62 | 'lon' => $lon |
45 | | - ); |
| 63 | + ); |
46 | 64 | } |
47 | 65 | |
48 | 66 | } |
\ No newline at end of file |
Index: trunk/extensions/Maps/Includes/Geocoders/Maps_YahooGeocoder.php |
— | — | @@ -1,49 +1,76 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | /** |
| 5 | + * Class for geocoding requests with the Yahoo! Geocoding Service. |
| 6 | + * |
5 | 7 | * Yahoo! Geocoding Service info: http://developer.yahoo.com/geo/geoplanet/ |
6 | 8 | * |
7 | 9 | * @file Maps_YahooGeocoder.php |
8 | 10 | * @ingroup Maps |
| 11 | + * @ingroup Geocoders |
9 | 12 | * |
10 | 13 | * @author Jeroen De Dauw |
11 | 14 | */ |
12 | | - |
13 | | -if ( !defined( 'MEDIAWIKI' ) ) { |
14 | | - die( 'Not an entry point.' ); |
15 | | -} |
16 | | - |
17 | | -$wgAutoloadClasses['MapsYahooGeocoder'] = __FILE__; |
18 | | -$egMapsGeoServices['yahoo'] = 'MapsYahooGeocoder'; |
19 | | - |
20 | 15 | final class MapsYahooGeocoder extends MapsGeocoder { |
21 | 16 | |
22 | 17 | /** |
23 | | - * @see MapsBaseGeocoder::geocode() |
24 | | - * |
| 18 | + * Registeres the geocoder. |
| 19 | + * |
| 20 | + * No LST in pre-5.3 PHP *sigh*. |
| 21 | + * This is to be refactored as soon as php >=5.3 becomes acceptable. |
| 22 | + * |
| 23 | + * @since 0.7 |
| 24 | + */ |
| 25 | + public static function register() { |
| 26 | + MapsGeocoders::registerGeocoder( 'yahoo', __CLASS__ ); |
| 27 | + return true; |
| 28 | + } |
| 29 | + |
| 30 | + /** |
| 31 | + * @see MapsGeocoder::getRequestUrl |
| 32 | + * |
| 33 | + * @since 0.7 |
| 34 | + * |
25 | 35 | * @param string $address |
26 | | - */ |
27 | | - public static function geocode( $address ) { |
| 36 | + * |
| 37 | + * @return string |
| 38 | + */ |
| 39 | + protected function getRequestUrl( $address ) { |
28 | 40 | global $egYahooMapsKey; |
29 | | - |
30 | | - // In case the Yahoo! Maps API key is not set, return false |
31 | | - if ( empty( $egYahooMapsKey ) ) return false; |
32 | | - |
33 | | - // Create the request url |
34 | | - $requestURL = "http://where.yahooapis.com/v1/places.q('" . urlencode( $address ) . "')?appid=" . urlencode( $egYahooMapsKey ) . "&format=xml"; |
35 | | - |
36 | | - $result = Http::get( $requestURL ); |
| 41 | + return "http://where.yahooapis.com/v1/places.q('" . urlencode( $address ) . "')?appid=" . urlencode( $egYahooMapsKey ) . '&format=xml'; |
| 42 | + } |
37 | 43 | |
38 | | - $lon = self::getXmlElementValue( $result, 'longitude' ); |
39 | | - $lat = self::getXmlElementValue( $result, 'latitude' ); |
| 44 | + /** |
| 45 | + * @see MapsGeocoder::parseResponse |
| 46 | + * |
| 47 | + * @since 0.7 |
| 48 | + * |
| 49 | + * @param string $address |
| 50 | + * |
| 51 | + * @return array |
| 52 | + */ |
| 53 | + protected function parseResponse( $response ) { |
| 54 | + $lon = self::getXmlElementValue( $response, 'longitude' ); |
| 55 | + $lat = self::getXmlElementValue( $response, 'latitude' ); |
40 | 56 | |
41 | | - // In case one of the values is not found, return false |
| 57 | + // In case one of the values is not found, return false. |
42 | 58 | if ( !$lon || !$lat ) return false; |
43 | 59 | |
44 | 60 | return array( |
45 | 61 | 'lat' => $lat, |
46 | 62 | 'lon' => $lon |
47 | | - ); |
| 63 | + ); |
48 | 64 | } |
49 | 65 | |
| 66 | + /** |
| 67 | + * @see MapsGeocoder::getOverrides |
| 68 | + * |
| 69 | + * @since 0.7 |
| 70 | + * |
| 71 | + * @return array |
| 72 | + */ |
| 73 | + public function getOverrides() { |
| 74 | + return array( 'yahoomaps' ); |
| 75 | + } |
| 76 | + |
50 | 77 | } |
\ No newline at end of file |
Index: trunk/extensions/Maps/Includes/Maps_Mapper.php |
— | — | @@ -175,11 +175,12 @@ |
176 | 176 | /** |
177 | 177 | * Returns a boolean indicating if MapsGeocoder is available. |
178 | 178 | * |
| 179 | + * @deprecated - use MapsGeocoders::canGeocode() instead |
| 180 | + * |
179 | 181 | * @return Boolean |
180 | 182 | */ |
181 | 183 | public static function geocoderIsAvailable() { |
182 | | - global $wgAutoloadClasses; |
183 | | - return array_key_exists( 'MapsGeocoders', $wgAutoloadClasses ); |
| 184 | + return MapsGeocoders::canGeocode(); |
184 | 185 | } |
185 | 186 | |
186 | 187 | /** |
Index: trunk/extensions/Maps/Includes/Maps_Geocoder.php |
— | — | @@ -11,8 +11,92 @@ |
12 | 12 | * @author Jeroen De Dauw |
13 | 13 | */ |
14 | 14 | abstract class MapsGeocoder { |
| 15 | + |
| 16 | + /** |
| 17 | + * The internal name of the geocoder. |
| 18 | + * |
| 19 | + * @since 0.7 |
| 20 | + * |
| 21 | + * @var string |
| 22 | + */ |
| 23 | + protected static $name; |
15 | 24 | |
16 | 25 | /** |
| 26 | + * A list of aliases for the internal name. |
| 27 | + * |
| 28 | + * @since 0.7 |
| 29 | + * |
| 30 | + * @var array |
| 31 | + */ |
| 32 | + protected $aliases; |
| 33 | + |
| 34 | + /** |
| 35 | + * Returns the url to which to make the geocoding request. |
| 36 | + * |
| 37 | + * @since 0.7 |
| 38 | + * |
| 39 | + * @param string $address |
| 40 | + * |
| 41 | + * @return string |
| 42 | + */ |
| 43 | + protected abstract function getRequestUrl( $address ); |
| 44 | + |
| 45 | + /** |
| 46 | + * Parses the response and returns it as an array with lat and lon keys. |
| 47 | + * |
| 48 | + * @since 0.7 |
| 49 | + * |
| 50 | + * @param string $address |
| 51 | + * |
| 52 | + * @return array |
| 53 | + */ |
| 54 | + protected abstract function parseResponse( $response ); |
| 55 | + |
| 56 | + /** |
| 57 | + * Constructor. |
| 58 | + * |
| 59 | + * @since 0.7 |
| 60 | + * |
| 61 | + * @param string $identifier |
| 62 | + */ |
| 63 | + public function __construct( $identifier ) { |
| 64 | + self::$name = $identifier; |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * Returns the geocoders identifier. |
| 69 | + * |
| 70 | + * @since 0.7 |
| 71 | + * |
| 72 | + * @return string |
| 73 | + */ |
| 74 | + public static function getName() { |
| 75 | + return self::$name; |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Returns the geocoders aliases. |
| 80 | + * |
| 81 | + * @since 0.7 |
| 82 | + * |
| 83 | + * @return array |
| 84 | + */ |
| 85 | + public function getAliases() { |
| 86 | + return $this->aliases; |
| 87 | + } |
| 88 | + |
| 89 | + /** |
| 90 | + * Returns if the geocoder has a certain alias. |
| 91 | + * |
| 92 | + * @since 0.7 |
| 93 | + * |
| 94 | + * @return boolean |
| 95 | + */ |
| 96 | + public function hasAlias( $alias ) { |
| 97 | + return in_array( $alias, $this->aliases ); |
| 98 | + } |
| 99 | + |
| 100 | + /** |
17 | 101 | * Returns an array containing the geocoded latitude (lat) and |
18 | 102 | * longitude (lon) of the provided address, or false in case the |
19 | 103 | * geocoding fails. |
— | — | @@ -21,10 +105,17 @@ |
22 | 106 | * |
23 | 107 | * @param $address String: the address to be geocoded |
24 | 108 | * |
25 | | - * @return string or false |
| 109 | + * @return array or false |
26 | 110 | */ |
27 | | - public static function geocode( $address ) { |
28 | | - return false; // This method needs to be overriden, if it's not, return false. |
| 111 | + public function geocode( $address ) { |
| 112 | + $response = Http::get( $this->getRequestUrl( $address ) ); |
| 113 | + |
| 114 | + if ( $response === false ) { |
| 115 | + return false; |
| 116 | + } |
| 117 | + else { |
| 118 | + return $this->parseResponse( $response ); |
| 119 | + } |
29 | 120 | } |
30 | 121 | |
31 | 122 | /** |
— | — | @@ -42,4 +133,31 @@ |
43 | 134 | return count( $match ) > 1 ? $match[1] : false; |
44 | 135 | } |
45 | 136 | |
| 137 | + /** |
| 138 | + * Returns the mapping service overrides for this geocoder, allowing it to be used |
| 139 | + * instead of the default geocoder when none is provided for certain mapping services. |
| 140 | + * |
| 141 | + * Returns an empty array by default. Override to add overrides. |
| 142 | + * |
| 143 | + * @since 0.7 |
| 144 | + * |
| 145 | + * @return array |
| 146 | + */ |
| 147 | + public function getOverrides() { |
| 148 | + return array(); |
| 149 | + } |
| 150 | + |
| 151 | + /** |
| 152 | + * Returns if the global geocoder cache should be used or not. |
| 153 | + * By default it should be, but overriding this function allows |
| 154 | + * for making a geocoder ignore it and implement it's own solution. |
| 155 | + * |
| 156 | + * @since 0.7 |
| 157 | + * |
| 158 | + * @return boolean |
| 159 | + */ |
| 160 | + public function hasGlobalCacheSupport() { |
| 161 | + return true; |
| 162 | + } |
| 163 | + |
46 | 164 | } |
\ No newline at end of file |
Index: trunk/extensions/Maps/Maps.php |
— | — | @@ -101,6 +101,12 @@ |
102 | 102 | $wgAutoloadClasses['MapsGeocoders'] = $incDir . 'Maps_Geocoders.php'; |
103 | 103 | $wgAutoloadClasses['MapsGeocoder'] = $incDir . 'Maps_Geocoder.php'; |
104 | 104 | |
| 105 | + // Geocoders at "Includes/Geocoders/". |
| 106 | + $geoDir = $incDir . 'Geocoders/'; |
| 107 | + $wgAutoloadClasses['MapsGeonamesGeocoder'] = $geoDir . 'Maps_GeonamesGeocoder.php'; |
| 108 | + $wgAutoloadClasses['MapsGoogleGeocoder'] = $geoDir . 'Maps_GoogleGeocoder.php'; |
| 109 | + $wgAutoloadClasses['MapsYahooGeocoder'] = $geoDir . 'Maps_YahooGeocoder.php'; |
| 110 | + |
105 | 111 | // Autoload the "ParserHooks/" classes. |
106 | 112 | $phDir = dirname( __FILE__ ) . '/ParserHooks/'; |
107 | 113 | $wgAutoloadClasses['MapsCoordinates'] = $phDir . 'Maps_Coordinates.php'; |
Index: trunk/extensions/Maps/Maps_Settings.php |
— | — | @@ -52,12 +52,11 @@ |
53 | 53 | $wgHooks['ParserFirstCallInit'][] = 'MapsGeodistance::staticInit'; |
54 | 54 | $wgHooks['LanguageGetMagic'][] = 'MapsGeodistance::staticMagic'; |
55 | 55 | |
56 | | - # |
57 | | - |
58 | | - $wgHooks['MappingFeatureLoad'][] = 'MapsGeocoders::initialize'; |
59 | | - |
60 | | - |
| 56 | + # Geocoders |
61 | 57 | |
| 58 | + $wgHooks['GeocoderFirstCallInit'][] = 'MapsGeonamesGeocoder::register'; |
| 59 | + $wgHooks['GeocoderFirstCallInit'][] = 'MapsGoogleGeocoder::register'; |
| 60 | + $wgHooks['GeocoderFirstCallInit'][] = 'MapsYahooGeocoder::register'; |
62 | 61 | |
63 | 62 | # Mapping services configuration |
64 | 63 | # Note: You can not use aliases in the settings. Use the main service names. |